Sync from Piper @425656941

PROTOBUF_SYNC_PIPER
diff --git a/.github/mergeable.yml b/.github/mergeable.yml
index ade6c67..1768852 100644
--- a/.github/mergeable.yml
+++ b/.github/mergeable.yml
@@ -9,10 +9,10 @@
           - and:
             - must_include:
                 regex: 'release notes: yes'
-                message: 'Please include release notes: yes'
+                message: 'Include release notes: yes'
             - must_include:
                 regex: '^(autotools|bazel|c#|c\+\+|cleanup|cmake|conformance tests|integration|go|java|javascript|objective-c|php|protoc|python|ruby|kotlin)'
-                message: 'Please include at least a language label (e.g., c++, java, python). Or apply one of the following labels: autotools, bazel, cmake, cleanup, conformance tests, integration, protoc.'
+                message: 'at least a language label (e.g., c++, java, python). Or apply one of the following labels: autotools, bazel, cmake, cleanup, conformance tests, integration, protoc.'
           - must_include:
               regex: 'release notes: no'
-              message: 'Please include release notes: no'
+              message: 'Include release notes: no'
diff --git a/BUILD b/BUILD
index 9fbf69d..df62e9e 100644
--- a/BUILD
+++ b/BUILD
@@ -2,11 +2,13 @@
 
 load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
 load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test", "objc_library", native_cc_proto_library = "cc_proto_library")
+load("@rules_pkg//:pkg.bzl", "pkg_zip")
+load("@rules_pkg//:mappings.bzl", "pkg_attributes", "pkg_files")
 load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain", "proto_library")
 load("@rules_python//python:defs.bzl", "py_library")
 load("@rules_java//java:defs.bzl", "java_binary", "java_lite_proto_library", "java_proto_library")
 load(":cc_proto_blacklist_test.bzl", "cc_proto_blacklist_test")
-
+load(":protobuf_release.bzl", "package_naming")
 licenses(["notice"])
 
 exports_files(["LICENSE"])
@@ -26,7 +28,6 @@
 ################################################################################
 
 MSVC_COPTS = [
-    "/DHAVE_PTHREAD",
     "/wd4018",  # -Wno-sign-compare
     "/wd4065",  # switch statement contains 'default' but no 'case' labels
     "/wd4146",  # unary minus operator applied to unsigned type, result still unsigned
@@ -46,7 +47,6 @@
 COPTS = select({
     ":msvc": MSVC_COPTS,
     "//conditions:default": [
-        "-DHAVE_PTHREAD",
         "-DHAVE_ZLIB",
         "-Wmissing-field-initializers",
         "-Woverloaded-virtual",
@@ -65,6 +65,13 @@
     ],
 )
 
+# Android NDK builds can specify different crosstool_top flags to choose which
+# STL they use for C++. We need these multiple variants to catch all of those
+# versions of crosstool_top and reliably detect Android.
+#
+# For more info on the various crosstool_tops used by NDK Bazel builds, see:
+# https://docs.bazel.build/versions/master/android-ndk.html#configuring-the-stl
+
 config_setting(
     name = "android",
     values = {
@@ -77,6 +84,17 @@
 )
 
 config_setting(
+    name = "android-stlport",
+    values = {
+        "crosstool_top": "@androidndk//:toolchain-stlport",
+    },
+    visibility = [
+        # Public, but Protobuf only visibility.
+        "//:__subpackages__",
+    ],
+)
+
+config_setting(
     name = "android-libcpp",
     values = {
         "crosstool_top": "@androidndk//:toolchain-libcpp",
@@ -98,11 +116,24 @@
     ],
 )
 
+config_setting(
+    name = "android-default",
+    values = {
+        "crosstool_top": "@androidndk//:default_crosstool",
+    },
+    visibility = [
+        # Public, but Protobuf only visibility.
+        "//:__subpackages__",
+    ],
+)
+
 # Android and MSVC builds do not need to link in a separate pthread library.
 LINK_OPTS = select({
     ":android": [],
+    ":android-stlport": [],
     ":android-libcpp": [],
     ":android-gnu-libstdcpp": [],
+    ":android-default": [],
     ":msvc": [
         # Suppress linker warnings about files with no symbols defined.
         "-ignore:4221",
@@ -147,6 +178,7 @@
         "src/google/protobuf/message_lite.cc",
         "src/google/protobuf/parse_context.cc",
         "src/google/protobuf/repeated_field.cc",
+        "src/google/protobuf/repeated_ptr_field.cc",
         "src/google/protobuf/stubs/bytestream.cc",
         "src/google/protobuf/stubs/common.cc",
         "src/google/protobuf/stubs/int128.cc",
@@ -488,6 +520,70 @@
     deps = [":protoc_lib"],
 )
 
+
+################################################################################
+# Generates protoc release artifacts.
+################################################################################
+
+genrule(
+    name = "protoc_readme",
+    visibility = ["//visibility:private"],
+    cmd = """
+echo "Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+https://developers.google.com/protocol-buffers/
+This package contains a precompiled binary version of the protocol buffer
+compiler (protoc). This binary is intended for users who want to use Protocol
+Buffers in languages other than C++ but do not want to compile protoc
+themselves. To install, simply place this binary somewhere in your PATH.
+If you intend to use the included well known types then don't forget to
+copy the contents of the 'include' directory somewhere as well, for example
+into '/usr/local/include/'.
+Please refer to our official github site for more installation instructions:
+  https://github.com/protocolbuffers/protobuf" > $@
+    """,
+    outs = ["readme.txt"],
+)
+
+# plugin.proto is excluded from this list because it belongs in a nested folder (protobuf/compiler/plugin.proto)
+pkg_files(
+    name = "wkt_protos_files",
+    srcs =  [value[0] for value in WELL_KNOWN_PROTO_MAP.values() if not value[0].endswith("plugin.proto")],
+    visibility = ["//visibility:private"],
+    prefix = "include/google/protobuf",
+)
+
+pkg_files(
+    name = "compiler_plugin_protos_files",
+    srcs =  ["src/google/protobuf/compiler/plugin.proto"],
+    visibility = ["//visibility:private"],
+    prefix = "include/google/protobuf/compiler",
+)
+
+pkg_files(
+    name = "protoc_files",
+    srcs =  [":protoc"],
+    attributes = pkg_attributes(mode = "0555"),
+    visibility = ["//visibility:private"],
+    prefix = "bin/",
+)
+
+package_naming(
+    name = "protoc_pkg_naming",
+)
+
+pkg_zip(
+    name = "protoc_release",
+    package_file_name = "protoc-{version}-{platform}.zip",
+    package_variables = ":protoc_pkg_naming",
+    srcs = [
+        ":protoc_files",
+        ":wkt_protos_files",
+        ":compiler_plugin_protos_files",
+        "readme.txt",
+    ],
+)
+
 ################################################################################
 # Tests
 ################################################################################
@@ -560,6 +656,8 @@
 TEST_PROTOS = ["src/" + s for s in RELATIVE_TEST_PROTOS]
 
 GENERIC_RELATIVE_TEST_PROTOS = [
+    "google/protobuf/map_proto2_unittest.proto",
+    "google/protobuf/map_unittest.proto",
     "google/protobuf/unittest.proto",
     "google/protobuf/unittest_arena.proto",
     "google/protobuf/unittest_custom_options.proto",
@@ -953,7 +1051,6 @@
     protoc = ":protoc",
     py_libs = [
         ":python_srcs",
-        "@six//:six",
     ],
     srcs_version = "PY2AND3",
     visibility = ["//visibility:public"],
@@ -1087,7 +1184,7 @@
     name = "generated_protos_proto",
     srcs = [
         "src/google/protobuf/unittest_import_public.proto",
-        "unittest_gen.proto",
+        "unittest_gen_import.proto",
     ],
 )
 
@@ -1095,7 +1192,7 @@
     name = "generated_protos_py",
     srcs = [
         "src/google/protobuf/unittest_import_public.proto",
-        "unittest_gen.proto",
+        "unittest_gen_import.proto",
     ],
     default_runtime = "",
     protoc = ":protoc",
@@ -1225,6 +1322,19 @@
 #     ],
 # )
 
+
+java_proto_library(
+    name = "java_test_protos",
+    deps = [":generic_test_protos"],
+    visibility = ["//java:__subpackages__"],
+)
+
+java_lite_proto_library(
+    name = "java_lite_test_protos",
+    deps = [":generic_test_protos"],
+    visibility = ["//java:__subpackages__"],
+)
+
 java_proto_library(
     name = "test_messages_proto2_java_proto",
     visibility = [
@@ -1318,3 +1428,146 @@
     srcs = glob(["**/*.bzl"]),
     visibility = ["//visibility:public"],
 )
+
+# Kotlin proto rules
+
+genrule(
+    name = "gen_kotlin_unittest_lite",
+    srcs = [
+        "src/google/protobuf/unittest_lite.proto",
+        "src/google/protobuf/unittest_import_lite.proto",
+        "src/google/protobuf/unittest_import_public_lite.proto",
+        "src/google/protobuf/map_lite_unittest.proto",
+    ],
+    outs = [
+        "TestAllTypesLiteKt.kt",
+        "ForeignMessageLiteKt.kt",
+        "TestAllExtensionsLiteKt.kt",
+        "TestEmptyMessageLiteKt.kt",
+        "TestEmptyMessageWithExtensionsLiteKt.kt",
+        "TestMapLiteKt.kt",
+        "OptionalGroup_extension_liteKt.kt",
+        "RepeatedGroup_extension_liteKt.kt",
+    ],
+    visibility = ["//java:__subpackages__"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(locations src/google/protobuf/unittest_lite.proto) && " +
+          "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(locations src/google/protobuf/map_lite_unittest.proto) && " +
+          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
+          "$(location TestAllTypesLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/ForeignMessageLiteKt.kt " +
+          "$(location ForeignMessageLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestAllExtensionsLiteKt.kt " +
+          "$(location TestAllExtensionsLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
+          "$(location TestAllTypesLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestEmptyMessageLiteKt.kt " +
+          "$(location TestEmptyMessageLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/TestEmptyMessageWithExtensionsLiteKt.kt " +
+          "$(location TestEmptyMessageWithExtensionsLiteKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestMapLiteKt.kt " +
+          "$(location TestMapLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/OptionalGroup_extension_liteKt.kt " +
+          "$(location OptionalGroup_extension_liteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/RepeatedGroup_extension_liteKt.kt " +
+          "$(location RepeatedGroup_extension_liteKt.kt)",
+    tools = [":protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_unittest",
+    srcs = [
+        "src/google/protobuf/unittest.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+        "src/google/protobuf/map_proto2_unittest.proto",
+    ],
+    outs = [
+        "TestAllTypesKt.kt",
+        "ForeignMessageKt.kt",
+        "TestAllExtensionsKt.kt",
+        "TestEmptyMessageKt.kt",
+        "TestEmptyMessageWithExtensionsKt.kt",
+        "TestIntIntMapKt.kt",
+        "TestEnumMapKt.kt",
+        "TestMapsKt.kt",
+        "OptionalGroup_extensionKt.kt",
+        "RepeatedGroup_extensionKt.kt",
+    ],
+    visibility = ["//java:__subpackages__"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest.proto) && " +
+          "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " + 
+          "$(location src/google/protobuf/map_proto2_unittest.proto) && " +
+          "cp $(@D)/protobuf_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/ForeignMessageKt.kt " +
+          "$(location ForeignMessageKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestAllExtensionsKt.kt " +
+          "$(location TestAllExtensionsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEmptyMessageWithExtensionsKt.kt " +
+          "$(location TestEmptyMessageWithExtensionsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestIntIntMapKt.kt " +
+          "$(location TestIntIntMapKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestEnumMapKt.kt " +
+          "$(location TestEnumMapKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/TestMapsKt.kt " +
+          "$(location TestMapsKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/OptionalGroup_extensionKt.kt " +
+          "$(location OptionalGroup_extensionKt.kt) && " +
+          "cp $(@D)/protobuf_unittest/RepeatedGroup_extensionKt.kt " +
+          "$(location RepeatedGroup_extensionKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_unittest_lite",
+    srcs = [
+        "src/google/protobuf/unittest_proto3_lite.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+    ],
+    outs = [
+        "TestAllTypesProto3LiteKt.kt",
+        "TestEmptyMessageProto3LiteKt.kt",
+    ],
+    visibility = ["//java:__subpackages__"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest_proto3_lite.proto) && " +
+          "cp $(@D)/proto3_lite_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesProto3LiteKt.kt) && " +
+          "cp $(@D)/proto3_lite_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageProto3LiteKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_unittest",
+    srcs = [
+        "src/google/protobuf/unittest_proto3.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+    ],
+    outs = [
+        "TestAllTypesProto3Kt.kt",
+        "TestEmptyMessageProto3Kt.kt",
+    ],
+    visibility = ["//java:__subpackages__"],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
+          "$(location src/google/protobuf/unittest_proto3.proto) && " +
+          "cp $(@D)/proto3_unittest/TestAllTypesKt.kt " +
+          "$(location TestAllTypesProto3Kt.kt) && " +
+          "cp $(@D)/proto3_unittest/TestEmptyMessageKt.kt " +
+          "$(location TestEmptyMessageProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
diff --git a/CHANGES.txt b/CHANGES.txt
index 7682fbd..ea9e6af 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,110 @@
 Unreleased Changes (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
-  Protocol Compiler
+
+  Ruby
+  * JSON will now output shorter strings for double and float fields when possible
+    without losing precision.
+  * Encoding and decoding of binary format will now work properly on big-endian
+    systems.
+  * UTF-8 verification was fixed to properly reject surrogate code points.
+  * Unknown enums for proto2 protos now properly implement proto2's behavior of
+    putting such values in unknown fields.
+
+2022-01-28 version 3.19.4 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  Python
+  * Make libprotobuf symbols local on OSX to fix issue #9395 (#9435)
+
+  Ruby
+  * Fixed a data loss bug that could occur when the number of `optional`
+    fields in a message is an exact multiple of 32. (#9440).
+
+  PHP
+  * Fixed a data loss bug that could occur when the number of `optional`
+    fields in a message is an exact multiple of 32. (#9440).
+
+2022-01-10 version 3.19.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  Python
+  * Fix missing Windows wheel for Python 3.10 on PyPI
+
+2022-01-05 version 3.19.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  Java
+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)
+  * This release addresses a Security Advisory for Java users
+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)
+
+2022-01-05 version 3.18.2 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  Java
+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)
+  * This release addresses a Security Advisory for Java users
+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)
+
+2022-01-05 version 3.16.1 (Java)
+
+  Java
+  * Improve performance characteristics of UnknownFieldSet parsing (#9371)
+  * This release addresses a Security Advisory for Java users
+   (https://github.com/protocolbuffers/protobuf/security/advisories/GHSA-wrvw-hg22-4m67)
+
+2021-10-28 version 3.19.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  Bazel
+  * Ensure that release archives contain everything needed for Bazel (#9131)
+  * Align dependency handling with Bazel best practices (#9165)
+
+  JavaScript
+  * Fix `ReferenceError: window is not defined` when getting the global object (#9156)
+
+  Ruby
+  * Fix memory leak in MessageClass.encode (#9150)
+
+2021-10-15 version 3.19.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
+
+  C++
   * Make proto2::Message::DiscardUnknownFields() non-virtual
+  * Separate RepeatedPtrField into its own header file
+  * For default floating point values of 0, consider all bits significant
+  * cmake: support `MSVC_RUNTIME_LIBRARY` property (#8851)
+  * Fix shadowing warnings (#8926)
+  * Fix for issue #8484, constant initialization doesn't compile in msvc clang-cl environment (#8993)
+  * Fix build on AIX and SunOS (#8373) (#9065)
+  * Add Android stlport and default toolchains to BUILD. (#8290)
+
+  Java
+  * For default floating point values of 0, consider all bits significant
+  * Annotate `//java/com/google/protobuf/util/...` with nullness annotations
+  * Use ArrayList copy constructor (#7853)
+
+  Kotlin
+  * Switch Kotlin proto DSLs to be implemented with inline value classes
+  * Fix inlining and deprecation for repeated string fields in kotlin (#9120)
+
+  Python
+  * Proto2 DecodeError now includes message name in error message
+  * Make MessageToDict convert map keys to strings (#8122)
+  * Add python-requires in setup.py (#8989)
+  * Add python 3.10 (#9034)
+
+  JavaScript
+  * Skip exports if not available by CommonJS (#8856)
+  * JS: Comply with CSP no-unsafe-eval. (#8864)
+
+  PHP
+  * Added "object" as a reserved name for PHP (#8962)
+
+  Ruby
+  * Override Map.clone to use Map's dup method (#7938)
+  * Ruby: build extensions for arm64-darwin (#8232)
+  * Add class method Timestamp.from_time to ruby well known types (#8562)
+  * Adopt pure ruby DSL implementation for JRuby (#9047)
+  * Add size to Map class (#8068)
+  * Fix for descriptor_pb.rb: google/protobuf should be required first (#9121)
+
+  C#
+  * Correctly set ExtensionRegistry when parsing with MessageParser, but using an already existing CodedInputStream (#7246)
+  * [C#] Make FieldDescriptor propertyName public (#7642)
 
 2021-10-04 version 3.18.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index db1ff31..8ef5dd2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,9 +1,31 @@
 # Contributing to Protocol Buffers
 
-We welcome your contributions to protocol buffers. This doc describes the
+We welcome some types of contributions to protocol buffers. This doc describes the
 process to contribute patches to protobuf and the general guidelines we
 expect contributors to follow.
 
+## What We Accept
+
+* Bug fixes with unit tests demonstrating the problem are very welcome.
+  We also appreciate bug reports, even when they don't come with a patch.
+  Bug fixes without tests are usually not accepted.
+* New APIs and features with adequate test coverage and documentation
+  may be accepted if they do not compromise backwards 
+  compatibility. However there's a fairly high bar of usefulness a new public
+  method must clear before it will be accepted. Features that are fine in 
+  isolation are often rejected because they don't have enough impact to justify the 
+  conceptual burden and ongoing maintenance cost. It's best to file an issue 
+  and get agreement from maintainers on the value of a new feature before
+  working on a PR.
+* Performance optimizations may be accepted if they have convincing benchmarks that demonstrate 
+  an improvement and they do not significantly increase complexity.  
+* Changes to existing APIs are almost never accepted. Stability and
+  backwards compatibility are paramount. In the unlikely event a breaking change 
+  is required, it must usually be implemented in google3 first. 
+* Changes to the wire and text formats are never accepted. Any breaking change
+  to these formats would have to be implemented as a completely new format.
+  We cannot begin generating protos that cannot be parsed by existing code.
+
 ## Before You Start
 
 We accept patches in the form of github pull requests. If you are new to
@@ -58,7 +80,7 @@
 * Create small PRs that are narrowly focused on addressing a single concern.
   We often receive PRs that are trying to fix several things at a time, but if
   only one fix is considered acceptable, nothing gets merged and both author's
-  & review's time is wasted. Create more PRs to address different concerns and
+  & reviewer's time is wasted. Create more PRs to address different concerns and
   everyone will be happy.
 * For speculative changes, consider opening an issue and discussing it first.
   If you are suggesting a behavioral or API change, make sure you get explicit
diff --git a/Makefile.am b/Makefile.am
index 6fb1c84..858eedf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1011,6 +1011,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                \
@@ -1426,7 +1427,6 @@
   examples/pubspec.yaml                  \
   protobuf.bzl                           \
   protobuf_deps.bzl                      \
-  third_party/six.BUILD                  \
   third_party/zlib.BUILD                 \
   util/python/BUILD                      \
   internal.bzl
diff --git a/Protobuf-C++.podspec b/Protobuf-C++.podspec
index f285e58..9b8fae5 100644
--- a/Protobuf-C++.podspec
+++ b/Protobuf-C++.podspec
@@ -35,9 +35,6 @@
     # Do not let src/google/protobuf/stubs/time.h override system API
     'USE_HEADERMAP' => 'NO',
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
-
-    # Configure tool is not being used for Xcode. When building, assume pthread is supported.
-    'GCC_PREPROCESSOR_DEFINITIONS' => '"$(inherited)" "HAVE_PTHREAD=1"',
   }
 
 end
diff --git a/Protobuf.podspec b/Protobuf.podspec
index 4a5f7dd..67c3114 100644
--- a/Protobuf.podspec
+++ b/Protobuf.podspec
@@ -5,10 +5,10 @@
 # dependent projects use the :git notation to refer to the library.
 Pod::Spec.new do |s|
   s.name     = 'Protobuf'
-  s.version  = '3.18.1'
+  s.version  = '3.19.4'
   s.summary  = 'Protocol Buffers v.3 runtime library for Objective-C.'
   s.homepage = 'https://github.com/protocolbuffers/protobuf'
-  s.license  = '3-Clause BSD License'
+  s.license  = 'BSD-3-Clause'
   s.authors  = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
   s.cocoapods_version = '>= 1.0'
 
diff --git a/WORKSPACE b/WORKSPACE
index 2174cab..36df3f3 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -27,7 +27,7 @@
 )
 
 # Load common dependencies.
-load("//:protobuf_deps.bzl", "protobuf_deps")
+load("//:protobuf_deps.bzl", "PROTOBUF_MAVEN_ARTIFACTS", "protobuf_deps")
 protobuf_deps()
 
 bind(
@@ -36,68 +36,33 @@
 )
 
 load("@rules_jvm_external//:defs.bzl", "maven_install")
+
 maven_install(
-    artifacts = [
-        "com.google.code.gson:gson:2.8.6",
-        "com.google.errorprone:error_prone_annotations:2.3.2",
-        "com.google.j2objc:j2obj_annotations:1.3",
-        "com.google.guava:guava:30.1.1-jre",
-        "com.google.truth:truth:1.1.2",
-        "junit:junit:4.12",
-        "org.easymock:easymock:3.2",
-    ],
+    artifacts = PROTOBUF_MAVEN_ARTIFACTS,
+    # For updating instructions, see:
+    # https://github.com/bazelbuild/rules_jvm_external#updating-maven_installjson
+    maven_install_json = "//:maven_install.json",
     repositories = [
         "https://repo1.maven.org/maven2",
         "https://repo.maven.apache.org/maven2",
     ],
-    # For updating instructions, see: 
-    # https://github.com/bazelbuild/rules_jvm_external#updating-maven_installjson
-    maven_install_json = "//:maven_install.json",
 )
 
 load("@maven//:defs.bzl", "pinned_maven_install")
+
 pinned_maven_install()
 
-bind(
-    name = "guava",
-    actual = "@maven//:com_google_guava_guava",
-)
-
-bind(
-    name = "gson",
-    actual = "@maven//:com_google_code_gson_gson",
-)
-
-bind(
-    name = "error_prone_annotations",
-    actual = "@maven//:com_google_errorprone_error_prone_annotations",
-)
-
-bind(
-    name = "j2objc_annotations",
-    actual = "@maven//:com_google_j2objc_j2objc_annotations",
-)
-
-bind(
-    name = "junit",
-    actual = "@maven//:junit_junit",
-)
-
-bind(
-    name = "easymock",
-    actual = "@maven//:org_easymock_easymock",
-)
-
-bind(
-    name = "easymock_classextension",
-    actual = "@maven//:org_easymock_easymockclassextension",
-)
-
-bind(
-    name = "truth",
-    actual = "@maven//:com_google_truth_truth",
-)
-
 # For `cc_proto_blacklist_test` and `build_test`.
 load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
+
 bazel_skylib_workspace()
+
+load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
+rules_pkg_dependencies()
+
+# For `kt_jvm_library`
+load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
+kotlin_repositories()
+
+load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
+kt_register_toolchains()
diff --git a/appveyor.bat b/appveyor.bat
index 7a35ceb..005fb11 100644
--- a/appveyor.bat
+++ b/appveyor.bat
@@ -38,7 +38,7 @@
 dotnet build -c %configuration% || goto error
 
 echo Testing C#
-dotnet test -c %configuration% -f netcoreapp2.1 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
+dotnet test -c %configuration% -f netcoreapp3.1 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
 dotnet test -c %configuration% -f net451 Google.Protobuf.Test\Google.Protobuf.Test.csproj || goto error
 
 goto :EOF
diff --git a/benchmarks/README.md b/benchmarks/README.md
index 9c25c78..f708afd 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/CMakeLists.txt b/cmake/CMakeLists.txt
index caa9215..51e8478 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -127,9 +127,6 @@
 endif()
 
 find_package(Threads REQUIRED)
-if (CMAKE_USE_PTHREADS_INIT)
-  add_definitions(-DHAVE_PTHREAD)
-endif (CMAKE_USE_PTHREADS_INIT)
 
 set(_protobuf_FIND_ZLIB)
 if (protobuf_WITH_ZLIB)
@@ -209,6 +206,8 @@
     # Build with multiple processes
     add_definitions(/MP)
   endif()
+  # Set source file and execution character sets to UTF-8
+  add_definitions(/utf-8)
   # MSVC warning suppressions
   add_definitions(
     /wd4018 # 'expression' : signed/unsigned mismatch
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index 8e26aed..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
@@ -48,6 +50,7 @@
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\duration.pb.h" include\google\protobuf\duration.pb.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\dynamic_message.h" include\google\protobuf\dynamic_message.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\empty.pb.h" include\google\protobuf\empty.pb.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\explicitly_constructed.h" include\google\protobuf\explicitly_constructed.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set.h" include\google\protobuf\extension_set.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\extension_set_inl.h" include\google\protobuf\extension_set_inl.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\field_access_listener.h" include\google\protobuf\field_access_listener.h
@@ -92,6 +95,7 @@
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h
+copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
index f36a7ac..0ee65e2 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 e4b810c..1f5ae5a 100644
--- a/cmake/libprotobuf.cmake
+++ b/cmake/libprotobuf.cmake
@@ -14,7 +14,6 @@
   ${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
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index 505e469..ed20f31 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -91,6 +91,8 @@
   ${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
@@ -117,6 +119,7 @@
   ${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/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/protobuf-module.cmake.in b/cmake/protobuf-module.cmake.in
index 810256e..09b9d29 100644
--- a/cmake/protobuf-module.cmake.in
+++ b/cmake/protobuf-module.cmake.in
@@ -110,16 +110,6 @@
   endif()
 endfunction()
 
-# Internal function: find threads library
-function(_protobuf_find_threads)
-    set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
-    find_package(Threads)
-    if(Threads_FOUND)
-        list(APPEND PROTOBUF_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
-        set(PROTOBUF_LIBRARIES "${PROTOBUF_LIBRARIES}" PARENT_SCOPE)
-    endif()
-endfunction()
-
 #
 # Main.
 #
@@ -139,10 +129,6 @@
 # The Protobuf Protoc Library
 _protobuf_find_libraries(Protobuf_PROTOC protoc)
 
-if(UNIX)
-  _protobuf_find_threads()
-endif()
-
 # Set the include directory
 get_target_property(Protobuf_INCLUDE_DIRS protobuf::libprotobuf
   INTERFACE_INCLUDE_DIRECTORIES)
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 9ede4f3..aa069fe 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -131,6 +131,7 @@
   ${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
@@ -155,6 +156,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_python.py b/conformance/conformance_python.py
index 37ee36e..f812752 100755
--- a/conformance/conformance_python.py
+++ b/conformance/conformance_python.py
@@ -39,8 +39,8 @@
 import os
 from google.protobuf import json_format
 from google.protobuf import message
-from google.protobuf import test_messages_proto3_pb2
-from google.protobuf import test_messages_proto2_pb2
+from google3.third_party.protobuf import test_messages_proto3_pb2
+from google3.third_party.protobuf import test_messages_proto2_pb2
 from google.protobuf import text_format
 import conformance_pb2
 
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/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec
index 8e5786f..098d79d 100644
--- a/csharp/Google.Protobuf.Tools.nuspec
+++ b/csharp/Google.Protobuf.Tools.nuspec
@@ -5,7 +5,7 @@
     <title>Google Protocol Buffers tools</title>
     <summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
     <description>See project site for more info.</description>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
     <authors>Google Inc.</authors>
     <owners>protobuf-packages</owners>
     <licenseUrl>https://github.com/protocolbuffers/protobuf/blob/master/LICENSE</licenseUrl>
diff --git a/csharp/NuGet.Config b/csharp/NuGet.Config
new file mode 100644
index 0000000..b04b006
--- /dev/null
+++ b/csharp/NuGet.Config
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <!--To inherit the global NuGet package sources remove the <clear/> line below -->
+    <clear />
+    <add key="NuGet.org (v3)" value="https://api.nuget.org/v3/index.json" />
+  </packageSources>
+</configuration>
\ No newline at end of file
diff --git a/csharp/build_packages.bat b/csharp/build_packages.bat
index d720565..9e68229 100644
--- a/csharp/build_packages.bat
+++ b/csharp/build_packages.bat
@@ -1,7 +1,7 @@
 @rem Builds Google.Protobuf NuGet packages
 
 dotnet restore src/Google.Protobuf.sln
-dotnet pack -c Release src/Google.Protobuf.sln || goto :error
+dotnet pack -c Release src/Google.Protobuf.sln -p:ContinuousIntegrationBuild=true || goto :error
 
 goto :EOF
 
diff --git a/csharp/buildall.sh b/csharp/buildall.sh
index 43b5ac3..ab1a6c4 100755
--- a/csharp/buildall.sh
+++ b/csharp/buildall.sh
@@ -10,8 +10,8 @@
 dotnet build -c $CONFIG $SRC/Google.Protobuf.sln
 
 echo Running tests.
-# Only test netcoreapp2.1, which uses the .NET Core runtime.
+# Only test netcoreapp3.1, which uses the .NET Core runtime.
 # If we want to test the .NET 4.5 version separately, we could
 # run Mono explicitly. However, we don't have any differences between
 # the .NET 4.5 and netstandard2.1 assemblies.
-dotnet test -c $CONFIG -f netcoreapp2.1 $SRC/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+dotnet test -c $CONFIG -f netcoreapp3.1 $SRC/Google.Protobuf.Test/Google.Protobuf.Test.csproj
diff --git a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
index cbb6fee..0ecdf37 100644
--- a/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ b/csharp/compatibility_tests/v3.0.0/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFrameworks>net451;netcoreapp2.1</TargetFrameworks>
+    <TargetFrameworks>net451;netcoreapp3.1</TargetFrameworks>
     <AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
     <SignAssembly>true</SignAssembly>
     <IsPackable>False</IsPackable>
diff --git a/csharp/compatibility_tests/v3.0.0/test.sh b/csharp/compatibility_tests/v3.0.0/test.sh
index f893d64..459c079 100755
--- a/csharp/compatibility_tests/v3.0.0/test.sh
+++ b/csharp/compatibility_tests/v3.0.0/test.sh
@@ -22,7 +22,7 @@
   dotnet restore src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
   dotnet build -c Release src/Google.Protobuf/Google.Protobuf.csproj
   dotnet build -c Release src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
-  dotnet run -c Release -f netcoreapp2.1 -p src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+  dotnet run -c Release -f netcoreapp3.1 -p src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
 }
 
 set -ex
diff --git a/csharp/install_dotnet_sdk.ps1 b/csharp/install_dotnet_sdk.ps1
index c78655c..f9dc0d9 100755
--- a/csharp/install_dotnet_sdk.ps1
+++ b/csharp/install_dotnet_sdk.ps1
@@ -16,5 +16,5 @@
 
 # The SDK versions to install should be kept in sync with versions
 # installed by kokoro/linux/dockerfile/test/csharp/Dockerfile
-&$InstallScriptPath -Version 2.1.802
-&$InstallScriptPath -Version 5.0.102
+&$InstallScriptPath -Version 3.1.415
+&$InstallScriptPath -Version 6.0.100
diff --git a/csharp/src/AddressBook/AddressBook.csproj b/csharp/src/AddressBook/AddressBook.csproj
index f3268c0..9a52787 100644
--- a/csharp/src/AddressBook/AddressBook.csproj
+++ b/csharp/src/AddressBook/AddressBook.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <OutputType>Exe</OutputType>
     <StartupObject>Google.Protobuf.Examples.AddressBook.Program</StartupObject>
     <IsPackable>False</IsPackable>
diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs
index 2e88db9..484a229 100644
--- a/csharp/src/AddressBook/Addressbook.cs
+++ b/csharp/src/AddressBook/Addressbook.cs
@@ -32,9 +32,10 @@
             "Eg4KBm51bWJlchgBIAEoCRIoCgR0eXBlGAIgASgOMhoudHV0b3JpYWwuUGVy",
             "c29uLlBob25lVHlwZSIrCglQaG9uZVR5cGUSCgoGTU9CSUxFEAASCAoESE9N",
             "RRABEggKBFdPUksQAiIvCgtBZGRyZXNzQm9vaxIgCgZwZW9wbGUYASADKAsy",
-            "EC50dXRvcmlhbC5QZXJzb25CZgobY29tLmV4YW1wbGUudHV0b3JpYWwucHJv",
-            "dG9zQhFBZGRyZXNzQm9va1Byb3Rvc1ABWgsuLi90dXRvcmlhbKoCJEdvb2ds",
-            "ZS5Qcm90b2J1Zi5FeGFtcGxlcy5BZGRyZXNzQm9va2IGcHJvdG8z"));
+            "EC50dXRvcmlhbC5QZXJzb25ClQEKG2NvbS5leGFtcGxlLnR1dG9yaWFsLnBy",
+            "b3Rvc0IRQWRkcmVzc0Jvb2tQcm90b3NQAVo6Z2l0aHViLmNvbS9wcm90b2Nv",
+            "bGJ1ZmZlcnMvcHJvdG9idWYvZXhhbXBsZXMvZ28vdHV0b3JpYWxwYqoCJEdv",
+            "b2dsZS5Qcm90b2J1Zi5FeGFtcGxlcy5BZGRyZXNzQm9va2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, },
           new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
diff --git a/csharp/src/Google.Protobuf.Benchmarks/Program.cs b/csharp/src/Google.Protobuf.Benchmarks/Program.cs
index 1f77a26..037752f 100644
--- a/csharp/src/Google.Protobuf.Benchmarks/Program.cs
+++ b/csharp/src/Google.Protobuf.Benchmarks/Program.cs
@@ -36,7 +36,7 @@
 {
     class Program
     {
-        // typical usage: dotnet run -c Release -f netcoreapp2.1
+        // typical usage: dotnet run -c Release -f netcoreapp3.1
         // (this can profile both .net core and .net framework; for some reason
         // if you start from "-f net461", it goes horribly wrong)
         public static void Main(string[] args)
diff --git a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
index ec8fb91..6277e68 100644
--- a/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
+++ b/csharp/src/Google.Protobuf.Conformance/Google.Protobuf.Conformance.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <OutputType>Exe</OutputType>
     <IsPackable>False</IsPackable>
   </PropertyGroup>
diff --git a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
index fee35be..b2c4272 100644
--- a/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
+++ b/csharp/src/Google.Protobuf.JsonDump/Google.Protobuf.JsonDump.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFramework>netcoreapp2.1</TargetFramework>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
     <OutputType>Exe</OutputType>
     <IsPackable>False</IsPackable>
   </PropertyGroup>
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
index 9f2ba6b..5030043 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/Google.Protobuf.Test.TestProtos.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">

+<Project Sdk="Microsoft.NET.Sdk">

 

   <!--

     This TestProtos project is kept separate from the original test project for many reasons.

@@ -15,7 +15,7 @@
 

   <!-- Needed for the net45 build to work on Unix. See https://github.com/dotnet/designs/pull/33 -->

   <ItemGroup>

-    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="All" />

+    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />

   </ItemGroup>

   

   <ItemGroup>

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.Test/Collections/RepeatedFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
index 61453e5..ff8f5cc 100644
--- a/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs
@@ -840,7 +840,7 @@
             var list2 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.PayloadFlipped };
             var list3 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.SignallingFlipped };
 
-            // All SampleNaNs have the same hashcode under certain targets (e.g. netcoreapp2.1)
+            // All SampleNaNs have the same hashcode under certain targets (e.g. netcoreapp3.1)
             EqualityTester.AssertInequality(list1, list2, checkHashcode: false);
             EqualityTester.AssertEquality(list1, list3);
             Assert.True(list1.Contains(SampleNaNs.SignallingFlipped));
diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs
index 1abed60..894d914 100644
--- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs
+++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.Proto2.cs
@@ -380,5 +380,18 @@
                 TestGroupExtension.Parser.WithExtensionRegistry(new ExtensionRegistry() { TestNestedExtension.Extensions.OptionalGroupExtension }),

                 message);

         }

+

+        [Test]

+        public void RoundTrip_ParseUsingCodedInput()

+        {

+            var message = new TestAllExtensions();

+            message.SetExtension(UnittestExtensions.OptionalBoolExtension, true);

+            byte[] bytes = message.ToByteArray();

+            using (CodedInputStream input = new CodedInputStream(bytes))

+            {

+                var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input);

+                Assert.AreEqual(message, parsed);

+            }

+        }

     }

 }

diff --git a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
index cdfa98e..deb17e9 100644
--- a/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
+++ b/csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>net451;netcoreapp2.1;net50</TargetFrameworks>
+    <TargetFrameworks>net451;netcoreapp3.1;net60</TargetFrameworks>
     <AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
     <SignAssembly>true</SignAssembly>
     <IsPackable>False</IsPackable>
@@ -21,7 +21,7 @@
 
   <!-- Needed for the net45 build to work on Unix. See https://github.com/dotnet/designs/pull/33 -->
   <ItemGroup>
-    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="All" />
+    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
index 69c9eb6..eb8996e 100644
--- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -35,6 +35,7 @@
 using Google.Protobuf.WellKnownTypes;
 using NUnit.Framework;
 using ProtobufTestMessages.Proto2;
+using ProtobufTestMessages.Proto3;
 using System;
 using UnitTest.Issues.TestProtos;
 
@@ -551,13 +552,9 @@
         }
 
         [Test]
-        // Skip these test cases in .NET 5 because floating point parsing supports bigger values.
-        // These big values won't throw an error in the test.
-#if !NET5_0
         [TestCase("1.7977e308")]
         [TestCase("-1.7977e308")]
         [TestCase("1e309")]
-#endif
         [TestCase("1,0")]
         [TestCase("1.0.0")]
         [TestCase("+1")]
@@ -922,10 +919,10 @@
         }
 
         [Test]
-        [TestCase("\"FOREIGN_BAR\"", ForeignEnum.ForeignBar)]
-        [TestCase("5", ForeignEnum.ForeignBar)]
-        [TestCase("100", (ForeignEnum)100)]
-        public void EnumValid(string value, ForeignEnum expectedValue)
+        [TestCase("\"FOREIGN_BAR\"", TestProtos.ForeignEnum.ForeignBar)]
+        [TestCase("5", TestProtos.ForeignEnum.ForeignBar)]
+        [TestCase("100", (TestProtos.ForeignEnum)100)]
+        public void EnumValid(string value, TestProtos.ForeignEnum expectedValue)
         {
             string json = "{ \"singleForeignEnum\": " + value + " }";
             var parsed = TestAllTypes.Parser.ParseJson(json);
@@ -1025,5 +1022,128 @@
         {
             return '"' + text + '"';
         }
+
+        [Test]
+        public void ParseAllNullValues()
+        {
+            string json = @"{
+  ""optionalInt32"": null,
+  ""optionalInt64"": null,
+  ""optionalUint32"": null,
+  ""optionalUint64"": null,
+  ""optionalSint32"": null,
+  ""optionalSint64"": null,
+  ""optionalFixed32"": null,
+  ""optionalFixed64"": null,
+  ""optionalSfixed32"": null,
+  ""optionalSfixed64"": null,
+  ""optionalFloat"": null,
+  ""optionalDouble"": null,
+  ""optionalBool"": null,
+  ""optionalString"": null,
+  ""optionalBytes"": null,
+  ""optionalNestedEnum"": null,
+  ""optionalNestedMessage"": null,
+  ""repeatedInt32"": null,
+  ""repeatedInt64"": null,
+  ""repeatedUint32"": null,
+  ""repeatedUint64"": null,
+  ""repeatedSint32"": null,
+  ""repeatedSint64"": null,
+  ""repeatedFixed32"": null,
+  ""repeatedFixed64"": null,
+  ""repeatedSfixed32"": null,
+  ""repeatedSfixed64"": null,
+  ""repeatedFloat"": null,
+  ""repeatedDouble"": null,
+  ""repeatedBool"": null,
+  ""repeatedString"": null,
+  ""repeatedBytes"": null,
+  ""repeatedNestedEnum"": null,
+  ""repeatedNestedMessage"": null,
+  ""mapInt32Int32"": null,
+  ""mapBoolBool"": null,
+  ""mapStringNestedMessage"": null
+}";
+
+            TestAllTypesProto3 message = new TestAllTypesProto3();
+
+            message.OptionalInt32 = 1;
+            message.OptionalInt64 = 1;
+            message.OptionalUint32 = 1;
+            message.OptionalUint64 = 1;
+            message.OptionalSint32 = 1;
+            message.OptionalSint64 = 1;
+            message.OptionalFixed32 = 1;
+            message.OptionalFixed64 = 1;
+            message.OptionalSfixed32 = 1;
+            message.OptionalSfixed64 = 1;
+            message.OptionalFloat = 1;
+            message.OptionalDouble = 1;
+            message.OptionalBool = true;
+            message.OptionalString = "1";
+            message.OptionalBytes = ByteString.CopyFrom(new byte[] { 1 });
+            message.OptionalNestedEnum = TestAllTypesProto3.Types.NestedEnum.Bar;
+            message.OptionalNestedMessage = new TestAllTypesProto3.Types.NestedMessage();
+            message.RepeatedInt32.Add(1);
+            message.RepeatedInt64.Add(1);
+            message.RepeatedUint32.Add(1);
+            message.RepeatedUint64.Add(1);
+            message.RepeatedSint32.Add(1);
+            message.RepeatedSint64.Add(1);
+            message.RepeatedFixed32.Add(1);
+            message.RepeatedFixed64.Add(1);
+            message.RepeatedSfixed32.Add(1);
+            message.RepeatedSfixed64.Add(1);
+            message.RepeatedFloat.Add(1);
+            message.RepeatedDouble.Add(1);
+            message.RepeatedBool.Add(true);
+            message.RepeatedString.Add("1");
+            message.RepeatedBytes.Add(ByteString.CopyFrom(new byte[] { 1 }));
+            message.RepeatedNestedEnum.Add(TestAllTypesProto3.Types.NestedEnum.Bar);
+            message.RepeatedNestedMessage.Add(new TestAllTypesProto3.Types.NestedMessage());
+            message.MapInt32Int32.Add(1, 1);
+            message.MapBoolBool.Add(true, true);
+            message.MapStringNestedMessage.Add(" ", new TestAllTypesProto3.Types.NestedMessage());
+
+            JsonParser.Default.Merge(message, json);
+
+            Assert.AreEqual(0, message.OptionalInt32);
+            Assert.AreEqual(0, message.OptionalInt64);
+            Assert.AreEqual(0, message.OptionalUint32);
+            Assert.AreEqual(0, message.OptionalUint64);
+            Assert.AreEqual(0, message.OptionalSint32);
+            Assert.AreEqual(0, message.OptionalSint64);
+            Assert.AreEqual(0, message.OptionalFixed32);
+            Assert.AreEqual(0, message.OptionalFixed64);
+            Assert.AreEqual(0, message.OptionalSfixed32);
+            Assert.AreEqual(0, message.OptionalSfixed64);
+            Assert.AreEqual(0, message.OptionalFloat);
+            Assert.AreEqual(0, message.OptionalDouble);
+            Assert.AreEqual(false, message.OptionalBool);
+            Assert.AreEqual("", message.OptionalString);
+            Assert.AreEqual(ByteString.Empty, message.OptionalBytes);
+            Assert.AreEqual(TestAllTypesProto3.Types.NestedEnum.Foo, message.OptionalNestedEnum);
+            Assert.AreEqual(null, message.OptionalNestedMessage);
+            Assert.AreEqual(0, message.RepeatedInt32.Count);
+            Assert.AreEqual(0, message.RepeatedInt64.Count);
+            Assert.AreEqual(0, message.RepeatedUint32.Count);
+            Assert.AreEqual(0, message.RepeatedUint64.Count);
+            Assert.AreEqual(0, message.RepeatedSint32.Count);
+            Assert.AreEqual(0, message.RepeatedSint64.Count);
+            Assert.AreEqual(0, message.RepeatedFixed32.Count);
+            Assert.AreEqual(0, message.RepeatedFixed64.Count);
+            Assert.AreEqual(0, message.RepeatedSfixed32.Count);
+            Assert.AreEqual(0, message.RepeatedFloat.Count);
+            Assert.AreEqual(0, message.RepeatedDouble.Count);
+            Assert.AreEqual(0, message.RepeatedBool.Count);
+            Assert.AreEqual(0, message.RepeatedString.Count);
+            Assert.AreEqual(0, message.RepeatedBytes.Count);
+            Assert.AreEqual(0, message.RepeatedNestedEnum.Count);
+            Assert.AreEqual(0, message.RepeatedNestedMessage.Count);
+            Assert.AreEqual(0, message.MapInt32Int32.Count);
+            Assert.AreEqual(0, message.MapBoolBool.Count);
+            Assert.AreEqual(0, message.MapStringNestedMessage.Count);
+        }
     }
 }
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
index 0cbc0a4..df43eff 100644
--- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -199,12 +199,8 @@
         [TestCase("1e-")]
         [TestCase("--")]
         [TestCase("--1")]
-        // Skip these test cases in .NET 5 because floating point parsing supports bigger values.
-        // These big values won't throw an error in the test.
-#if !NET5_0
         [TestCase("-1.7977e308")]
         [TestCase("1.7977e308")]
-#endif
         public void InvalidNumberValue(string json)
         {
             AssertThrowsAfter(json);
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
index fab983d..65c8b82 100644
--- a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs
@@ -124,6 +124,7 @@
             }
 
             Assert.AreEqual(10, file.SerializedData[0]);
+            TestDescriptorToProto(file.ToProto, file.Proto);
         }
 
         [Test]
@@ -231,6 +232,7 @@
             {
                 Assert.AreEqual(i, messageType.EnumTypes[i].Index);
             }
+            TestDescriptorToProto(messageType.ToProto, messageType.Proto);
         }
 
         [Test]
@@ -294,6 +296,11 @@
             // For a field in a regular onoef, ContainingOneof and RealContainingOneof should be the same.
             Assert.AreEqual("oneof_field", fieldInOneof.ContainingOneof.Name);
             Assert.AreSame(fieldInOneof.ContainingOneof, fieldInOneof.RealContainingOneof);
+
+            TestDescriptorToProto(primitiveField.ToProto, primitiveField.Proto);
+            TestDescriptorToProto(enumField.ToProto, enumField.Proto);
+            TestDescriptorToProto(foreignMessageField.ToProto, foreignMessageField.Proto);
+            TestDescriptorToProto(fieldInOneof.ToProto, fieldInOneof.Proto);
         }
 
         [Test]
@@ -338,6 +345,8 @@
             {
                 Assert.AreEqual(i, enumType.Values[i].Index);
             }
+            TestDescriptorToProto(enumType.ToProto, enumType.Proto);
+            TestDescriptorToProto(nestedType.ToProto, nestedType.Proto);
         }
 
         [Test]
@@ -361,6 +370,7 @@
             }
 
             CollectionAssert.AreEquivalent(expectedFields, descriptor.Fields);
+            TestDescriptorToProto(descriptor.ToProto, descriptor.Proto);
         }
 
         [Test]
@@ -370,6 +380,7 @@
             Assert.IsNull(descriptor.Parser);
             Assert.IsNull(descriptor.ClrType);
             Assert.IsNull(descriptor.Fields[1].Accessor);
+            TestDescriptorToProto(descriptor.ToProto, descriptor.Proto);
         }
 
         // From TestFieldOrdering:
@@ -391,6 +402,7 @@
         {
             var descriptor = Google.Protobuf.Reflection.FileDescriptor.DescriptorProtoFileDescriptor;
             Assert.AreEqual("google/protobuf/descriptor.proto", descriptor.Name);
+            TestDescriptorToProto(descriptor.ToProto, descriptor.Proto);
         }
 
         [Test]
@@ -453,5 +465,17 @@
                 }
             }
         }
+
+        private static void TestDescriptorToProto(Func<IMessage> toProtoFunction, IMessage expectedProto)
+        {
+            var clone1 = toProtoFunction();
+            var clone2 = toProtoFunction();
+            Assert.AreNotSame(clone1, clone2);
+            Assert.AreNotSame(clone1, expectedProto);
+            Assert.AreNotSame(clone2, expectedProto);
+
+            Assert.AreEqual(clone1, clone2);
+            Assert.AreEqual(clone1, expectedProto);
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index f1f44f1..2fc4b53 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMemberTypes.cs b/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMemberTypes.cs
new file mode 100644
index 0000000..a4d739d
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMemberTypes.cs
@@ -0,0 +1,127 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if !NET5_0_OR_GREATER
+// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
+namespace System.Diagnostics.CodeAnalysis
+{
+    /// <summary>
+    /// Specifies the types of members that are dynamically accessed.
+    ///
+    /// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a
+    /// bitwise combination of its member values.
+    /// </summary>
+    [Flags]
+    internal enum DynamicallyAccessedMemberTypes
+    {
+        /// <summary>
+        /// Specifies no members.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Specifies the default, parameterless public constructor.
+        /// </summary>
+        PublicParameterlessConstructor = 0x0001,
+
+        /// <summary>
+        /// Specifies all public constructors.
+        /// </summary>
+        PublicConstructors = 0x0002 | PublicParameterlessConstructor,
+
+        /// <summary>
+        /// Specifies all non-public constructors.
+        /// </summary>
+        NonPublicConstructors = 0x0004,
+
+        /// <summary>
+        /// Specifies all public methods.
+        /// </summary>
+        PublicMethods = 0x0008,
+
+        /// <summary>
+        /// Specifies all non-public methods.
+        /// </summary>
+        NonPublicMethods = 0x0010,
+
+        /// <summary>
+        /// Specifies all public fields.
+        /// </summary>
+        PublicFields = 0x0020,
+
+        /// <summary>
+        /// Specifies all non-public fields.
+        /// </summary>
+        NonPublicFields = 0x0040,
+
+        /// <summary>
+        /// Specifies all public nested types.
+        /// </summary>
+        PublicNestedTypes = 0x0080,
+
+        /// <summary>
+        /// Specifies all non-public nested types.
+        /// </summary>
+        NonPublicNestedTypes = 0x0100,
+
+        /// <summary>
+        /// Specifies all public properties.
+        /// </summary>
+        PublicProperties = 0x0200,
+
+        /// <summary>
+        /// Specifies all non-public properties.
+        /// </summary>
+        NonPublicProperties = 0x0400,
+
+        /// <summary>
+        /// Specifies all public events.
+        /// </summary>
+        PublicEvents = 0x0800,
+
+        /// <summary>
+        /// Specifies all non-public events.
+        /// </summary>
+        NonPublicEvents = 0x1000,
+
+        /// <summary>
+        /// Specifies all interfaces implemented by the type.
+        /// </summary>
+        Interfaces = 0x2000,
+
+        /// <summary>
+        /// Specifies all members.
+        /// </summary>
+        All = ~None
+    }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMembersAttribute.cs b/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMembersAttribute.cs
new file mode 100644
index 0000000..ae09276
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/DynamicallyAccessedMembersAttribute.cs
@@ -0,0 +1,83 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if !NET5_0_OR_GREATER
+// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
+namespace System.Diagnostics.CodeAnalysis
+{
+    /// <summary>
+    /// Indicates that certain members on a specified <see cref="Type"/> are accessed dynamically,
+    /// for example through <see cref="System.Reflection"/>.
+    /// </summary>
+    /// <remarks>
+    /// This allows tools to understand which members are being accessed during the execution
+    /// of a program.
+    ///
+    /// This attribute is valid on members whose type is <see cref="Type"/> or <see cref="string"/>.
+    ///
+    /// When this attribute is applied to a location of type <see cref="string"/>, the assumption is
+    /// that the string represents a fully qualified type name.
+    ///
+    /// When this attribute is applied to a class, interface, or struct, the members specified
+    /// can be accessed dynamically on <see cref="Type"/> instances returned from calling
+    /// <see cref="object.GetType"/> on instances of that class, interface, or struct.
+    ///
+    /// If the attribute is applied to a method it's treated as a special case and it implies
+    /// the attribute should be applied to the "this" parameter of the method. As such the attribute
+    /// should only be used on instance methods of types assignable to System.Type (or string, but no methods
+    /// will use it there).
+    /// </remarks>
+    [AttributeUsage(
+        AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
+        AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
+        AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
+        Inherited = false)]
+    internal sealed class DynamicallyAccessedMembersAttribute : Attribute
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
+        /// with the specified member types.
+        /// </summary>
+        /// <param name="memberTypes">The types of members dynamically accessed.</param>
+        public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
+        {
+            MemberTypes = memberTypes;
+        }
+
+        /// <summary>
+        /// Gets the <see cref="DynamicallyAccessedMemberTypes"/> which specifies the type
+        /// of members dynamically accessed.
+        /// </summary>
+        public DynamicallyAccessedMemberTypes MemberTypes { get; }
+    }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf/Compatibility/RequiresUnreferencedCodeAttribute.cs b/csharp/src/Google.Protobuf/Compatibility/RequiresUnreferencedCodeAttribute.cs
new file mode 100644
index 0000000..1fc8e66
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/RequiresUnreferencedCodeAttribute.cs
@@ -0,0 +1,72 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if !NET5_0_OR_GREATER
+// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
+namespace System.Diagnostics.CodeAnalysis
+{
+    /// <summary>
+    /// Indicates that the specified method requires dynamic access to code that is not referenced
+    /// statically, for example through <see cref="System.Reflection"/>.
+    /// </summary>
+    /// <remarks>
+    /// This allows tools to understand which methods are unsafe to call when removing unreferenced
+    /// code from an application.
+    /// </remarks>
+    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
+    internal sealed class RequiresUnreferencedCodeAttribute : Attribute
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RequiresUnreferencedCodeAttribute"/> class
+        /// with the specified message.
+        /// </summary>
+        /// <param name="message">
+        /// A message that contains information about the usage of unreferenced code.
+        /// </param>
+        public RequiresUnreferencedCodeAttribute(string message)
+        {
+            Message = message;
+        }
+
+        /// <summary>
+        /// Gets a message that contains information about the usage of unreferenced code.
+        /// </summary>
+        public string Message { get; }
+
+        /// <summary>
+        /// Gets or sets an optional URL that contains more information about the method,
+        /// why it requires unreferenced code, and what options a consumer has to deal with it.
+        /// </summary>
+        public string Url { get; set; }
+    }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
index 2f23713..b3acda2 100644
--- a/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
+++ b/csharp/src/Google.Protobuf/Compatibility/TypeExtensions.cs
@@ -31,6 +31,7 @@
 #endregion
 
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
 
 #if !NET35
@@ -59,7 +60,11 @@
         /// including inherited properties or null if there is no such public property.
         /// Here, "public property" means a property where either the getter, or the setter, or both, is public.
         /// </summary>
-        internal static PropertyInfo GetProperty(this Type target, string name)
+        [UnconditionalSuppressMessage("Trimming", "IL2072",
+            Justification = "The BaseType of the target will have all properties because of the annotation.")]
+        internal static PropertyInfo GetProperty(
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
+            this Type target, string name)
         {
             // GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
             while (target != null)
@@ -86,7 +91,11 @@
         /// class Child : Base declares public void Foo(long)).
         /// </remarks>
         /// <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
-        internal static MethodInfo GetMethod(this Type target, string name)
+        [UnconditionalSuppressMessage("Trimming", "IL2072",
+            Justification = "The BaseType of the target will have all properties because of the annotation.")]
+        internal static MethodInfo GetMethod(
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
+            this Type target, string name)
         {
             // GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
             while (target != null)
diff --git a/csharp/src/Google.Protobuf/Compatibility/UnconditionalSuppressMessageAttribute.cs b/csharp/src/Google.Protobuf/Compatibility/UnconditionalSuppressMessageAttribute.cs
new file mode 100644
index 0000000..a02a145
--- /dev/null
+++ b/csharp/src/Google.Protobuf/Compatibility/UnconditionalSuppressMessageAttribute.cs
@@ -0,0 +1,117 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+#if !NET5_0_OR_GREATER
+// Copied with permission from https://github.com/dotnet/runtime/tree/8fbf206d0e518b45ca855832e8bfb391afa85972/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
+namespace System.Diagnostics.CodeAnalysis
+{
+    /// <summary>
+    /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a
+    /// single code artifact.
+    /// </summary>
+    /// <remarks>
+    /// <see cref="UnconditionalSuppressMessageAttribute"/> is different than
+    /// <see cref="SuppressMessageAttribute"/> in that it doesn't have a
+    /// <see cref="ConditionalAttribute"/>. So it is always preserved in the compiled assembly.
+    /// </remarks>
+    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
+    internal sealed class UnconditionalSuppressMessageAttribute : Attribute
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="UnconditionalSuppressMessageAttribute"/>
+        /// class, specifying the category of the tool and the identifier for an analysis rule.
+        /// </summary>
+        /// <param name="category">The category for the attribute.</param>
+        /// <param name="checkId">The identifier of the analysis rule the attribute applies to.</param>
+        public UnconditionalSuppressMessageAttribute(string category, string checkId)
+        {
+            Category = category;
+            CheckId = checkId;
+        }
+
+        /// <summary>
+        /// Gets the category identifying the classification of the attribute.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="Category"/> property describes the tool or tool analysis category
+        /// for which a message suppression attribute applies.
+        /// </remarks>
+        public string Category { get; }
+
+        /// <summary>
+        /// Gets the identifier of the analysis tool rule to be suppressed.
+        /// </summary>
+        /// <remarks>
+        /// Concatenated together, the <see cref="Category"/> and <see cref="CheckId"/>
+        /// properties form a unique check identifier.
+        /// </remarks>
+        public string CheckId { get; }
+
+        /// <summary>
+        /// Gets or sets the scope of the code that is relevant for the attribute.
+        /// </summary>
+        /// <remarks>
+        /// The Scope property is an optional argument that specifies the metadata scope for which
+        /// the attribute is relevant.
+        /// </remarks>
+        public string Scope { get; set; }
+
+        /// <summary>
+        /// Gets or sets a fully qualified path that represents the target of the attribute.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="Target"/> property is an optional argument identifying the analysis target
+        /// of the attribute. An example value is "System.IO.Stream.ctor():System.Void".
+        /// Because it is fully qualified, it can be long, particularly for targets such as parameters.
+        /// The analysis tool user interface should be capable of automatically formatting the parameter.
+        /// </remarks>
+        public string Target { get; set; }
+
+        /// <summary>
+        /// Gets or sets an optional argument expanding on exclusion criteria.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="MessageId "/> property is an optional argument that specifies additional
+        /// exclusion where the literal metadata target is not sufficiently precise. For example,
+        /// the <see cref="UnconditionalSuppressMessageAttribute"/> cannot be applied within a method,
+        /// and it may be desirable to suppress a violation against a statement in the method that will
+        /// give a rule violation, but not against all statements in the method.
+        /// </remarks>
+        public string MessageId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the justification for suppressing the code analysis message.
+        /// </summary>
+        public string Justification { get; set; }
+    }
+}
+#endif
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index f6d6069..8c2a68a 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -1,10 +1,10 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
     <Copyright>Copyright 2015, Google Inc.</Copyright>
     <AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
-    <VersionPrefix>3.18.1</VersionPrefix>
+    <VersionPrefix>3.19.4</VersionPrefix>
     <!-- C# 7.2 is required for Span/BufferWriter/ReadOnlySequence -->
     <LangVersion>7.2</LangVersion>
     <Authors>Google Inc.</Authors>
@@ -15,12 +15,14 @@
     <PackageTags>Protocol;Buffers;Binary;Serialization;Format;Google;proto;proto3</PackageTags>
     <PackageReleaseNotes>C# proto3 support</PackageReleaseNotes>
     <PackageProjectUrl>https://github.com/protocolbuffers/protobuf</PackageProjectUrl>
-    <PackageLicenseUrl>https://github.com/protocolbuffers/protobuf/blob/master/LICENSE</PackageLicenseUrl>
+    <PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
     <RepositoryType>git</RepositoryType>
     <RepositoryUrl>https://github.com/protocolbuffers/protobuf.git</RepositoryUrl>
-    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <EmbedUntrackedSources>true</EmbedUntrackedSources>
     <!-- Include PDB in the built .nupkg -->
     <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
+    <IsTrimmable>true</IsTrimmable>
   </PropertyGroup>
 
   <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
@@ -43,7 +45,7 @@
 
   <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
     <PackageReference Include="System.Memory" Version="4.5.3"/>
-    <!-- Needed for netcoreapp2.1 to work correctly. .NET is not able to load the assembly without this -->
+    <!-- Needed for netcoreapp3.1 to work correctly. .NET is not able to load the assembly without this -->
     <PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2"/>
   </ItemGroup>
 
diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs
index 4bffd58..17fdc7f 100644
--- a/csharp/src/Google.Protobuf/JsonFormatter.cs
+++ b/csharp/src/Google.Protobuf/JsonFormatter.cs
@@ -40,6 +40,7 @@
 using System.Linq;
 using System.Collections.Generic;
 using System.Reflection;
+using System.Diagnostics.CodeAnalysis;
 
 namespace Google.Protobuf
 {
@@ -879,6 +880,8 @@
             private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
                 = new Dictionary<System.Type, Dictionary<object, string>>();
 
+            [UnconditionalSuppressMessage("Trimming", "IL2072",
+                Justification = "The field for the value must still be present. It will be returned by reflection, will be in this collection, and its name can be resolved.")]
             internal static string GetOriginalName(object value)
             {
                 var enumType = value.GetType();
@@ -898,21 +901,13 @@
                 return originalName;
             }
 
-#if NET35
-            // TODO: Consider adding functionality to TypeExtensions to avoid this difference.
-            private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
-                enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
-                    .Where(f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
-                                 .FirstOrDefault() as OriginalNameAttribute)
-                                 ?.PreferredAlias ?? true)
-                    .ToDictionary(f => f.GetValue(null),
-                                  f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
-                                        .FirstOrDefault() as OriginalNameAttribute)
-                                        // If the attribute hasn't been applied, fall back to the name of the field.
-                                        ?.Name ?? f.Name);
-#else
-            private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
-                enumType.GetTypeInfo().DeclaredFields
+            private static Dictionary<object, string> GetNameMapping(
+                [DynamicallyAccessedMembers(
+                    DynamicallyAccessedMemberTypes.PublicFields |
+                    DynamicallyAccessedMemberTypes.NonPublicFields)]
+                System.Type enumType)
+            {
+                return enumType.GetTypeInfo().DeclaredFields
                     .Where(f => f.IsStatic)
                     .Where(f => f.GetCustomAttributes<OriginalNameAttribute>()
                                  .FirstOrDefault()?.PreferredAlias ?? true)
@@ -921,7 +916,7 @@
                                         .FirstOrDefault()
                                         // If the attribute hasn't been applied, fall back to the name of the field.
                                         ?.Name ?? f.Name);
-#endif
+            }
         }
     }
 }
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
index 4725e7c..13a12c0 100644
--- a/csharp/src/Google.Protobuf/JsonTokenizer.cs
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -471,9 +471,18 @@
                 // TODO: What exception should we throw if the value can't be represented as a double?
                 try
                 {
-                    return double.Parse(builder.ToString(),
+                    double result = double.Parse(builder.ToString(),
                         NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
                         CultureInfo.InvariantCulture);
+
+                    // .NET Core 3.0 and later returns infinity if the number is too large or small to be represented.
+                    // For compatibility with other Protobuf implementations the tokenizer should still throw.
+                    if (double.IsInfinity(result))
+                    {
+                        throw reader.CreateException("Numeric value out of range: " + builder);
+                    }
+
+                    return result;
                 }
                 catch (OverflowException)
                 {
diff --git a/csharp/src/Google.Protobuf/MessageParser.cs b/csharp/src/Google.Protobuf/MessageParser.cs
index 30a25a8..a10c908 100644
--- a/csharp/src/Google.Protobuf/MessageParser.cs
+++ b/csharp/src/Google.Protobuf/MessageParser.cs
@@ -187,14 +187,17 @@
         internal void MergeFrom(IMessage message, CodedInputStream codedInput)
         {
             bool originalDiscard = codedInput.DiscardUnknownFields;
+            ExtensionRegistry originalRegistry = codedInput.ExtensionRegistry;
             try
             {
                 codedInput.DiscardUnknownFields = DiscardUnknownFields;
+                codedInput.ExtensionRegistry = Extensions;
                 message.MergeFrom(codedInput);
             }
             finally
             {
                 codedInput.DiscardUnknownFields = originalDiscard;
+                codedInput.ExtensionRegistry = originalRegistry;
             }
         }
 
diff --git a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs
index 9fc3766..f6fa152 100644
--- a/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs
+++ b/csharp/src/Google.Protobuf/Reflection/CustomOptions.cs
@@ -34,6 +34,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Reflection;
 
@@ -63,6 +64,8 @@
     /// </remarks>
     public sealed class CustomOptions
     {
+        private const string UnreferencedCodeMessage = "CustomOptions is incompatible with trimming.";
+
         private static readonly object[] EmptyParameters = new object[0];
         private readonly IDictionary<int, IExtensionValue> values;
 
@@ -77,6 +80,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetBool(int field, out bool value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -85,6 +89,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -93,6 +98,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -102,6 +108,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetFixed32(int field, out uint value) => TryGetUInt32(field, out value);
 
         /// <summary>
@@ -111,6 +118,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetFixed64(int field, out ulong value) => TryGetUInt64(field, out value);
 
         /// <summary>
@@ -120,6 +128,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetSFixed32(int field, out int value) => TryGetInt32(field, out value);
 
         /// <summary>
@@ -129,6 +138,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetSFixed64(int field, out long value) => TryGetInt64(field, out value);
 
         /// <summary>
@@ -138,6 +148,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetSInt32(int field, out int value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -147,6 +158,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetSInt64(int field, out long value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -155,6 +167,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetUInt32(int field, out uint value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -163,6 +176,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetUInt64(int field, out ulong value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -171,6 +185,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetFloat(int field, out float value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -179,6 +194,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetDouble(int field, out double value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -187,6 +203,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetString(int field, out string value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -195,6 +212,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetBytes(int field, out ByteString value) => TryGetPrimitiveValue(field, out value);
 
         /// <summary>
@@ -203,6 +221,7 @@
         /// <param name="field">The field to fetch the value for.</param>
         /// <param name="value">The output variable to populate.</param>
         /// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         public bool TryGetMessage<T>(int field, out T value) where T : class, IMessage, new()
         {
             if (values == null)
@@ -240,6 +259,7 @@
             return false;
         }
 
+        [RequiresUnreferencedCode(UnreferencedCodeMessage)]
         private bool TryGetPrimitiveValue<T>(int field, out T value)
         {
             if (values == null)
diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
index 5cae6ac..1a9fade 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/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
index f7e8b5b..3f2e1c4 100644
--- a/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/EnumDescriptor.cs
@@ -69,6 +69,14 @@
         internal EnumDescriptorProto Proto { get { return proto; } }
 
         /// <summary>
+        /// Returns a clone of the underlying <see cref="EnumDescriptorProto"/> describing this enum.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this enum descriptor.</returns>
+        public EnumDescriptorProto ToProto() => Proto.Clone();
+
+        /// <summary>
         /// The brief name of the descriptor's target.
         /// </summary>
         public override string Name { get { return proto.Name; } }
diff --git a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
index 05097bd..50b26a4 100644
--- a/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/EnumValueDescriptor.cs
@@ -56,6 +56,14 @@
         internal EnumValueDescriptorProto Proto { get { return proto; } }
 
         /// <summary>
+        /// Returns a clone of the underlying <see cref="EnumValueDescriptorProto"/> describing this enum value.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this enum value descriptor.</returns>
+        public EnumValueDescriptorProto ToProto() => Proto.Clone();
+
+        /// <summary>
         /// Returns the name of the enum value described by this object.
         /// </summary>
         public override string Name { get { return proto.Name; } }
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
index 7324e3d..84ad49d 100644
--- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -45,7 +45,6 @@
         private MessageDescriptor extendeeType;
         private MessageDescriptor messageType;
         private FieldType fieldType;
-        private readonly string propertyName; // Annoyingly, needed in Crosslink.
         private IFieldAccessor accessor;
 
         /// <summary>
@@ -71,6 +70,11 @@
         public string JsonName { get; }
 
         /// <summary>
+        /// The name of the property in the <c>ContainingType.ClrType</c> class.
+        /// </summary>
+        public string PropertyName { get; }
+
+        /// <summary>
         /// Indicates whether this field supports presence, either implicitly (e.g. due to it being a message
         /// type field) or explicitly via Has/Clear members. If this returns true, it is safe to call
         /// <see cref="IFieldAccessor.Clear(IMessage)"/> and <see cref="IFieldAccessor.HasValue(IMessage)"/>
@@ -88,6 +92,14 @@
         internal FieldDescriptorProto Proto { get; }
 
         /// <summary>
+        /// Returns a clone of the underlying <see cref="FieldDescriptorProto"/> describing this field.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this field descriptor.</returns>
+        public FieldDescriptorProto ToProto() => Proto.Clone();
+
+        /// <summary>
         /// An extension identifier for this field, or <c>null</c> if this field isn't an extension.
         /// </summary>
         public Extension Extension { get; }
@@ -123,7 +135,7 @@
             // for later.
             // We could trust the generated code and check whether the type of the property is
             // a MapField, but that feels a tad nasty.
-            this.propertyName = propertyName;
+            PropertyName = propertyName;
             Extension = extension;
             JsonName =  Proto.JsonName == "" ? JsonFormatter.ToJsonName(Proto.Name) : Proto.JsonName;
         }
@@ -235,7 +247,8 @@
                 }
                 else
                 {
-                    return !Proto.Options.HasPacked || Proto.Options.Packed;
+                    // Packed by default with proto3
+                    return Proto.Options == null || !Proto.Options.HasPacked || Proto.Options.Packed;
                 }
             }
         }
@@ -436,19 +449,19 @@
             // If we're given no property name, that's because we really don't want an accessor.
             // This could be because it's a map message, or it could be that we're loading a FileDescriptor dynamically.
             // TODO: Support dynamic messages.
-            if (propertyName == null)
+            if (PropertyName == null)
             {
                 return null;
             }
 
-            var property = ContainingType.ClrType.GetProperty(propertyName);
+            var property = ContainingType.ClrType.GetProperty(PropertyName);
             if (property == null)
             {
-                throw new DescriptorValidationException(this, $"Property {propertyName} not found in {ContainingType.ClrType}");
+                throw new DescriptorValidationException(this, $"Property {PropertyName} not found in {ContainingType.ClrType}");
             }
             return IsMap ? new MapFieldAccessor(property, this)
                 : IsRepeated ? new RepeatedFieldAccessor(property, this)
-                : (IFieldAccessor) new SingleFieldAccessor(property, this);
+                : (IFieldAccessor) new SingleFieldAccessor(ContainingType.ClrType, property, this);
         }
     }
 }
diff --git a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
index 724bb3a..d7701da 100644
--- a/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FileDescriptor.cs
@@ -250,6 +250,14 @@
         internal FileDescriptorProto Proto { get; }
 
         /// <summary>
+        /// Returns a clone of the underlying <see cref="FileDescriptorProto"/> describing this file.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this file descriptor.</returns>
+        public FileDescriptorProto ToProto() => Proto.Clone();
+
+        /// <summary>
         /// The syntax of the file
         /// </summary>
         public Syntax Syntax { get; }
diff --git a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
index 479e177..d0a495b 100644
--- a/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
+++ b/csharp/src/Google.Protobuf/Reflection/GeneratedClrTypeInfo.cs
@@ -30,6 +30,7 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endregion
 using System;
+using System.Diagnostics.CodeAnalysis;
 
 namespace Google.Protobuf.Reflection
 {
@@ -43,10 +44,19 @@
         private static readonly string[] EmptyNames = new string[0];
         private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
         private static readonly Extension[] EmptyExtensions = new Extension[0];
+        internal const DynamicallyAccessedMemberTypes MessageAccessibility =
+            // Creating types
+            DynamicallyAccessedMemberTypes.PublicConstructors |
+            // Getting and setting properties
+            DynamicallyAccessedMemberTypes.PublicProperties |
+            DynamicallyAccessedMemberTypes.NonPublicProperties |
+            // Calling presence methods
+            DynamicallyAccessedMemberTypes.PublicMethods;
 
         /// <summary>
         /// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
         /// </summary>
+        [DynamicallyAccessedMembers(MessageAccessibility)]
         public Type ClrType { get; private set; }
 
         /// <summary>
@@ -88,7 +98,11 @@
         /// Each array parameter may be null, to indicate a lack of values.
         /// The parameter order is designed to make it feasible to format the generated code readably.
         /// </summary>
-        public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, Extension[] extensions, GeneratedClrTypeInfo[] nestedTypes)
+        public GeneratedClrTypeInfo(
+            // Preserve all public members on message types when trimming is enabled.
+            // This ensures that members used by reflection, e.g. JSON serialization, are preserved.
+            [DynamicallyAccessedMembers(MessageAccessibility)]
+            Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, Extension[] extensions, GeneratedClrTypeInfo[] nestedTypes)
         {
             NestedTypes = nestedTypes ?? EmptyCodeInfo;
             NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
@@ -104,7 +118,11 @@
         /// Each array parameter may be null, to indicate a lack of values.
         /// The parameter order is designed to make it feasible to format the generated code readably.
         /// </summary>
-        public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
+        public GeneratedClrTypeInfo(
+            // Preserve all public members on message types when trimming is enabled.
+            // This ensures that members used by reflection, e.g. JSON serialization, are preserved.
+            [DynamicallyAccessedMembers(MessageAccessibility)]
+            Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
             : this(clrType, parser, propertyNames, oneofNames, nestedEnums, null, nestedTypes)
         {
         }
diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
index 7b5ab2f..40a6ff8 100644
--- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs
@@ -33,6 +33,7 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Reflection;
 #if NET35
@@ -150,6 +151,14 @@
 
         internal DescriptorProto Proto { get; }
 
+        /// <summary>
+        /// Returns a clone of the underlying <see cref="DescriptorProto"/> describing this message.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this message descriptor.</returns>
+        public DescriptorProto ToProto() => Proto.Clone();
+
         internal bool IsExtensionsInitialized(IMessage message)
         {
             if (Proto.ExtensionRange.Count == 0)
@@ -182,6 +191,7 @@
         /// a wrapper type, and handle the result appropriately.
         /// </para>
         /// </remarks>
+        [DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]
         public Type ClrType { get; }
 
         /// <summary>
diff --git a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
index 8e15037..f5ecf2e 100644
--- a/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs
@@ -115,6 +115,14 @@
         internal MethodDescriptorProto Proto { get { return proto; } }
 
         /// <summary>
+        /// Returns a clone of the underlying <see cref="MethodDescriptorProto"/> describing this method.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this method descriptor.</returns>
+        public MethodDescriptorProto ToProto() => Proto.Clone();
+
+        /// <summary>
         /// The brief name of the descriptor's target.
         /// </summary>
         public override string Name { get { return proto.Name; } }
diff --git a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
index b41d520..ae29ded 100644
--- a/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs
@@ -45,7 +45,6 @@
     /// </summary>
     public sealed class OneofDescriptor : DescriptorBase
     {
-        private readonly OneofDescriptorProto proto;
         private MessageDescriptor containingType;
         private IList<FieldDescriptor> fields;
         private readonly OneofAccessor accessor;
@@ -53,7 +52,7 @@
         internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string clrName)
             : base(file, file.ComputeFullName(parent, proto.Name), index)
         {
-            this.proto = proto;
+            this.Proto = proto;
             containingType = parent;
             file.DescriptorPool.AddSymbol(this);
 
@@ -68,7 +67,18 @@
         /// <summary>
         /// The brief name of the descriptor's target.
         /// </summary>
-        public override string Name { get { return proto.Name; } }
+        public override string Name => Proto.Name;
+
+        // Visible for testing
+        internal OneofDescriptorProto Proto { get; }
+
+        /// <summary>
+        /// Returns a clone of the underlying <see cref="OneofDescriptorProto"/> describing this oneof.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this oneof descriptor.</returns>
+        public OneofDescriptorProto ToProto() => Proto.Clone();
 
         /// <summary>
         /// Gets the message type containing this oneof.
@@ -118,7 +128,7 @@
         /// The (possibly empty) set of custom options for this oneof.
         /// </summary>
         [Obsolete("CustomOptions are obsolete. Use the GetOptions method.")]
-        public CustomOptions CustomOptions => new CustomOptions(proto.Options?._extensions?.ValuesByNumber);
+        public CustomOptions CustomOptions => new CustomOptions(Proto.Options?._extensions?.ValuesByNumber);
 
         /// <summary>
         /// The <c>OneofOptions</c>, defined in <c>descriptor.proto</c>.
@@ -126,7 +136,7 @@
         /// Custom options can be retrieved as extensions of the returned message.
         /// NOTE: A defensive copy is created each time this property is retrieved.
         /// </summary>
-        public OneofOptions GetOptions() => proto.Options?.Clone();
+        public OneofOptions GetOptions() => Proto.Options?.Clone();
 
         /// <summary>
         /// Gets a single value oneof option for this descriptor
@@ -134,7 +144,7 @@
         [Obsolete("GetOption is obsolete. Use the GetOptions() method.")]
         public T GetOption<T>(Extension<OneofOptions, T> extension)
         {
-            var value = proto.Options.GetExtension(extension);
+            var value = Proto.Options.GetExtension(extension);
             return value is IDeepCloneable<T> ? (value as IDeepCloneable<T>).Clone() : value;
         }
 
@@ -144,7 +154,7 @@
         [Obsolete("GetOption is obsolete. Use the GetOptions() method.")]
         public RepeatedField<T> GetOption<T>(RepeatedExtension<OneofOptions, T> extension)
         {
-            return proto.Options.GetExtension(extension).Clone();
+            return Proto.Options.GetExtension(extension).Clone();
         }
 
         internal void CrossLink()
diff --git a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
index fd1ad4e..73efcc2 100644
--- a/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
+++ b/csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs
@@ -32,6 +32,7 @@
 
 using Google.Protobuf.Compatibility;
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
 
 namespace Google.Protobuf.Reflection
@@ -115,13 +116,15 @@
         internal static Func<IMessage, bool> CreateFuncIMessageBool(MethodInfo method) =>
             GetReflectionHelper(method.DeclaringType, method.ReturnType).CreateFuncIMessageBool(method);
 
-        internal static Func<IMessage, bool> CreateIsInitializedCaller(Type msg) =>
+        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
+        internal static Func<IMessage, bool> CreateIsInitializedCaller([DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]Type msg) =>
             ((IExtensionSetReflector)Activator.CreateInstance(typeof(ExtensionSetReflector<>).MakeGenericType(msg))).CreateIsInitializedCaller();
 
         /// <summary>
         /// Creates a delegate which will execute the given method after casting the first argument to
         /// the type that declares the method, and the second argument to the first parameter type of the method.
         /// </summary>
+        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
         internal static IExtensionReflectionHelper CreateExtensionHelper(Extension extension) =>
             (IExtensionReflectionHelper)Activator.CreateInstance(typeof(ExtensionReflectionHelper<,>).MakeGenericType(extension.TargetType, extension.GetType().GenericTypeArguments[1]), extension);
 
@@ -131,6 +134,7 @@
         /// they can be garbage collected. We could cache them by type if that proves to be important, but creating
         /// an object is pretty cheap.
         /// </summary>
+        [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Type parameter members are preserved with DynamicallyAccessedMembers on GeneratedClrTypeInfo.ctor clrType parameter.")]
         private static IReflectionHelper GetReflectionHelper(Type t1, Type t2) =>
             (IReflectionHelper) Activator.CreateInstance(typeof(ReflectionHelper<,>).MakeGenericType(t1, t2));
 
@@ -308,16 +312,14 @@
             }
         }
 
-        private class ExtensionSetReflector<T1> : IExtensionSetReflector where T1 : IExtendableMessage<T1>
+        private class ExtensionSetReflector<
+            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
+            T1> : IExtensionSetReflector where T1 : IExtendableMessage<T1>
         {
             public Func<IMessage, bool> CreateIsInitializedCaller()
             {
                 var prop = typeof(T1).GetTypeInfo().GetDeclaredProperty("_Extensions");
-#if NET35
-                var getFunc = (Func<T1, ExtensionSet<T1>>)prop.GetGetMethod(true).CreateDelegate(typeof(Func<T1, ExtensionSet<T1>>));
-#else
                 var getFunc = (Func<T1, ExtensionSet<T1>>)prop.GetMethod.CreateDelegate(typeof(Func<T1, ExtensionSet<T1>>));
-#endif
                 var initializedFunc = (Func<ExtensionSet<T1>, bool>)
                     typeof(ExtensionSet<T1>)
                         .GetTypeInfo()
diff --git a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
index dab348b..944ea11 100644
--- a/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/ServiceDescriptor.cs
@@ -73,6 +73,14 @@
 
         internal ServiceDescriptorProto Proto { get { return proto; } }
 
+        /// <summary>
+        /// Returns a clone of the underlying <see cref="ServiceDescriptorProto"/> describing this service.
+        /// Note that a copy is taken every time this method is called, so clients using it frequently
+        /// (and not modifying it) may want to cache the returned value.
+        /// </summary>
+        /// <returns>A protobuf representation of this service descriptor.</returns>
+        public ServiceDescriptorProto ToProto() => Proto.Clone();
+
         /// <value>
         /// An unmodifiable list of methods in this service.
         /// </value>
diff --git a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
index 07d84d7..ac35e72 100644
--- a/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/SingleFieldAccessor.cs
@@ -31,6 +31,8 @@
 #endregion
 
 using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
 using Google.Protobuf.Compatibility;
 
@@ -50,7 +52,9 @@
         private readonly Action<IMessage> clearDelegate;
         private readonly Func<IMessage, bool> hasDelegate;
 
-        internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
+        internal SingleFieldAccessor(
+            [DynamicallyAccessedMembers(GeneratedClrTypeInfo.MessageAccessibility)]
+            Type messageType, PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
         {
             if (!property.CanWrite)
             {
@@ -87,13 +91,13 @@
             // Primitive fields always support presence in proto2, and support presence in proto3 for optional fields.
             else if (descriptor.File.Syntax == Syntax.Proto2 || descriptor.Proto.Proto3Optional)
             {
-                MethodInfo hasMethod = property.DeclaringType.GetRuntimeProperty("Has" + property.Name).GetMethod;
+                MethodInfo hasMethod = messageType.GetRuntimeProperty("Has" + property.Name).GetMethod;
                 if (hasMethod == null)
                 {
                     throw new ArgumentException("Not all required properties/methods are available");
                 }
                 hasDelegate = ReflectionUtil.CreateFuncIMessageBool(hasMethod);
-                MethodInfo clearMethod = property.DeclaringType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
+                MethodInfo clearMethod = messageType.GetRuntimeMethod("Clear" + property.Name, ReflectionUtil.EmptyTypes);
                 if (clearMethod == null)
                 {
                     throw new ArgumentException("Not all required properties/methods are available");
@@ -107,16 +111,48 @@
                 hasDelegate = message => { throw new InvalidOperationException("Presence is not implemented for this field"); };
 
                 // While presence isn't supported, clearing still is; it's just setting to a default value.
-                var clrType = property.PropertyType;
-
-                object defaultValue =
-                    clrType == typeof(string) ? ""
-                    : clrType == typeof(ByteString) ? ByteString.Empty
-                    : Activator.CreateInstance(clrType);
+                object defaultValue = GetDefaultValue(descriptor);
                 clearDelegate = message => SetValue(message, defaultValue);
             }
         }
 
+        private static object GetDefaultValue(FieldDescriptor descriptor)
+        {
+            switch (descriptor.FieldType)
+            {
+                case FieldType.Bool:
+                    return false;
+                case FieldType.Bytes:
+                    return ByteString.Empty;
+                case FieldType.String:
+                    return "";
+                case FieldType.Double:
+                    return 0.0;
+                case FieldType.SInt32:
+                case FieldType.Int32:
+                case FieldType.SFixed32:
+                case FieldType.Enum:
+                    return 0;
+                case FieldType.Fixed32:
+                case FieldType.UInt32:
+                    return (uint)0;
+                case FieldType.Fixed64:
+                case FieldType.UInt64:
+                    return 0UL;
+                case FieldType.SFixed64:
+                case FieldType.Int64:
+                case FieldType.SInt64:
+                    return 0L;
+                case FieldType.Float:
+                    return 0f;
+                case FieldType.Message:
+                case FieldType.Group: // Never expect to get this, but...
+                    return null;
+                default:
+                    throw new ArgumentException("Invalid field type");
+            }
+        }
+
         public override void Clear(IMessage message) => clearDelegate(message);
         public override bool HasValue(IMessage message) => hasDelegate(message);
         public override void SetValue(IMessage message, object value) => setValueDelegate(message, value);
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
index 91d2ee9..58a33cb 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
@@ -33,6 +33,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using Google.Protobuf.Reflection;
@@ -115,7 +116,7 @@
         /// Parses from a string to a FieldMask and validates all field paths.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static FieldMask FromString<T>(string value) where T : IMessage
+        public static FieldMask FromString<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(string value) where T : IMessage
         {
             return FromStringEnumerable<T>(new List<string>(value.Split(FIELD_PATH_SEPARATOR)));
         }
@@ -124,7 +125,7 @@
         /// Constructs a FieldMask for a list of field paths in a certain type.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static FieldMask FromStringEnumerable<T>(IEnumerable<string> paths) where T : IMessage
+        public static FieldMask FromStringEnumerable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(IEnumerable<string> paths) where T : IMessage
         {
             var mask = new FieldMask();
             foreach (var path in paths)
@@ -151,7 +152,7 @@
         /// Constructs a FieldMask from the passed field numbers.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static FieldMask FromFieldNumbers<T>(params int[] fieldNumbers) where T : IMessage
+        public static FieldMask FromFieldNumbers<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(params int[] fieldNumbers) where T : IMessage
         {
             return FromFieldNumbers<T>((IEnumerable<int>)fieldNumbers);
         }
@@ -160,7 +161,7 @@
         /// Constructs a FieldMask from the passed field numbers.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static FieldMask FromFieldNumbers<T>(IEnumerable<int> fieldNumbers) where T : IMessage
+        public static FieldMask FromFieldNumbers<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(IEnumerable<int> fieldNumbers) where T : IMessage
         {
             var descriptor = Activator.CreateInstance<T>().Descriptor;
 
@@ -208,7 +209,7 @@
         /// Checks whether paths in a given fields mask are valid.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static bool IsValid<T>(FieldMask fieldMask) where T : IMessage
+        public static bool IsValid<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(FieldMask fieldMask) where T : IMessage
         {
             var descriptor = Activator.CreateInstance<T>().Descriptor;
 
@@ -235,7 +236,7 @@
         /// Checks whether a given field path is valid.
         /// </summary>
         /// <typeparam name="T">The type to validate the field paths against.</typeparam>
-        public static bool IsValid<T>(string path) where T : IMessage
+        public static bool IsValid<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]T>(string path) where T : IMessage
         {
             var descriptor = Activator.CreateInstance<T>().Descriptor;
 
diff --git a/docs/options.md b/docs/options.md
index 159951a..e4ca729 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -292,3 +292,11 @@
 1. Protoc-gen-jsonschema
    * Website: https://github.com/chrusty/protoc-gen-jsonschema
    * Extension: 1125-1129
+
+1. Protoc-gen-checker
+   * Website: https://github.com/Intrinsec/protoc-gen-checker
+   * Extension: 1130-1139
+
+1. Protoc-gen-go-svc
+   * Website: https://github.com/dane/protoc-gen-go-svc
+   * Extension: 1140
diff --git a/docs/third_party.md b/docs/third_party.md
index 06b31b1..1bf36a8 100644
--- a/docs/third_party.md
+++ b/docs/third_party.md
@@ -2,31 +2,32 @@
 
 This page lists code related to Protocol Buffers which is developed and maintained by third parties.  You may find this code useful, but note that **these projects are not affiliated with or endorsed by Google (unless explicitly marked)**; try them at your own risk.  Also note that many projects here are in the early stages of development and not production-ready.
 
-If you have a project that should be listed here, please [send us a pull request](https://github.com/google/protobuf/pulls) to update this page.
+If you have a project that should be listed here, please
+[send us a pull request](https://github.com/protocolbuffers/protobuf/pulls) to update this page.
 
 ## Programming Languages
 
 These are projects we know about implementing Protocol Buffers for other programming languages:
-* Action Script: http://code.google.com/p/protobuf-actionscript3/
+* Action Script: https://code.google.com/p/protobuf-actionscript3/
 * Action Script: https://code.google.com/p/protoc-gen-as3/
 * Action Script: https://github.com/matrix3d/JProtoc
 * Action Script: https://github.com/zhongfq/protobuf-as3/
 * Ada: https://github.com/reznikmm/protobuf
 * C: https://github.com/protobuf-c/protobuf-c
-* C: http://koti.kapsi.fi/jpa/nanopb/
+* C: https://koti.kapsi.fi/jpa/nanopb/
 * C: https://github.com/cloudwu/pbc/
 * C: https://github.com/haberman/upb/wiki
 * C: https://github.com/squidfunk/protobluff
 * C: https://github.com/eerimoq/pbtools
-* C++: https://github.com/google/protobuf (Google-official implementation)
+* C++: https://github.com/protocolbuffers/protobuf (Google-official implementation)
 * C++: https://EmbeddedProto.com
 * C/C++: http://spbc.sf.net/
-* C#: http://code.google.com/p/protobuf-csharp-port
+* C#: https://code.google.com/p/protobuf-csharp-port
 * C#: https://silentorbit.com/protobuf/
-* C#/.NET/WCF/VB: http://code.google.com/p/protobuf-net/
+* C#/.NET/WCF/VB: https://code.google.com/p/protobuf-net/
 * Clojure: http://github.com/ninjudd/clojure-protobuf
 * Clojure: https://github.com/clojusc/protobuf
-* Clojure: https://protojure.github.io
+* Clojure: https://protojure.readthedocs.io
 * Common Lisp: http://github.com/brown/protobuf
 * Common Lisp: http://github.com/qitab/cl-protobuf
 * D: https://github.com/dcarp/protobuf-d
@@ -48,21 +49,20 @@
 * Go: https://github.com/akunspy/gopbuf
 * Go: https://github.com/gogo/protobuf
 * GopherJS: https://github.com/johanbrandhorst/protobuf
-* Haskell: http://hackage.haskell.org/package/hprotoc
+* Haskell: https://hackage.haskell.org/package/hprotoc
 * Haskell: https://github.com/google/proto-lens (Google-unofficial implementation)
 * Haskell: https://github.com/awakesecurity/proto3-suite (code generator) https://github.com/awakesecurity/proto3-wire (binary serializer/deserializer)
 * Haxe: https://github.com/Atry/protoc-gen-haxe
-* Java: https://github.com/google/protobuf (Google-official implementation)
+* Java: https://github.com/protocolbuffers/protobuf (Google-official implementation)
 * Java/Android: https://github.com/square/wire
 * Java: https://github.com/HebiRobotics/QuickBuffers/
-* Java ME: http://code.google.com/p/protobuf-javame/
+* Java ME: https://code.google.com/p/protobuf-javame/
 * Java ME: http://swingme.sourceforge.net/encode.shtml
-* Java ME: http://code.google.com/p/protobuf-j2me/
-* Javascript: http://code.google.com/p/protobuf-js/
+* Javascript: https://code.google.com/p/protobuf-js/
 * Javascript: http://github.com/sirikata/protojs
 * Javascript: https://github.com/dcodeIO/ProtoBuf.js
-* Javascript: http://code.google.com/p/protobuf-for-node/
-* Javascript: http://code.google.com/p/protostuff/
+* Javascript: https://code.google.com/p/protobuf-for-node/
+* Javascript: https://code.google.com/p/protostuff/
 * Javascript: https://github.com/seishun/node-protoc-plugin (Node.js port of plugin.h)
 * Javascript: https://github.com/seishun/node-protoc-gen-javascript (Node.js port of the Google-official implementation)
 * Javascript: https://github.com/ButterCam/sisyphus-js
@@ -71,43 +71,45 @@
 * Kotlin: https://github.com/Kotlin/kotlinx.serialization
 * Kotlin: https://github.com/ButterCam/sisyphus
 * Kotlin: https://github.com/open-toast/protokt
-* Lua: http://code.google.com/p/protoc-gen-lua/
+* Lua: https://code.google.com/p/protoc-gen-lua/
 * Lua: http://github.com/indygreg/lua-protobuf
 * Lua: https://github.com/Neopallium/lua-pb
-* Matlab: http://code.google.com/p/protobuf-matlab/
-* Mercury: http://code.google.com/p/protobuf-mercury/
-* Objective C: http://code.google.com/p/protobuf-objc/
+* Matlab: https://code.google.com/p/protobuf-matlab/
+* Mercury: https://code.google.com/p/protobuf-mercury/
+* Objective C: https://code.google.com/p/protobuf-objc/
 * Objective C: https://github.com/alexeyxo/protobuf-objc
 * OCaml: http://piqi.org/
 * Perl: http://groups.google.com/group/protobuf-perl
-* Perl: http://search.cpan.org/perldoc?Google::ProtocolBuffers
+* Perl: https://metacpan.org/pod/Google::ProtocolBuffers
 * Perl: https://metacpan.org/pod/Google::ProtocolBuffers::Dynamic
-* Perl/XS: http://code.google.com/p/protobuf-perlxs/
-* PHP: http://code.google.com/p/pb4php/
+* Perl/XS: https://code.google.com/p/protobuf-perlxs/
+* PHP: https://code.google.com/p/pb4php/
 * PHP: https://github.com/allegro/php-protobuf/
 * PHP: https://github.com/chobie/php-protocolbuffers
-* PHP: http://drslump.github.com/Protobuf-PHP
 * Prolog: http://www.swi-prolog.org/pldoc/package/protobufs.html
 * Purescript: https://github.com/xc-jp/purescript-protobuf
-* Python: https://github.com/google/protobuf (Google-official implementation)
+* Python: https://github.com/protocolbuffers/protobuf (Google-official implementation)
 * Python: https://github.com/eigenein/protobuf
 * Python: https://github.com/danielgtaylor/python-betterproto
 * R: http://cran.r-project.org/package=RProtoBuf
-* Ruby: http://code.google.com/p/ruby-protobuf/
+* Ruby: https://code.google.com/p/ruby-protobuf/
 * Ruby: http://github.com/mozy/ruby-protocol-buffers
 * Ruby: https://github.com/bmizerany/beefcake/tree/master/lib/beefcake
 * Ruby: https://github.com/localshred/protobuf
+* Rust: https://github.com/tokio-rs/prost
 * Rust: https://github.com/stepancheg/rust-protobuf/
+* Rust: https://github.com/tafia/quick-protobuf
 * Scala: http://github.com/jeffplaisance/scala-protobuf
-* Scala: http://code.google.com/p/protobuf-scala
+* Scala: https://code.google.com/p/protobuf-scala
 * Scala: https://github.com/SandroGrzicic/ScalaBuff
 * Scala: https://scalapb.github.io
 * Solidity: https://github.com/celer-network/pb3-gen-sol
 * Swift: https://github.com/alexeyxo/protobuf-swift
 * Swift: https://github.com/apple/swift-protobuf/
 * Typescript: https://github.com/thesayyn/protoc-gen-ts
+* Typescript: https://github.com/pbkit/pbkit
 * Vala: https://launchpad.net/protobuf-vala
-* Visual Basic: http://code.google.com/p/protobuf-net/
+* Visual Basic: https://code.google.com/p/protobuf-net/
 
 ## RPC Implementations
 
@@ -128,6 +130,7 @@
 * https://github.com/awakesecurity/gRPC-haskell (Haskell)
 * https://github.com/Yeolar/raster (C++)
 * https://github.com/jnordberg/wsrpc (JavaScript Node.js/Browser)
+* https://github.com/pbkit/npm-packages/blob/main/frpc-test/src/index.spec.ts (TypeScript Node.js/Browser)
 * https://github.com/ppissias/xsrpcj (Java)
 * https://github.com/twitchtv/twirp (Multiple languages)
 
@@ -157,24 +160,23 @@
     * [rules_closure](https://github.com/bazelbuild/rules_closure) `js-closure`
     * [rules_go](https://github.com/bazelbuild/rules_go) `go`
     * [rules_protobuf](https://github.com/pubref/rules_protobuf) `java` `c++` `c#` `go` `js-closure` `js-node` `python` `ruby`
-* [NetBeans IDE plugin](http://code.google.com/p/protobuf-netbeans-plugin/)
-* [Wireshark/Ethereal packet sniffer plugin](http://code.google.com/p/protobuf-wireshark/)
-* [Alternate encodings (JSON, XML, HTML) for Java protobufs](http://code.google.com/p/protobuf-java-format/)
+* [NetBeans IDE plugin](https://code.google.com/p/protobuf-netbeans-plugin/)
+* [Wireshark/Ethereal packet sniffer plugin](https://code.google.com/p/protobuf-wireshark/)
+* [Alternate encodings (JSON, XML, HTML) for Java protobufs](https://code.google.com/p/protobuf-java-format/)
 * [Another JSON encoder/decoder for Java](https://github.com/sijuv/protobuf-codec)
-* [Editor for serialized protobufs](http://code.google.com/p/protobufeditor/)
+* [Editor for serialized protobufs](https://code.google.com/p/protobufeditor/)
 * [IntelliJ IDEA plugin](http://github.com/jvolkman/intellij-protobuf-editor)
 * [IntelliJ Protobuf Plugin](https://github.com/devkanro/intellij-protobuf-plugin)
 * [TextMate syntax highlighting](http://github.com/michaeledgar/protobuf-tmbundle)
-* [Oracle PL SQL plugin](http://code.google.com/p/protocol-buffer-plsql/)
-* [Eclipse editor for protobuf (from Google)](http://code.google.com/p/protobuf-dt/)
+* [Oracle PL SQL plugin](https://code.google.com/p/protocol-buffer-plsql/)
+* [Eclipse editor for protobuf (from Google)](https://code.google.com/p/protobuf-dt/)
 * [C++ Builder compatible protobuf](https://github.com/saadware/protobuf-cppbuilder)
 * Maven Protobuf Compiler Plugin
     * By xolstice.org ([Documentation](https://www.xolstice.org/protobuf-maven-plugin/)) ([Source](https://github.com/xolstice/protobuf-maven-plugin/)) [![Maven Central](https://img.shields.io/maven-central/v/org.xolstice.maven.plugins/protobuf-maven-plugin.svg)](https://repo1.maven.org/maven2/org/xolstice/maven/plugins/protobuf-maven-plugin/)
-    * http://igor-petruk.github.com/protobuf-maven-plugin/
-    * http://code.google.com/p/maven-protoc-plugin/
+    * https://code.google.com/p/maven-protoc-plugin/
     * https://github.com/os72/protoc-jar-maven-plugin
 * [Documentation generator plugin (Markdown/HTML/DocBook/...)](https://github.com/pseudomuto/protoc-gen-doc)
-* [DocBook generator for .proto files](http://code.google.com/p/protoc-gen-docbook/)
+* [DocBook generator for .proto files](https://code.google.com/p/protoc-gen-docbook/)
 * [Protobuf for nginx module](https://github.com/dbcode/protobuf-nginx/)
 * [RSpec matchers and Cucumber step defs for testing Protocol Buffers](https://github.com/connamara/protobuf_spec)
 * [Sbt plugin for Protocol Buffers](https://github.com/Atry/sbt-cppp)
diff --git a/editors/protobuf-mode.el b/editors/protobuf-mode.el
index aa31bd0..bbb82b7 100644
--- a/editors/protobuf-mode.el
+++ b/editors/protobuf-mode.el
@@ -193,7 +193,7 @@
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.proto\\'" . protobuf-mode))
 
 ;;;###autoload
-(defun protobuf-mode ()
+(define-derived-mode protobuf-mode prog-mode "Protobuf"
   "Major mode for editing Protocol Buffers description language.
 
 The hook `c-mode-common-hook' is run with no argument at mode
diff --git a/examples/Makefile b/examples/Makefile
index 8ed2492..1c7ec8d 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -16,7 +16,7 @@
 	rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
 	rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
 	rm -f *.pyc
-	rm -f protoc_middleman_go tutorial/*.pb.go add_person_go list_people_go go.mod go.sum
+	rm -f go/tutorialpb/*.pb.go add_person_go list_people_go
 	rm -f protoc_middleman_dart dart_tutorial/*.pb*.dart
 	rmdir dart_tutorial 2>/dev/null || true
 	rmdir tutorial 2>/dev/null || true
@@ -28,10 +28,9 @@
 	protoc $$PROTO_PATH --cpp_out=. --java_out=. --python_out=. addressbook.proto
 	@touch protoc_middleman
 
-protoc_middleman_go: addressbook.proto
-	mkdir -p tutorial # make directory for go package
-	protoc $$PROTO_PATH --go_out=tutorial addressbook.proto
-	@touch protoc_middleman_go
+go/tutorialpb/addressbook.pb.go: addressbook.proto
+	mkdir -p go/tutorialpb # make directory for go package
+	protoc $$PROTO_PATH --go_opt=paths=source_relative --go_out=go/tutorialpb addressbook.proto
 
 protoc_middleman_dart: addressbook.proto
 	mkdir -p dart_tutorial # make directory for the dart package
@@ -51,21 +50,17 @@
 
 list_people_dart: list_people.dart protoc_middleman_dart
 
-go_mod:
-	go mod init github.com/protocolbuffers/protobuf/examples
-	go mod tidy
+add_person_go: go/cmd/add_person/add_person.go go/tutorialpb/addressbook.pb.go
+	cd go && go build -o ../add_person_go ./cmd/add_person
 
-add_person_go: add_person.go protoc_middleman_go go_mod
-	go build -o add_person_go add_person.go
+add_person_gotest: go/tutorialpb/addressbook.pb.go
+	cd go && go test ./cmd/add_person
 
-add_person_gotest: add_person_test.go add_person_go go_mod
-	go test add_person.go add_person_test.go
+list_people_go: go/cmd/list_people/list_people.go go/tutorialpb/addressbook.pb.go
+	cd go && go build -o ../list_people_go ./cmd/list_people
 
-list_people_go: list_people.go protoc_middleman_go go_mod
-	go build -o list_people_go list_people.go
-
-list_people_gotest: list_people.go list_people_go go_mod
-	go test list_people.go list_people_test.go
+list_people_gotest: go/tutorialpb/addressbook.pb.go
+	cd go && go test ./cmd/list_people
 
 javac_middleman: AddPerson.java ListPeople.java protoc_middleman
 	javac -cp $$CLASSPATH AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
diff --git a/examples/README.md b/examples/README.md
index 4bf7c17..a99883e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -91,22 +91,18 @@
 
 ### Go
 
-The Go example requires a plugin to the protocol buffer compiler, so it is not
-build with all the other examples.  See:
+Follow instructions in [../README.md](../README.md) to install protoc. Then
+install the Go protoc plugin (protoc-gen-go):
 
-    https://github.com/golang/protobuf
+    $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
 
-for more information about Go protocol buffer support.
+The "go install" command will install protoc-gen-go into the GOBIN
+directory.  You can set the $GOBIN environment variable before
+running "go install" to change the install location.  Make sure the
+install directory is in your shell $PATH.
 
-First, install the Protocol Buffers compiler (protoc).
-
-Then, install the Go Protocol Buffers plugin ($GOPATH/bin must be in your $PATH
-for protoc to find it):
-
-    go get github.com/golang/protobuf/protoc-gen-go
-
-Build the Go samples in this directory with "make go".  This creates the
-following executable files in the current directory:
+Build the Go samples with "make go".  This creates the following
+executable files in the current directory:
 
     add_person_go      list_people_go
 
diff --git a/examples/addressbook.proto b/examples/addressbook.proto
index 5bb3577..1bff4ad 100644
--- a/examples/addressbook.proto
+++ b/examples/addressbook.proto
@@ -24,7 +24,7 @@
 // [END csharp_declaration]
 
 // [START go_declaration]
-option go_package = "../tutorial";
+option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
 // [END go_declaration]
 
 // [START messages]
diff --git a/examples/add_person.go b/examples/go/cmd/add_person/add_person.go
similarity index 96%
rename from examples/add_person.go
rename to examples/go/cmd/add_person/add_person.go
index 7ffb0ab..5d2f21c 100644
--- a/examples/add_person.go
+++ b/examples/go/cmd/add_person/add_person.go
@@ -9,8 +9,8 @@
 	"os"
 	"strings"
 
-	"github.com/golang/protobuf/proto"
-	pb "github.com/protocolbuffers/protobuf/examples/tutorial"
+	pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
+	"google.golang.org/protobuf/proto"
 )
 
 func promptForAddress(r io.Reader) (*pb.Person, error) {
diff --git a/examples/add_person_test.go b/examples/go/cmd/add_person/add_person_test.go
similarity index 88%
rename from examples/add_person_test.go
rename to examples/go/cmd/add_person/add_person_test.go
index d35f10e..f10c355 100644
--- a/examples/add_person_test.go
+++ b/examples/go/cmd/add_person/add_person_test.go
@@ -4,8 +4,8 @@
 	"strings"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
-	pb "github.com/protocolbuffers/protobuf/examples/tutorial"
+	pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
+	"google.golang.org/protobuf/proto"
 )
 
 func TestPromptForAddressReturnsAddress(t *testing.T) {
@@ -51,7 +51,7 @@
 	}
 	for i := 0; i < phones; i++ {
 		if !proto.Equal(got.Phones[i], want[i]) {
-			t.Errorf("want phone %q, got %q", *want[i], *got.Phones[i])
+			t.Errorf("want phone %q, got %q", want[i], got.Phones[i])
 		}
 
 	}
diff --git a/examples/list_people.go b/examples/go/cmd/list_people/list_people.go
similarity index 91%
rename from examples/list_people.go
rename to examples/go/cmd/list_people/list_people.go
index 6c2c34a..5ca0dcf 100644
--- a/examples/list_people.go
+++ b/examples/go/cmd/list_people/list_people.go
@@ -7,8 +7,8 @@
 	"log"
 	"os"
 
-	"github.com/golang/protobuf/proto"
-	pb "github.com/protocolbuffers/protobuf/examples/tutorial"
+	pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
+	"google.golang.org/protobuf/proto"
 )
 
 func writePerson(w io.Writer, p *pb.Person) {
diff --git a/examples/list_people_test.go b/examples/go/cmd/list_people/list_people_test.go
similarity index 97%
rename from examples/list_people_test.go
rename to examples/go/cmd/list_people/list_people_test.go
index aceabd4..b116c16 100644
--- a/examples/list_people_test.go
+++ b/examples/go/cmd/list_people/list_people_test.go
@@ -5,7 +5,7 @@
 	"strings"
 	"testing"
 
-	pb "github.com/protocolbuffers/protobuf/examples/tutorial"
+	pb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
 )
 
 func TestWritePersonWritesPerson(t *testing.T) {
diff --git a/examples/go/go.mod b/examples/go/go.mod
new file mode 100644
index 0000000..ed43328
--- /dev/null
+++ b/examples/go/go.mod
@@ -0,0 +1,5 @@
+module github.com/protocolbuffers/protobuf/examples/go
+
+go 1.14
+
+require google.golang.org/protobuf v1.27.1
diff --git a/examples/go/go.sum b/examples/go/go.sum
new file mode 100644
index 0000000..9f8c064
--- /dev/null
+++ b/examples/go/go.sum
@@ -0,0 +1,6 @@
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
diff --git a/global.json b/global.json
index d29e29a..ade0252 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
 {
   "sdk": {
-    "version": "5.0.102",
+    "version": "6.0.100",
     "rollForward": "latestMinor"
   }
 }
diff --git a/java/BUILD b/java/BUILD
index e12d472..3e57ab6 100644
--- a/java/BUILD
+++ b/java/BUILD
@@ -2,6 +2,8 @@
     name = "tests",
     tests = [
         "//java/core:tests",
+        "//java/kotlin:tests",
+        "//java/kotlin-lite:tests",
         "//java/lite:tests",
         "//java/util:tests",
     ],
@@ -13,4 +15,4 @@
         "//java/core:release", # contains lite.
         "//java/util:release",
     ]
-)
\ No newline at end of file
+)
diff --git a/java/README.md b/java/README.md
index 849f9b0..0170b9d 100644
--- a/java/README.md
+++ b/java/README.md
@@ -23,7 +23,7 @@
 <dependency>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-java</artifactId>
-  <version>3.18.0</version>
+  <version>3.19.4</version>
 </dependency>
 ```
 
@@ -37,7 +37,7 @@
 <dependency>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-java-util</artifactId>
-  <version>3.18.0</version>
+  <version>3.19.4</version>
 </dependency>
 ```
 
@@ -45,7 +45,7 @@
 
 If you are using Gradle, add the following to your `build.gradle` file's dependencies:
 ```
-    implementation 'com.google.protobuf:protobuf-java:3.18.0'
+    implementation 'com.google.protobuf:protobuf-java:3.19.4'
 ```
 Again, be sure to check that the version number matches (or is newer than) the version number of protoc that you are using.
 
diff --git a/java/bom/pom.xml b/java/bom/pom.xml
index c4ec685..f12aa0b 100644
--- a/java/bom/pom.xml
+++ b/java/bom/pom.xml
@@ -4,7 +4,7 @@
 
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-bom</artifactId>
-  <version>3.18.1</version>
+  <version>3.19.4</version>
   <packaging>pom</packaging>
 
   <name>Protocol Buffers [BOM]</name>
@@ -29,7 +29,7 @@
 
   <licenses>
     <license>
-      <name>3-Clause BSD License</name>
+      <name>BSD-3-Clause</name>
       <url>https://opensource.org/licenses/BSD-3-Clause</url>
     </license>
   </licenses>
diff --git a/java/core/BUILD b/java/core/BUILD
index 42124bb..a698fc8 100644
--- a/java/core/BUILD
+++ b/java/core/BUILD
@@ -1,5 +1,5 @@
 load("@bazel_skylib//rules:build_test.bzl", "build_test")
-load("@rules_java//java:defs.bzl", "java_library", "java_proto_library", "java_lite_proto_library")
+load("@rules_java//java:defs.bzl", "java_library", "java_lite_proto_library", "java_proto_library")
 load("@rules_jvm_external//:defs.bzl", "java_export")
 load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain", "proto_library")
 load("//:internal.bzl", "conformance_test")
@@ -103,7 +103,7 @@
 java_library(
     name = "lite",
     srcs = LITE_SRCS + [
-        "//:gen_well_known_protos_javalite"
+        "//:gen_well_known_protos_javalite",
     ],
     visibility = [
         "//java/lite:__pkg__",
@@ -115,10 +115,10 @@
     name = "lite_mvn",
     maven_coordinates = "com.google.protobuf:protobuf-javalite:%s" % PROTOBUF_VERSION,
     pom_template = "//java/lite:pom_template.xml",
-    runtime_deps = [":lite"],
     resources = [
         "//:lite_well_known_protos",
     ],
+    runtime_deps = [":lite"],
 )
 
 java_library(
@@ -150,25 +150,25 @@
     name = "core_mvn",
     maven_coordinates = "com.google.protobuf:protobuf-java:%s" % PROTOBUF_VERSION,
     pom_template = "pom_template.xml",
-    runtime_deps = [":core"],
     resources = [
         "//:well_known_protos",
     ],
+    runtime_deps = [":core"],
 )
 
 filegroup(
     name = "release",
-    visibility = ["//java:__pkg__"],
     srcs = [
-        ":core_mvn-pom",
-        ":core_mvn-maven-source",
         ":core_mvn-docs",
+        ":core_mvn-maven-source",
+        ":core_mvn-pom",
         ":core_mvn-project",
-        ":lite_mvn-pom",
-        ":lite_mvn-maven-source",
         ":lite_mvn-docs",
+        ":lite_mvn-maven-source",
+        ":lite_mvn-pom",
         ":lite_mvn-project",
-    ]
+    ],
+    visibility = ["//java:__pkg__"],
 )
 
 proto_lang_toolchain(
@@ -176,6 +176,21 @@
     command_line = "--java_out=$(OUT)",
     runtime = ":core",
     visibility = ["//visibility:public"],
+    # keep this in sync w/ WELL_KNOWN_PROTO_MAP in //:BUILD
+    blacklisted_protos = [
+        "//:any_proto",
+        "//:api_proto",
+        "//:compiler_plugin_proto",
+        "//:descriptor_proto",
+        "//:duration_proto",
+        "//:empty_proto",
+        "//:field_mask_proto",
+        "//:source_context_proto",
+        "//:struct_proto",
+        "//:timestamp_proto",
+        "//:type_proto",
+        "//:wrappers_proto",
+    ],
 )
 
 proto_library(
@@ -207,23 +222,25 @@
     name = "test_util",
     srcs = [
         "src/test/java/com/google/protobuf/TestUtil.java",
-        "src/test/java/com/google/protobuf/TestUtilLite.java"
+        "src/test/java/com/google/protobuf/TestUtilLite.java",
     ],
     deps = [
         ":core",
         ":generic_test_protos_java_proto",
         ":java_test_protos_java_proto",
-        "//external:guava",
-        "//external:junit",
+        "@maven//:com_google_guava_guava",
+        "@maven//:junit_junit",
     ],
+    visibility = ["//java:__subpackages__"],
 )
 
 test_suite(
     name = "tests",
     tests = [
-        "core_build_test",
         "conformance_test",
+        "core_build_test",
         "core_tests",
+        "utf8_tests",
     ],
 )
 
@@ -236,30 +253,52 @@
 
 conformance_test(
     name = "conformance_test",
-    testee = "//:conformance_java",
     failure_list = "//:conformance/failure_list_java.txt",
+    testee = "//:conformance_java",
     text_format_failure_list = "//:conformance/text_format_failure_list_java.txt",
 )
 
 junit_tests(
     name = "core_tests",
-    srcs = glob(["src/test/java/**/*.java"], exclude = [
-        "src/test/java/com/google/protobuf/TestUtil.java",
-        "src/test/java/com/google/protobuf/TestUtilLite.java",
-    ]),
+    size = "small",
+    srcs = glob(
+        ["src/test/java/**/*.java"],
+        exclude = [
+            "src/test/java/com/google/protobuf/DecodeUtf8Test.java",
+            "src/test/java/com/google/protobuf/IsValidUtf8Test.java",
+            "src/test/java/com/google/protobuf/TestUtil.java",
+            "src/test/java/com/google/protobuf/TestUtilLite.java",
+        ],
+    ),
     data = ["//:testdata"],
-    size = "large",
     deps = [
         ":core",
         ":generic_test_protos_java_proto",
         ":java_test_protos_java_proto",
         ":test_util",
-        "//external:easymock",
-        "//external:easymock_classextension",
-        "//external:guava",
-        "//external:junit",
-        "//external:truth",
-    ]
+        "@maven//:com_google_guava_guava",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+        "@maven//:org_easymock_easymock",
+    ],
+)
+
+# The UTF-8 validation tests are much slower than the other tests, so they get
+# their own test target with a longer timeout.
+junit_tests(
+    name = "utf8_tests",
+    size = "large",
+    srcs = [
+        "src/test/java/com/google/protobuf/DecodeUtf8Test.java",
+        "src/test/java/com/google/protobuf/IsValidUtf8Test.java",
+        "src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java",
+    ],
+    deps = [
+        ":core",
+        "@maven//:com_google_guava_guava",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
 )
 
 java_lite_proto_library(
@@ -282,27 +321,28 @@
     name = "rewrite_javalite_test_util",
     srcs = [
         "//java/lite:lite.awk",
-        "src/test/java/com/google/protobuf/TestUtil.java"
+        "src/test/java/com/google/protobuf/TestUtil.java",
     ],
     outs = ["TestUtil.java"],
-    cmd = "awk -f $(location //java/lite:lite.awk) $(location src/test/java/com/google/protobuf/TestUtil.java) > $@"
+    cmd = "awk -f $(location //java/lite:lite.awk) $(location src/test/java/com/google/protobuf/TestUtil.java) > $@",
 )
 
 java_library(
     name = "test_util_lite",
     srcs = [
+        "src/test/java/com/google/protobuf/TestUtilLite.java",
         ":rewrite_javalite_test_util",
-        "src/test/java/com/google/protobuf/TestUtilLite.java"
     ],
     visibility = [
         "//java/lite:__pkg__",
+        "//java/kotlin-lite:__pkg__",
     ],
     deps = [
         ":generic_test_protos_java_proto_lite",
         ":java_test_protos_java_proto_lite",
         ":lite_runtime_only",
-        "//external:guava",
-        "//external:junit",
+        "@maven//:com_google_guava_guava",
+        "@maven//:junit_junit",
     ],
 )
 
@@ -344,6 +384,7 @@
     "src/test/java/com/google/protobuf/TypeRegistryTest.java",
     "src/test/java/com/google/protobuf/UnknownEnumValueTest.java",
     "src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java",
+    "src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java",
     "src/test/java/com/google/protobuf/UnknownFieldSetTest.java",
     "src/test/java/com/google/protobuf/WellKnownTypesTest.java",
     "src/test/java/com/google/protobuf/WireFormatTest.java",
@@ -351,18 +392,20 @@
 
 junit_tests(
     name = "lite_tests",
-    srcs = glob(["src/test/java/**/*.java"], exclude = LITE_TEST_EXCLUSIONS),
+    size = "large",
+    srcs = glob(
+        ["src/test/java/**/*.java"],
+        exclude = LITE_TEST_EXCLUSIONS,
+    ),
     data = ["//:testdata"],
     test_prefix = "Lite",
-    size = "large",
     deps = [
-        ":lite",
         ":generic_test_protos_java_proto_lite",
         ":java_test_protos_java_proto_lite",
+        ":lite",
         ":test_util_lite",
-        "//external:easymock",
-        "//external:junit",
-        "//external:truth",
-    ]
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+        "@maven//:org_easymock_easymock",
+    ],
 )
-
diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml
index 71a88d0..db44a15 100644
--- a/java/core/generate-test-sources-build.xml
+++ b/java/core/generate-test-sources-build.xml
@@ -30,7 +30,6 @@
         <arg value="${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_lite_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/map_test.proto"/>
-        <arg value="${test.proto.dir}/com/google/protobuf/message_lite_extension_util_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/multiple_files_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
         <arg value="${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 3b56150..ce068ee 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
   </parent>
 
   <artifactId>protobuf-java</artifactId>
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 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 a4beaeb..f9e8efd 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).
@@ -282,8 +319,8 @@
       };
 
   /**
-   * Returns a {@link Comparator} which compares {@link ByteString}-s lexicographically
-   * as sequences of unsigned bytes (i.e. 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}:
@@ -347,6 +384,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/proto/com/google/protobuf/message_lite_extension_util_test.proto b/java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
similarity index 75%
copy from java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto
copy to java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
index 9baf948..dde7cf1 100644
--- a/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto
+++ b/java/core/src/main/java/com/google/protobuf/CompileTimeConstant.java
@@ -28,21 +28,20 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Proto definitions used to test MessageLiteExtensionUtil
-syntax = "proto2";
+package com.google.protobuf;
 
-package protobuf_unittest;
+import static java.lang.annotation.RetentionPolicy.CLASS;
 
-option java_outer_classname = "MessageLiteExtensionTestProtos";
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
 
-message Car {
-  optional string make = 1;
-  extensions 1000 to max;
-}
-
-extend Car {
-  optional bool turbo = 1001;
-  optional bool self_driving = 1002;
-  optional bool flies = 1003;
-  optional string plate = 9999;
-}
+/**
+ * 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 f36d033..1722ba5 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 4853df2..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) {
@@ -1081,8 +1071,7 @@
 
         // Wrap the contents in a new list so that the caller cannot change
         // the list's contents after setting it.
-        final List newList = new ArrayList();
-        newList.addAll((List) value);
+        final List newList = new ArrayList((List) value);
         for (final Object element : newList) {
           verifyType(descriptor, element);
           hasNestedBuilders = hasNestedBuilders || element instanceof MessageLite.Builder;
@@ -1115,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 {
@@ -1170,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();
       }
@@ -1195,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<>();
@@ -1263,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();
@@ -1272,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..71ccb14 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,15 @@
   private MessageLite unfinishedMessage = null;
   private boolean wasThrownFromInputStream;
 
-  public InvalidProtocolBufferException(final String description) {
+  public InvalidProtocolBufferException(String description) {
     super(description);
   }
 
-  public InvalidProtocolBufferException(IOException e) {
+  public InvalidProtocolBufferException(Exception e) {
     super(e.getMessage(), e);
   }
 
-  public InvalidProtocolBufferException(final String description, IOException e) {
+  public InvalidProtocolBufferException(String description, Exception 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..db63534 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 21f1ff0..6aeb565 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -70,6 +70,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);
@@ -92,6 +95,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);
@@ -145,6 +151,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);
   }
@@ -166,6 +175,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);
   }
@@ -227,6 +239,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/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
index ba2f9df..5c482d6 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -43,13 +43,13 @@
 import java.util.TreeMap;
 
 /**
- * {@code UnknownFieldSet} is used to keep track of fields which were seen when parsing a protocol
+ * {@code UnknownFieldSet} keeps track of fields which were seen when parsing a protocol
  * message but whose field numbers or types are unrecognized. This most frequently occurs when new
  * fields are added to a message type and then messages containing those fields are read by old
  * software that was compiled before the new types were added.
  *
  * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every {@link Message.Builder}
- * contains an {@link Builder}).
+ * contains a {@link Builder}).
  *
  * <p>Most users will never need to use this class.
  *
@@ -57,9 +57,13 @@
  */
 public final class UnknownFieldSet implements MessageLite {
 
-  private UnknownFieldSet() {
-    fields = null;
-    fieldsDescending = null;
+  private final TreeMap<Integer, Field> fields;
+
+  /**
+   * Construct an {@code UnknownFieldSet} around the given map.
+   */
+  UnknownFieldSet(TreeMap<Integer, Field> fields) {
+    this.fields = fields;
   }
 
   /** Create a new {@link Builder}. */
@@ -68,7 +72,7 @@
   }
 
   /** Create a new {@link Builder} and initialize it to be a copy of {@code copyFrom}. */
-  public static Builder newBuilder(final UnknownFieldSet copyFrom) {
+  public static Builder newBuilder(UnknownFieldSet copyFrom) {
     return newBuilder().mergeFrom(copyFrom);
   }
 
@@ -83,25 +87,11 @@
   }
 
   private static final UnknownFieldSet defaultInstance =
-      new UnknownFieldSet(
-          Collections.<Integer, Field>emptyMap(), Collections.<Integer, Field>emptyMap());
-
-  /**
-   * Construct an {@code UnknownFieldSet} around the given map. The map is expected to be immutable.
-   */
-  UnknownFieldSet(final Map<Integer, Field> fields, final Map<Integer, Field> fieldsDescending) {
-    this.fields = fields;
-    this.fieldsDescending = fieldsDescending;
-  }
-
-  private final Map<Integer, Field> fields;
-
-  /** A copy of {@link #fields} who's iterator order is reversed. */
-  private final Map<Integer, Field> fieldsDescending;
+      new UnknownFieldSet(new TreeMap<Integer, Field>());
 
 
   @Override
-  public boolean equals(final Object other) {
+  public boolean equals(Object other) {
     if (this == other) {
       return true;
     }
@@ -110,29 +100,33 @@
 
   @Override
   public int hashCode() {
+    if (fields.isEmpty()) { // avoid allocation of iterator.
+      // This optimization may not be helpful but it is needed for the allocation tests to pass.
+      return 0;
+    }
     return fields.hashCode();
   }
 
   /** Get a map of fields in the set by number. */
   public Map<Integer, Field> asMap() {
-    return fields;
+    return (Map<Integer, Field>) fields.clone();
   }
 
   /** Check if the given field number is present in the set. */
-  public boolean hasField(final int number) {
+  public boolean hasField(int number) {
     return fields.containsKey(number);
   }
 
   /** Get a field by number. Returns an empty field if not present. Never returns {@code null}. */
-  public Field getField(final int number) {
-    final Field result = fields.get(number);
+  public Field getField(int number) {
+    Field result = fields.get(number);
     return (result == null) ? Field.getDefaultInstance() : result;
   }
 
   /** Serializes the set and writes it to {@code output}. */
   @Override
-  public void writeTo(final CodedOutputStream output) throws IOException {
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+  public void writeTo(CodedOutputStream output) throws IOException {
+    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
       Field field = entry.getValue();
       field.writeTo(entry.getKey(), output);
     }
@@ -154,10 +148,10 @@
   @Override
   public ByteString toByteString() {
     try {
-      final ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize());
+      ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize());
       writeTo(out.getCodedOutput());
       return out.build();
-    } catch (final IOException e) {
+    } catch (IOException e) {
       throw new RuntimeException(
           "Serializing to a ByteString threw an IOException (should never happen).", e);
     }
@@ -170,12 +164,12 @@
   @Override
   public byte[] toByteArray() {
     try {
-      final byte[] result = new byte[getSerializedSize()];
-      final CodedOutputStream output = CodedOutputStream.newInstance(result);
+      byte[] result = new byte[getSerializedSize()];
+      CodedOutputStream output = CodedOutputStream.newInstance(result);
       writeTo(output);
       output.checkNoSpaceLeft();
       return result;
-    } catch (final IOException e) {
+    } catch (IOException e) {
       throw new RuntimeException(
           "Serializing to a byte array threw an IOException (should never happen).", e);
     }
@@ -186,16 +180,16 @@
    * {@link #writeTo(CodedOutputStream)}.
    */
   @Override
-  public void writeTo(final OutputStream output) throws IOException {
-    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+  public void writeTo(OutputStream output) throws IOException {
+    CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
     writeTo(codedOutput);
     codedOutput.flush();
   }
 
   @Override
   public void writeDelimitedTo(OutputStream output) throws IOException {
-    final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
-    codedOutput.writeRawVarint32(getSerializedSize());
+    CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+    codedOutput.writeUInt32NoTag(getSerializedSize());
     writeTo(codedOutput);
     codedOutput.flush();
   }
@@ -204,15 +198,17 @@
   @Override
   public int getSerializedSize() {
     int result = 0;
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      result += entry.getValue().getSerializedSize(entry.getKey());
+    if (!fields.isEmpty()) {
+      for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
+        result += entry.getValue().getSerializedSize(entry.getKey());
+      }
     }
     return result;
   }
 
   /** Serializes the set and writes it to {@code output} using {@code MessageSet} wire format. */
-  public void writeAsMessageSetTo(final CodedOutputStream output) throws IOException {
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+  public void writeAsMessageSetTo(CodedOutputStream output) throws IOException {
+    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
       entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), output);
     }
   }
@@ -221,7 +217,7 @@
   void writeTo(Writer writer) throws IOException {
     if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
       // Write fields in descending order.
-      for (Map.Entry<Integer, Field> entry : fieldsDescending.entrySet()) {
+      for (Map.Entry<Integer, Field> entry : fields.descendingMap().entrySet()) {
         entry.getValue().writeTo(entry.getKey(), writer);
       }
     } else {
@@ -233,15 +229,15 @@
   }
 
   /** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */
-  void writeAsMessageSetTo(final Writer writer) throws IOException {
+  void writeAsMessageSetTo(Writer writer) throws IOException {
     if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
       // Write fields in descending order.
-      for (final Map.Entry<Integer, Field> entry : fieldsDescending.entrySet()) {
+      for (Map.Entry<Integer, Field> entry : fields.descendingMap().entrySet()) {
         entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer);
       }
     } else {
       // Write fields in ascending order.
-      for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+      for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
         entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer);
       }
     }
@@ -250,7 +246,7 @@
   /** Get the number of bytes required to encode this set using {@code MessageSet} wire format. */
   public int getSerializedSizeAsMessageSet() {
     int result = 0;
-    for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+    for (Map.Entry<Integer, Field> entry : fields.entrySet()) {
       result += entry.getValue().getSerializedSizeAsMessageSetExtension(entry.getKey());
     }
     return result;
@@ -264,23 +260,23 @@
   }
 
   /** Parse an {@code UnknownFieldSet} from the given input stream. */
-  public static UnknownFieldSet parseFrom(final CodedInputStream input) throws IOException {
+  public static UnknownFieldSet parseFrom(CodedInputStream input) throws IOException {
     return newBuilder().mergeFrom(input).build();
   }
 
   /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(final ByteString data)
+  public static UnknownFieldSet parseFrom(ByteString data)
       throws InvalidProtocolBufferException {
     return newBuilder().mergeFrom(data).build();
   }
 
   /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
-  public static UnknownFieldSet parseFrom(final byte[] data) throws InvalidProtocolBufferException {
+  public static UnknownFieldSet parseFrom(byte[] data) throws InvalidProtocolBufferException {
     return newBuilder().mergeFrom(data).build();
   }
 
   /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
-  public static UnknownFieldSet parseFrom(final InputStream input) throws IOException {
+  public static UnknownFieldSet parseFrom(InputStream input) throws IOException {
     return newBuilder().mergeFrom(input).build();
   }
 
@@ -309,64 +305,43 @@
     // This constructor should never be called directly (except from 'create').
     private Builder() {}
 
-    private Map<Integer, Field> fields;
-
-    // Optimization:  We keep around a builder for the last field that was
-    //   modified so that we can efficiently add to it multiple times in a
-    //   row (important when parsing an unknown repeated field).
-    private int lastFieldNumber;
-    private Field.Builder lastField;
+    private TreeMap<Integer, Field.Builder> fieldBuilders = new TreeMap<>();
 
     private static Builder create() {
-      Builder builder = new Builder();
-      builder.reinitialize();
-      return builder;
+      return new Builder();
     }
 
     /**
      * Get a field builder for the given field number which includes any values that already exist.
      */
-    private Field.Builder getFieldBuilder(final int number) {
-      if (lastField != null) {
-        if (number == lastFieldNumber) {
-          return lastField;
-        }
-        // Note:  addField() will reset lastField and lastFieldNumber.
-        addField(lastFieldNumber, lastField.build());
-      }
+    private Field.Builder getFieldBuilder(int number) {
       if (number == 0) {
         return null;
       } else {
-        final Field existing = fields.get(number);
-        lastFieldNumber = number;
-        lastField = Field.newBuilder();
-        if (existing != null) {
-          lastField.mergeFrom(existing);
+        Field.Builder builder = fieldBuilders.get(number);
+        if (builder == null) {
+          builder = Field.newBuilder();
+          fieldBuilders.put(number, builder);
         }
-        return lastField;
+        return builder;
       }
     }
 
     /**
      * Build the {@link UnknownFieldSet} and return it.
-     *
-     * <p>Once {@code build()} has been called, the {@code Builder} will no longer be usable.
-     * Calling any method after {@code build()} will result in undefined behavior and can cause a
-     * {@code NullPointerException} to be thrown.
      */
     @Override
     public UnknownFieldSet build() {
-      getFieldBuilder(0); // Force lastField to be built.
-      final UnknownFieldSet result;
-      if (fields.isEmpty()) {
+      UnknownFieldSet result;
+      if (fieldBuilders.isEmpty()) {
         result = getDefaultInstance();
       } else {
-        Map<Integer, Field> descendingFields = null;
-        descendingFields =
-            Collections.unmodifiableMap(((TreeMap<Integer, Field>) fields).descendingMap());
-        result = new UnknownFieldSet(Collections.unmodifiableMap(fields), descendingFields);
+        TreeMap<Integer, Field> fields = new TreeMap<>();
+        for (Map.Entry<Integer, Field.Builder> entry : fieldBuilders.entrySet()) {
+          fields.put(entry.getKey(), entry.getValue().build());
+        }
+        result = new UnknownFieldSet(fields);
       }
-      fields = null;
       return result;
     }
 
@@ -378,11 +353,13 @@
 
     @Override
     public Builder clone() {
-      getFieldBuilder(0); // Force lastField to be built.
-      Map<Integer, Field> descendingFields = null;
-      descendingFields =
-          Collections.unmodifiableMap(((TreeMap<Integer, Field>) fields).descendingMap());
-      return UnknownFieldSet.newBuilder().mergeFrom(new UnknownFieldSet(fields, descendingFields));
+      Builder clone = UnknownFieldSet.newBuilder();
+      for (Map.Entry<Integer, Field.Builder> entry : fieldBuilders.entrySet()) {
+        Integer key = entry.getKey();
+        Field.Builder value = entry.getValue();
+        clone.fieldBuilders.put(key, value.clone());
+      }
+      return clone;
     }
 
     @Override
@@ -390,31 +367,24 @@
       return UnknownFieldSet.getDefaultInstance();
     }
 
-    private void reinitialize() {
-      fields = Collections.emptyMap();
-      lastFieldNumber = 0;
-      lastField = null;
-    }
-
     /** Reset the builder to an empty set. */
     @Override
     public Builder clear() {
-      reinitialize();
+      fieldBuilders = new TreeMap<>();
       return this;
     }
 
-    /** Clear fields from the set with a given field number. */
-    public Builder clearField(final int number) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
+    /**
+     * Clear fields from the set with a given field number.
+     *
+     * @throws IllegalArgumentException if number is not positive
+     */
+    public Builder clearField(int number) {
+      if (number <= 0) {
+        throw new IllegalArgumentException(number + " is not a valid field number.");
       }
-      if (lastField != null && lastFieldNumber == number) {
-        // Discard this.
-        lastField = null;
-        lastFieldNumber = 0;
-      }
-      if (fields.containsKey(number)) {
-        fields.remove(number);
+      if (fieldBuilders.containsKey(number)) {
+        fieldBuilders.remove(number);
       }
       return this;
     }
@@ -423,9 +393,9 @@
      * Merge the fields from {@code other} into this set. If a field number exists in both sets,
      * {@code other}'s values for that field will be appended to the values in this set.
      */
-    public Builder mergeFrom(final UnknownFieldSet other) {
+    public Builder mergeFrom(UnknownFieldSet other) {
       if (other != getDefaultInstance()) {
-        for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
+        for (Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
           mergeField(entry.getKey(), entry.getValue());
         }
       }
@@ -435,10 +405,12 @@
     /**
      * Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists,
      * the two are merged.
+     *
+     * @throws IllegalArgumentException if number is not positive
      */
-    public Builder mergeField(final int number, final Field field) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
+    public Builder mergeField(int number, final Field field) {
+      if (number <= 0) {
+        throw new IllegalArgumentException(number + " is not a valid field number.");
       }
       if (hasField(number)) {
         getFieldBuilder(number).mergeFrom(field);
@@ -454,10 +426,12 @@
     /**
      * Convenience method for merging a new field containing a single varint value. This is used in
      * particular when an unknown enum value is encountered.
+     *
+     * @throws IllegalArgumentException if number is not positive
      */
-    public Builder mergeVarintField(final int number, final int value) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
+    public Builder mergeVarintField(int number, int value) {
+      if (number <= 0) {
+        throw new IllegalArgumentException(number + " is not a valid field number.");
       }
       getFieldBuilder(number).addVarint(value);
       return this;
@@ -467,40 +441,33 @@
      * Convenience method for merging a length-delimited field.
      *
      * <p>For use by generated code only.
+     *
+     * @throws IllegalArgumentException if number is not positive
      */
-    public Builder mergeLengthDelimitedField(final int number, final ByteString value) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
+    public Builder mergeLengthDelimitedField(int number, ByteString value) {
+      if (number <= 0) {
+        throw new IllegalArgumentException(number + " is not a valid field number.");
       }
       getFieldBuilder(number).addLengthDelimited(value);
       return this;
     }
 
     /** Check if the given field number is present in the set. */
-    public boolean hasField(final int number) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
-      }
-      return number == lastFieldNumber || fields.containsKey(number);
+    public boolean hasField(int number) {
+      return fieldBuilders.containsKey(number);
     }
 
     /**
      * Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists,
      * it is removed.
+     *
+     * @throws IllegalArgumentException if number is not positive
      */
-    public Builder addField(final int number, final Field field) {
-      if (number == 0) {
-        throw new IllegalArgumentException("Zero is not a valid field number.");
+    public Builder addField(int number, Field field) {
+      if (number <= 0) {
+        throw new IllegalArgumentException(number + " is not a valid field number.");
       }
-      if (lastField != null && lastFieldNumber == number) {
-        // Discard this.
-        lastField = null;
-        lastFieldNumber = 0;
-      }
-      if (fields.isEmpty()) {
-        fields = new TreeMap<Integer, Field>();
-      }
-      fields.put(number, field);
+      fieldBuilders.put(number, Field.newBuilder(field));
       return this;
     }
 
@@ -509,15 +476,18 @@
      * changes may or may not be reflected in this map.
      */
     public Map<Integer, Field> asMap() {
-      getFieldBuilder(0); // Force lastField to be built.
+      TreeMap<Integer, Field> fields = new TreeMap<>();
+      for (Map.Entry<Integer, Field.Builder> entry : fieldBuilders.entrySet()) {
+        fields.put(entry.getKey(), entry.getValue().build());
+      }
       return Collections.unmodifiableMap(fields);
     }
 
     /** Parse an entire message from {@code input} and merge its fields into this set. */
     @Override
-    public Builder mergeFrom(final CodedInputStream input) throws IOException {
+    public Builder mergeFrom(CodedInputStream input) throws IOException {
       while (true) {
-        final int tag = input.readTag();
+        int tag = input.readTag();
         if (tag == 0 || !mergeFieldFrom(tag, input)) {
           break;
         }
@@ -531,8 +501,8 @@
      * @param tag The field's tag number, which was already parsed.
      * @return {@code false} if the tag is an end group tag.
      */
-    public boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
-      final int number = WireFormat.getTagFieldNumber(tag);
+    public boolean mergeFieldFrom(int tag, CodedInputStream input) throws IOException {
+      int number = WireFormat.getTagFieldNumber(tag);
       switch (WireFormat.getTagWireType(tag)) {
         case WireFormat.WIRETYPE_VARINT:
           getFieldBuilder(number).addVarint(input.readInt64());
@@ -544,7 +514,7 @@
           getFieldBuilder(number).addLengthDelimited(input.readBytes());
           return true;
         case WireFormat.WIRETYPE_START_GROUP:
-          final Builder subBuilder = newBuilder();
+          Builder subBuilder = newBuilder();
           input.readGroup(number, subBuilder, ExtensionRegistry.getEmptyRegistry());
           getFieldBuilder(number).addGroup(subBuilder.build());
           return true;
@@ -563,15 +533,15 @@
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      */
     @Override
-    public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException {
+    public Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException {
       try {
-        final CodedInputStream input = data.newCodedInput();
+        CodedInputStream input = data.newCodedInput();
         mergeFrom(input);
         input.checkLastTagWas(0);
         return this;
-      } catch (final InvalidProtocolBufferException e) {
+      } catch (InvalidProtocolBufferException e) {
         throw e;
-      } catch (final IOException e) {
+      } catch (IOException e) {
         throw new RuntimeException(
             "Reading from a ByteString threw an IOException (should never happen).", e);
       }
@@ -582,15 +552,15 @@
      * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      */
     @Override
-    public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException {
+    public Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException {
       try {
-        final CodedInputStream input = CodedInputStream.newInstance(data);
+        CodedInputStream input = CodedInputStream.newInstance(data);
         mergeFrom(input);
         input.checkLastTagWas(0);
         return this;
-      } catch (final InvalidProtocolBufferException e) {
+      } catch (InvalidProtocolBufferException e) {
         throw e;
-      } catch (final IOException e) {
+      } catch (IOException e) {
         throw new RuntimeException(
             "Reading from a byte array threw an IOException (should never happen).", e);
       }
@@ -601,8 +571,8 @@
      * This is just a small wrapper around {@link #mergeFrom(CodedInputStream)}.
      */
     @Override
-    public Builder mergeFrom(final InputStream input) throws IOException {
-      final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+    public Builder mergeFrom(InputStream input) throws IOException {
+      CodedInputStream codedInput = CodedInputStream.newInstance(input);
       mergeFrom(codedInput);
       codedInput.checkLastTagWas(0);
       return this;
@@ -610,12 +580,12 @@
 
     @Override
     public boolean mergeDelimitedFrom(InputStream input) throws IOException {
-      final int firstByte = input.read();
+      int firstByte = input.read();
       if (firstByte == -1) {
         return false;
       }
-      final int size = CodedInputStream.readRawVarint32(firstByte, input);
-      final InputStream limitedInput = new LimitedInputStream(input, size);
+      int size = CodedInputStream.readRawVarint32(firstByte, input);
+      InputStream limitedInput = new LimitedInputStream(input, size);
       mergeFrom(limitedInput);
       return true;
     }
@@ -644,7 +614,7 @@
     @Override
     public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException {
       try {
-        final CodedInputStream input = CodedInputStream.newInstance(data, off, len);
+        CodedInputStream input = CodedInputStream.newInstance(data, off, len);
         mergeFrom(input);
         input.checkLastTagWas(0);
         return this;
@@ -718,7 +688,7 @@
     }
 
     /** Construct a new {@link Builder} and initialize it to a copy of {@code copyFrom}. */
-    public static Builder newBuilder(final Field copyFrom) {
+    public static Builder newBuilder(Field copyFrom) {
       return newBuilder().mergeFrom(copyFrom);
     }
 
@@ -758,7 +728,7 @@
     }
 
     @Override
-    public boolean equals(final Object other) {
+    public boolean equals(Object other) {
       if (this == other) {
         return true;
       }
@@ -785,7 +755,7 @@
     public ByteString toByteString(int fieldNumber) {
       try {
         // TODO(lukes): consider caching serialized size in a volatile long
-        final ByteString.CodedBuilder out =
+        ByteString.CodedBuilder out =
             ByteString.newCodedBuilder(getSerializedSize(fieldNumber));
         writeTo(fieldNumber, out.getCodedOutput());
         return out.build();
@@ -796,40 +766,40 @@
     }
 
     /** Serializes the field, including field number, and writes it to {@code output}. */
-    public void writeTo(final int fieldNumber, final CodedOutputStream output) throws IOException {
-      for (final long value : varint) {
+    public void writeTo(int fieldNumber, CodedOutputStream output) throws IOException {
+      for (long value : varint) {
         output.writeUInt64(fieldNumber, value);
       }
-      for (final int value : fixed32) {
+      for (int value : fixed32) {
         output.writeFixed32(fieldNumber, value);
       }
-      for (final long value : fixed64) {
+      for (long value : fixed64) {
         output.writeFixed64(fieldNumber, value);
       }
-      for (final ByteString value : lengthDelimited) {
+      for (ByteString value : lengthDelimited) {
         output.writeBytes(fieldNumber, value);
       }
-      for (final UnknownFieldSet value : group) {
+      for (UnknownFieldSet value : group) {
         output.writeGroup(fieldNumber, value);
       }
     }
 
     /** Get the number of bytes required to encode this field, including field number. */
-    public int getSerializedSize(final int fieldNumber) {
+    public int getSerializedSize(int fieldNumber) {
       int result = 0;
-      for (final long value : varint) {
+      for (long value : varint) {
         result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
       }
-      for (final int value : fixed32) {
+      for (int value : fixed32) {
         result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
       }
-      for (final long value : fixed64) {
+      for (long value : fixed64) {
         result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
       }
-      for (final ByteString value : lengthDelimited) {
+      for (ByteString value : lengthDelimited) {
         result += CodedOutputStream.computeBytesSize(fieldNumber, value);
       }
-      for (final UnknownFieldSet value : group) {
+      for (UnknownFieldSet value : group) {
         result += CodedOutputStream.computeGroupSize(fieldNumber, value);
       }
       return result;
@@ -839,15 +809,15 @@
      * Serializes the field, including field number, and writes it to {@code output}, using {@code
      * MessageSet} wire format.
      */
-    public void writeAsMessageSetExtensionTo(final int fieldNumber, final CodedOutputStream output)
+    public void writeAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output)
         throws IOException {
-      for (final ByteString value : lengthDelimited) {
+      for (ByteString value : lengthDelimited) {
         output.writeRawMessageSetExtension(fieldNumber, value);
       }
     }
 
     /** Serializes the field, including field number, and writes it to {@code writer}. */
-    void writeTo(final int fieldNumber, final Writer writer) throws IOException {
+    void writeTo(int fieldNumber, Writer writer) throws IOException {
       writer.writeInt64List(fieldNumber, varint, false);
       writer.writeFixed32List(fieldNumber, fixed32, false);
       writer.writeFixed64List(fieldNumber, fixed64, false);
@@ -872,7 +842,7 @@
      * Serializes the field, including field number, and writes it to {@code writer}, using {@code
      * MessageSet} wire format.
      */
-    private void writeAsMessageSetExtensionTo(final int fieldNumber, final Writer writer)
+    private void writeAsMessageSetExtensionTo(int fieldNumber, Writer writer)
         throws IOException {
       if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
         // Write in descending field order.
@@ -882,7 +852,7 @@
         }
       } else {
         // Write in ascending field order.
-        for (final ByteString value : lengthDelimited) {
+        for (ByteString value : lengthDelimited) {
           writer.writeMessageSetItem(fieldNumber, value);
         }
       }
@@ -892,9 +862,9 @@
      * Get the number of bytes required to encode this field, including field number, using {@code
      * MessageSet} wire format.
      */
-    public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
+    public int getSerializedSizeAsMessageSetExtension(int fieldNumber) {
       int result = 0;
-      for (final ByteString value : lengthDelimited) {
+      for (ByteString value : lengthDelimited) {
         result += CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, value);
       }
       return result;
@@ -912,52 +882,85 @@
      * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
      */
     public static final class Builder {
-      // This constructor should never be called directly (except from 'create').
-      private Builder() {}
+      // This constructor should only be called directly from 'create' and 'clone'.
+      private Builder() {
+        result = new Field();
+      }
 
       private static Builder create() {
         Builder builder = new Builder();
-        builder.result = new Field();
         return builder;
       }
 
       private Field result;
 
-      /**
-       * Build the field. After {@code build()} has been called, the {@code Builder} is no longer
-       * usable. Calling any other method will result in undefined behavior and can cause a {@code
-       * NullPointerException} to be thrown.
-       */
-      public Field build() {
+      @Override
+      public Builder clone() {
+        Field copy = new Field();
         if (result.varint == null) {
-          result.varint = Collections.emptyList();
+          copy.varint = null;
         } else {
-          result.varint = Collections.unmodifiableList(result.varint);
+          copy.varint = new ArrayList<>(result.varint);
         }
         if (result.fixed32 == null) {
-          result.fixed32 = Collections.emptyList();
+          copy.fixed32 = null;
         } else {
-          result.fixed32 = Collections.unmodifiableList(result.fixed32);
+          copy.fixed32 = new ArrayList<>(result.fixed32);
         }
         if (result.fixed64 == null) {
-          result.fixed64 = Collections.emptyList();
+          copy.fixed64 = null;
         } else {
-          result.fixed64 = Collections.unmodifiableList(result.fixed64);
+          copy.fixed64 = new ArrayList<>(result.fixed64);
         }
         if (result.lengthDelimited == null) {
-          result.lengthDelimited = Collections.emptyList();
+          copy.lengthDelimited = null;
         } else {
-          result.lengthDelimited = Collections.unmodifiableList(result.lengthDelimited);
+          copy.lengthDelimited = new ArrayList<>(result.lengthDelimited);
         }
         if (result.group == null) {
-          result.group = Collections.emptyList();
+          copy.group = null;
         } else {
-          result.group = Collections.unmodifiableList(result.group);
+          copy.group = new ArrayList<>(result.group);
         }
 
-        final Field returnMe = result;
-        result = null;
-        return returnMe;
+        Builder clone = new Builder();
+        clone.result = copy;
+        return clone;
+      }
+
+      /**
+       * Build the field.
+       */
+      public Field build() {
+        Field built = new Field();
+        if (result.varint == null) {
+          built.varint = Collections.emptyList();
+        } else {
+          built.varint = Collections.unmodifiableList(new ArrayList<>(result.varint));
+        }
+        if (result.fixed32 == null) {
+          built.fixed32 = Collections.emptyList();
+        } else {
+          built.fixed32 = Collections.unmodifiableList(new ArrayList<>(result.fixed32));
+        }
+        if (result.fixed64 == null) {
+          built.fixed64 = Collections.emptyList();
+        } else {
+          built.fixed64 = Collections.unmodifiableList(new ArrayList<>(result.fixed64));
+        }
+        if (result.lengthDelimited == null) {
+          built.lengthDelimited = Collections.emptyList();
+        } else {
+          built.lengthDelimited = Collections.unmodifiableList(
+              new ArrayList<>(result.lengthDelimited));
+        }
+        if (result.group == null) {
+          built.group = Collections.emptyList();
+        } else {
+          built.group = Collections.unmodifiableList(new ArrayList<>(result.group));
+        }
+
+        return built;
       }
 
       /** Discard the field's contents. */
@@ -970,7 +973,7 @@
        * Merge the values in {@code other} into this field. For each list of values, {@code other}'s
        * values are append to the ones in this field.
        */
-      public Builder mergeFrom(final Field other) {
+      public Builder mergeFrom(Field other) {
         if (!other.varint.isEmpty()) {
           if (result.varint == null) {
             result.varint = new ArrayList<Long>();
@@ -985,19 +988,19 @@
         }
         if (!other.fixed64.isEmpty()) {
           if (result.fixed64 == null) {
-            result.fixed64 = new ArrayList<Long>();
+            result.fixed64 = new ArrayList<>();
           }
           result.fixed64.addAll(other.fixed64);
         }
         if (!other.lengthDelimited.isEmpty()) {
           if (result.lengthDelimited == null) {
-            result.lengthDelimited = new ArrayList<ByteString>();
+            result.lengthDelimited = new ArrayList<>();
           }
           result.lengthDelimited.addAll(other.lengthDelimited);
         }
         if (!other.group.isEmpty()) {
           if (result.group == null) {
-            result.group = new ArrayList<UnknownFieldSet>();
+            result.group = new ArrayList<>();
           }
           result.group.addAll(other.group);
         }
@@ -1005,45 +1008,45 @@
       }
 
       /** Add a varint value. */
-      public Builder addVarint(final long value) {
+      public Builder addVarint(long value) {
         if (result.varint == null) {
-          result.varint = new ArrayList<Long>();
+          result.varint = new ArrayList<>();
         }
         result.varint.add(value);
         return this;
       }
 
       /** Add a fixed32 value. */
-      public Builder addFixed32(final int value) {
+      public Builder addFixed32(int value) {
         if (result.fixed32 == null) {
-          result.fixed32 = new ArrayList<Integer>();
+          result.fixed32 = new ArrayList<>();
         }
         result.fixed32.add(value);
         return this;
       }
 
       /** Add a fixed64 value. */
-      public Builder addFixed64(final long value) {
+      public Builder addFixed64(long value) {
         if (result.fixed64 == null) {
-          result.fixed64 = new ArrayList<Long>();
+          result.fixed64 = new ArrayList<>();
         }
         result.fixed64.add(value);
         return this;
       }
 
       /** Add a length-delimited value. */
-      public Builder addLengthDelimited(final ByteString value) {
+      public Builder addLengthDelimited(ByteString value) {
         if (result.lengthDelimited == null) {
-          result.lengthDelimited = new ArrayList<ByteString>();
+          result.lengthDelimited = new ArrayList<>();
         }
         result.lengthDelimited.add(value);
         return this;
       }
 
       /** Add an embedded group. */
-      public Builder addGroup(final UnknownFieldSet value) {
+      public Builder addGroup(UnknownFieldSet value) {
         if (result.group == null) {
-          result.group = new ArrayList<UnknownFieldSet>();
+          result.group = new ArrayList<>();
         }
         result.group.add(value);
         return this;
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/Proto2MessageInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto2MessageInfoFactory.java
deleted file mode 100644
index af671b2..0000000
--- a/java/core/src/test/java/com/google/protobuf/Proto2MessageInfoFactory.java
+++ /dev/null
@@ -1,892 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static com.google.protobuf.FieldInfo.forField;
-import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier;
-import static com.google.protobuf.FieldInfo.forMapField;
-import static com.google.protobuf.FieldInfo.forOneofMemberField;
-import static com.google.protobuf.FieldInfo.forProto2OptionalField;
-import static com.google.protobuf.FieldInfo.forProto2RequiredField;
-import static com.google.protobuf.FieldInfo.forRepeatedMessageField;
-
-import com.google.protobuf.testing.Proto2Testing;
-import com.google.protobuf.testing.Proto2Testing.Proto2Empty;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroup49;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroup69;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldGroupList51;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.FieldRequiredGroup88;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.RequiredNestedMessage;
-import com.google.protobuf.testing.Proto2Testing.Proto2Message.TestEnum;
-import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithExtensions;
-import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps;
-import java.lang.reflect.Field;
-
-/** A factory that generates a hard-coded message info for {@link Proto2Message}. */
-public final class Proto2MessageInfoFactory implements MessageInfoFactory {
-  private static final Proto2MessageInfoFactory INSTANCE = new Proto2MessageInfoFactory();
-
-  private Proto2MessageInfoFactory() {}
-
-  public static Proto2MessageInfoFactory getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public boolean isSupported(Class<?> clazz) {
-    return true;
-  }
-
-  @Override
-  public MessageInfo messageInfoFor(Class<?> clazz) {
-    if (Proto2Message.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2Message();
-    } else if (FieldGroup49.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroup49();
-    } else if (FieldGroupList51.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroupList51();
-    } else if (FieldGroup69.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroup69();
-    } else if (FieldRequiredGroup88.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldRequiredGroup88();
-    } else if (RequiredNestedMessage.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForRequiredNestedMessage();
-    } else if (Proto2Empty.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2Empty();
-    } else if (Proto2MessageWithExtensions.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2MessageWithExtensions();
-    } else if (Proto2Testing.FieldGroup49.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForExtensionFieldGroup49();
-    } else if (Proto2Testing.FieldGroupList51.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForExtensionFieldGroupList51();
-    } else if (Proto2Testing.Proto2MessageWithMaps.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2MessageWithMaps();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  /**
-   * Creates a new hard-coded info for {@link Proto2Message}. Each time this is called, we manually
-   * go through the entire process of what a message would do if it self-registered its own info,
-   * including looking up each field by name. This is done for benchmarking purposes, so that we get
-   * a more accurate representation of the time it takes to perform this process.
-   */
-  private static StructuralMessageInfo newMessageInfoForProto2Message() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(50);
-    builder.withCheckInitialized(
-        new int[] {
-          10, 27, 62, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
-        });
-    lookupFieldsByName(builder);
-    return builder.build();
-  }
-
-  private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) {
-    Field bitField0 = field("bitField0_");
-
-    builder.withDefaultInstance(Proto2Message.getDefaultInstance());
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldDouble1_"), 1, FieldType.DOUBLE, bitField0, 0x00000001, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldFloat2_"), 2, FieldType.FLOAT, bitField0, 0x00000002, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldInt643_"), 3, FieldType.INT64, bitField0, 0x00000004, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldUint644_"), 4, FieldType.UINT64, bitField0, 0x00000008, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldInt325_"), 5, FieldType.INT32, bitField0, 0x00000010, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldFixed646_"), 6, FieldType.FIXED64, bitField0, 0x00000020, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldFixed327_"), 7, FieldType.FIXED32, bitField0, 0x00000040, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldBool8_"), 8, FieldType.BOOL, bitField0, 0x00000080, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldString9_"), 9, FieldType.STRING, bitField0, 0x00000100, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldMessage10_"), 10, FieldType.MESSAGE, bitField0, 0x00000200, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldBytes11_"), 11, FieldType.BYTES, bitField0, 0x00000400, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldUint3212_"), 12, FieldType.UINT32, bitField0, 0x00000800, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldEnum13_"),
-            13,
-            FieldType.ENUM,
-            bitField0,
-            0x00001000,
-            false,
-            asVerifier(TestEnum.internalGetValueMap())));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldSfixed3214_"), 14, FieldType.SFIXED32, bitField0, 0x00002000, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldSfixed6415_"), 15, FieldType.SFIXED64, bitField0, 0x00004000, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldSint3216_"), 16, FieldType.SINT32, bitField0, 0x00008000, false, null));
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldSint6417_"), 17, FieldType.SINT64, bitField0, 0x00010000, false, null));
-    builder.withField(forField(field("fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, false));
-    builder.withField(forField(field("fieldFloatList19_"), 19, FieldType.FLOAT_LIST, false));
-    builder.withField(forField(field("fieldInt64List20_"), 20, FieldType.INT64_LIST, false));
-    builder.withField(forField(field("fieldUint64List21_"), 21, FieldType.UINT64_LIST, false));
-    builder.withField(forField(field("fieldInt32List22_"), 22, FieldType.INT32_LIST, false));
-    builder.withField(forField(field("fieldFixed64List23_"), 23, FieldType.FIXED64_LIST, false));
-    builder.withField(forField(field("fieldFixed32List24_"), 24, FieldType.FIXED32_LIST, false));
-    builder.withField(forField(field("fieldBoolList25_"), 25, FieldType.BOOL_LIST, false));
-    builder.withField(forField(field("fieldStringList26_"), 26, FieldType.STRING_LIST, false));
-    builder.withField(
-        forRepeatedMessageField(
-            field("fieldMessageList27_"), 27, FieldType.MESSAGE_LIST, Proto2Message.class));
-    builder.withField(forField(field("fieldBytesList28_"), 28, FieldType.BYTES_LIST, false));
-    builder.withField(forField(field("fieldUint32List29_"), 29, FieldType.UINT32_LIST, false));
-    builder.withField(
-        forFieldWithEnumVerifier(
-            field("fieldEnumList30_"),
-            30,
-            FieldType.ENUM_LIST,
-            asVerifier(TestEnum.internalGetValueMap())));
-    builder.withField(forField(field("fieldSfixed32List31_"), 31, FieldType.SFIXED32_LIST, false));
-    builder.withField(forField(field("fieldSfixed64List32_"), 32, FieldType.SFIXED64_LIST, false));
-    builder.withField(forField(field("fieldSint32List33_"), 33, FieldType.SINT32_LIST, false));
-    builder.withField(forField(field("fieldSint64List34_"), 34, FieldType.SINT64_LIST, false));
-    builder.withField(
-        forField(field("fieldDoubleListPacked35_"), 35, FieldType.DOUBLE_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldFloatListPacked36_"), 36, FieldType.FLOAT_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldInt64ListPacked37_"), 37, FieldType.INT64_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldUint64ListPacked38_"), 38, FieldType.UINT64_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldInt32ListPacked39_"), 39, FieldType.INT32_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldFixed64ListPacked40_"), 40, FieldType.FIXED64_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldFixed32ListPacked41_"), 41, FieldType.FIXED32_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldBoolListPacked42_"), 42, FieldType.BOOL_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldUint32ListPacked43_"), 43, FieldType.UINT32_LIST_PACKED, false));
-    builder.withField(
-        forFieldWithEnumVerifier(
-            field("fieldEnumListPacked44_"),
-            44,
-            FieldType.ENUM_LIST_PACKED,
-            asVerifier(TestEnum.internalGetValueMap())));
-    builder.withField(
-        forField(field("fieldSfixed32ListPacked45_"), 45, FieldType.SFIXED32_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldSfixed64ListPacked46_"), 46, FieldType.SFIXED64_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldSint32ListPacked47_"), 47, FieldType.SINT32_LIST_PACKED, false));
-    builder.withField(
-        forField(field("fieldSint64ListPacked48_"), 48, FieldType.SINT64_LIST_PACKED, false));
-
-    builder.withField(
-        forProto2OptionalField(
-            field("fieldGroup49_"), 49, FieldType.GROUP, bitField0, 0x00020000, false, null));
-    builder.withField(
-        forRepeatedMessageField(
-            field("fieldGroupList51_"),
-            51,
-            FieldType.GROUP_LIST,
-            Proto2Message.FieldGroupList51.class));
-
-    OneofInfo oneof = new OneofInfo(0, field("testOneofCase_"), field("testOneof_"));
-    builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, false, null));
-    builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, false, null));
-    builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, false, null));
-    builder.withField(
-        forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, false, null));
-    builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, false, null));
-    builder.withField(
-        forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto2Message.class, false, null));
-    builder.withField(
-        forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, false, null));
-    builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, false, null));
-    builder.withField(
-        forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, false, null));
-    builder.withField(
-        forOneofMemberField(
-            69, FieldType.GROUP, oneof, Proto2Message.FieldGroup69.class, false, null));
-
-    Field bitField1 = field("bitField1_");
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredDouble71_"),
-            71,
-            FieldType.DOUBLE,
-            bitField1,
-            0x00000008,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredFloat72_"),
-            72,
-            FieldType.FLOAT,
-            bitField1,
-            0x00000010,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredInt6473_"),
-            73,
-            FieldType.INT64,
-            bitField1,
-            0x00000020,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredUint6474_"),
-            74,
-            FieldType.UINT64,
-            bitField1,
-            0x00000040,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredInt3275_"),
-            75,
-            FieldType.INT32,
-            bitField1,
-            0x00000080,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredFixed6476_"),
-            76,
-            FieldType.FIXED64,
-            bitField1,
-            0x00000100,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredFixed3277_"),
-            77,
-            FieldType.FIXED32,
-            bitField1,
-            0x00000200,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredBool78_"), 78, FieldType.BOOL, bitField1, 0x00000400, false, null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredString79_"),
-            79,
-            FieldType.STRING,
-            bitField1,
-            0x00000800,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredMessage80_"),
-            80,
-            FieldType.MESSAGE,
-            bitField1,
-            0x00001000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredBytes81_"),
-            81,
-            FieldType.BYTES,
-            bitField1,
-            0x00002000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredUint3282_"),
-            82,
-            FieldType.UINT32,
-            bitField1,
-            0x00004000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredEnum83_"),
-            83,
-            FieldType.ENUM,
-            bitField1,
-            0x00008000,
-            false,
-            asVerifier(TestEnum.internalGetValueMap())));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredSfixed3284_"),
-            84,
-            FieldType.SFIXED32,
-            bitField1,
-            0x00010000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredSfixed6485_"),
-            85,
-            FieldType.SFIXED64,
-            bitField1,
-            0x00020000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredSint3286_"),
-            86,
-            FieldType.SINT32,
-            bitField1,
-            0x00040000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredSint6487_"),
-            87,
-            FieldType.SINT64,
-            bitField1,
-            0x00080000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field("fieldRequiredGroup88_"),
-            88,
-            FieldType.GROUP,
-            bitField1,
-            0x00100000,
-            false,
-            null));
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroup49() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroup49.class, "fieldInt3250_"),
-            50,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroupList51() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroupList51.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroupList51.class, "fieldInt3252_"),
-            52,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroup69() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroup69.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroup69.class, "fieldInt3270_"),
-            70,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForRequiredNestedMessage() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(RequiredNestedMessage.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(RequiredNestedMessage.class, "value_"),
-            1,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldRequiredGroup88() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldRequiredGroup88.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldRequiredGroup88.class, "fieldInt3289_"),
-            89,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto2Empty() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto2MessageWithExtensions() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(0);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForExtensionFieldGroup49() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(Proto2Testing.FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2Testing.FieldGroup49.class, "fieldInt3250_"),
-            50,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForExtensionFieldGroupList51() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(Proto2Testing.FieldGroupList51.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2Testing.FieldGroupList51.class, "fieldInt3252_"),
-            52,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto2MessageWithMaps() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder();
-    builder.withCheckInitialized(
-        new int[] {
-          10, 27, 44, 61, 78, 95, 112, 129, 146, 163, 180, 197,
-        });
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_bool_1", 1));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_bytes_2", 2));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_double_3", 3));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_enum_4", 4));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_fixed32_5", 5));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_fixed64_6", 6));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_float_7", 7));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_int32_8", 8));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_int64_9", 9));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_message_10", 10));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sfixed32_11", 11));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sfixed64_12", 12));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sint32_13", 13));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_sint64_14", 14));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_string_15", 15));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_uint32_16", 16));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_bool_uint64_17", 17));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_bool_18", 18));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_bytes_19", 19));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_double_20", 20));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_enum_21", 21));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_fixed32_22", 22));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_fixed64_23", 23));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_float_24", 24));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_int32_25", 25));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_int64_26", 26));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_message_27", 27));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sfixed32_28", 28));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sfixed64_29", 29));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sint32_30", 30));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_sint64_31", 31));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_string_32", 32));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_uint32_33", 33));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed32_uint64_34", 34));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_bool_35", 35));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_bytes_36", 36));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_double_37", 37));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_enum_38", 38));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_fixed32_39", 39));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_fixed64_40", 40));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_float_41", 41));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_int32_42", 42));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_int64_43", 43));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_message_44", 44));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sfixed32_45", 45));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sfixed64_46", 46));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sint32_47", 47));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_sint64_48", 48));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_string_49", 49));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_uint32_50", 50));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_fixed64_uint64_51", 51));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_bool_52", 52));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_bytes_53", 53));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_double_54", 54));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_enum_55", 55));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_fixed32_56", 56));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_fixed64_57", 57));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_float_58", 58));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_int32_59", 59));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_int64_60", 60));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_message_61", 61));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sfixed32_62", 62));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sfixed64_63", 63));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sint32_64", 64));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_sint64_65", 65));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_string_66", 66));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_uint32_67", 67));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int32_uint64_68", 68));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_bool_69", 69));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_bytes_70", 70));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_double_71", 71));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_enum_72", 72));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_fixed32_73", 73));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_fixed64_74", 74));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_float_75", 75));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_int32_76", 76));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_int64_77", 77));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_message_78", 78));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sfixed32_79", 79));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sfixed64_80", 80));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sint32_81", 81));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_sint64_82", 82));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_string_83", 83));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_uint32_84", 84));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_int64_uint64_85", 85));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_bool_86", 86));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_bytes_87", 87));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_double_88", 88));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_enum_89", 89));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_fixed32_90", 90));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_fixed64_91", 91));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_float_92", 92));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_int32_93", 93));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_int64_94", 94));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_message_95", 95));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sfixed32_96", 96));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sfixed64_97", 97));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sint32_98", 98));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_sint64_99", 99));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_string_100", 100));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_uint32_101", 101));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed32_uint64_102", 102));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_bool_103", 103));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_bytes_104", 104));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_double_105", 105));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_enum_106", 106));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_fixed32_107", 107));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_fixed64_108", 108));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_float_109", 109));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_int32_110", 110));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_int64_111", 111));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_message_112", 112));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sfixed32_113", 113));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sfixed64_114", 114));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sint32_115", 115));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_sint64_116", 116));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_string_117", 117));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_uint32_118", 118));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sfixed64_uint64_119", 119));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_bool_120", 120));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_bytes_121", 121));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_double_122", 122));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_enum_123", 123));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_fixed32_124", 124));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_fixed64_125", 125));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_float_126", 126));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_int32_127", 127));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_int64_128", 128));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_message_129", 129));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sfixed32_130", 130));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sfixed64_131", 131));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sint32_132", 132));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_sint64_133", 133));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_string_134", 134));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_uint32_135", 135));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint32_uint64_136", 136));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_bool_137", 137));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_bytes_138", 138));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_double_139", 139));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_enum_140", 140));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_fixed32_141", 141));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_fixed64_142", 142));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_float_143", 143));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_int32_144", 144));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_int64_145", 145));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_message_146", 146));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sfixed32_147", 147));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sfixed64_148", 148));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sint32_149", 149));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_sint64_150", 150));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_string_151", 151));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_uint32_152", 152));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_sint64_uint64_153", 153));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_bool_154", 154));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_bytes_155", 155));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_double_156", 156));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_enum_157", 157));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_fixed32_158", 158));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_fixed64_159", 159));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_float_160", 160));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_int32_161", 161));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_int64_162", 162));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_message_163", 163));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sfixed32_164", 164));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sfixed64_165", 165));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sint32_166", 166));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_sint64_167", 167));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_string_168", 168));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_uint32_169", 169));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_string_uint64_170", 170));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_bool_171", 171));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_bytes_172", 172));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_double_173", 173));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_enum_174", 174));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_fixed32_175", 175));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_fixed64_176", 176));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_float_177", 177));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_int32_178", 178));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_int64_179", 179));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_message_180", 180));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sfixed32_181", 181));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sfixed64_182", 182));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sint32_183", 183));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_sint64_184", 184));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_string_185", 185));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_uint32_186", 186));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint32_uint64_187", 187));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_bool_188", 188));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_bytes_189", 189));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_double_190", 190));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_enum_191", 191));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_fixed32_192", 192));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_fixed64_193", 193));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_float_194", 194));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_int32_195", 195));
-    builder.withField(mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_int64_196", 196));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_message_197", 197));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sfixed32_198", 198));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sfixed64_199", 199));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sint32_200", 200));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_sint64_201", 201));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_string_202", 202));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint32_203", 203));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint64_204", 204));
-
-    return builder.build();
-  }
-
-  private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) {
-    try {
-      return forMapField(
-          field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"),
-          fieldNumber,
-          SchemaUtil.getMapDefaultEntry(clazz, fieldName),
-          fieldName.contains("_enum_") ? asVerifier(TestEnum.internalGetValueMap()) : null);
-    } catch (Throwable t) {
-      throw new RuntimeException(t);
-    }
-  }
-
-
-  private static Field field(String name) {
-    return field(Proto2Message.class, name);
-  }
-
-  private static Field field(Class<?> clazz, String name) {
-    try {
-      return clazz.getDeclaredField(name);
-    } catch (NoSuchFieldException | SecurityException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private static Internal.EnumVerifier asVerifier(final Internal.EnumLiteMap<?> map) {
-    return new Internal.EnumVerifier() {
-      @Override
-      public boolean isInRange(int number) {
-        return map.findValueByNumber(number) != null;
-      }
-    };
-  }
-}
diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java
deleted file mode 100644
index 364071b..0000000
--- a/java/core/src/test/java/com/google/protobuf/Proto3MessageInfoFactory.java
+++ /dev/null
@@ -1,506 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static com.google.protobuf.FieldInfo.forField;
-import static com.google.protobuf.FieldInfo.forMapField;
-import static com.google.protobuf.FieldInfo.forOneofMemberField;
-import static com.google.protobuf.FieldInfo.forRepeatedMessageField;
-
-import com.google.protobuf.testing.Proto2Testing.Proto2MessageWithMaps;
-import com.google.protobuf.testing.Proto3Testing.Proto3Empty;
-import com.google.protobuf.testing.Proto3Testing.Proto3Message;
-import com.google.protobuf.testing.Proto3Testing.Proto3MessageWithMaps;
-import java.lang.reflect.Field;
-
-/** A factory that generates a hard-coded info for {@link Proto3Message}. */
-public final class Proto3MessageInfoFactory implements MessageInfoFactory {
-  private static final Proto3MessageInfoFactory INSTANCE = new Proto3MessageInfoFactory();
-
-  private Proto3MessageInfoFactory() {}
-
-  public static Proto3MessageInfoFactory getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public boolean isSupported(Class<?> clazz) {
-    return true;
-  }
-
-  @Override
-  public MessageInfo messageInfoFor(Class<?> clazz) {
-    if (Proto3Message.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3Message();
-    } else if (Proto3Empty.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3Empty();
-    } else if (Proto3MessageWithMaps.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3MessageWithMaps();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  /**
-   * Creates a new hard-coded info for {@link Proto3Message}. Each time this is called, we manually
-   * go through the entire process of what a message would do if it self-registered its own info,
-   * including looking up each field by name. This is done for benchmarking purposes, so that we get
-   * a more accurate representation of the time it takes to perform this process.
-   */
-  private static StructuralMessageInfo newMessageInfoForProto3Message() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48);
-    lookupFieldsByName(builder);
-    return builder.build();
-  }
-
-  private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) {
-    builder.withDefaultInstance(Proto3Message.getDefaultInstance());
-    builder.withSyntax(ProtoSyntax.PROTO3);
-    builder.withField(forField(field("fieldDouble1_"), 1, FieldType.DOUBLE, true));
-    builder.withField(forField(field("fieldFloat2_"), 2, FieldType.FLOAT, true));
-    builder.withField(forField(field("fieldInt643_"), 3, FieldType.INT64, true));
-    builder.withField(forField(field("fieldUint644_"), 4, FieldType.UINT64, true));
-    builder.withField(forField(field("fieldInt325_"), 5, FieldType.INT32, true));
-    builder.withField(forField(field("fieldFixed646_"), 6, FieldType.FIXED64, true));
-    builder.withField(forField(field("fieldFixed327_"), 7, FieldType.FIXED32, true));
-    builder.withField(forField(field("fieldBool8_"), 8, FieldType.BOOL, true));
-    builder.withField(forField(field("fieldString9_"), 9, FieldType.STRING, true));
-    builder.withField(forField(field("fieldMessage10_"), 10, FieldType.MESSAGE, true));
-    builder.withField(forField(field("fieldBytes11_"), 11, FieldType.BYTES, true));
-    builder.withField(forField(field("fieldUint3212_"), 12, FieldType.UINT32, true));
-    builder.withField(forField(field("fieldEnum13_"), 13, FieldType.ENUM, true));
-    builder.withField(forField(field("fieldSfixed3214_"), 14, FieldType.SFIXED32, true));
-    builder.withField(forField(field("fieldSfixed6415_"), 15, FieldType.SFIXED64, true));
-    builder.withField(forField(field("fieldSint3216_"), 16, FieldType.SINT32, true));
-    builder.withField(forField(field("fieldSint6417_"), 17, FieldType.SINT64, true));
-    builder.withField(forField(field("fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, true));
-    builder.withField(forField(field("fieldFloatList19_"), 19, FieldType.FLOAT_LIST, true));
-    builder.withField(forField(field("fieldInt64List20_"), 20, FieldType.INT64_LIST, true));
-    builder.withField(forField(field("fieldUint64List21_"), 21, FieldType.UINT64_LIST, true));
-    builder.withField(forField(field("fieldInt32List22_"), 22, FieldType.INT32_LIST, true));
-    builder.withField(forField(field("fieldFixed64List23_"), 23, FieldType.FIXED64_LIST, true));
-    builder.withField(forField(field("fieldFixed32List24_"), 24, FieldType.FIXED32_LIST, true));
-    builder.withField(forField(field("fieldBoolList25_"), 25, FieldType.BOOL_LIST, true));
-    builder.withField(forField(field("fieldStringList26_"), 26, FieldType.STRING_LIST, true));
-    builder.withField(
-        forRepeatedMessageField(
-            field("fieldMessageList27_"), 27, FieldType.MESSAGE_LIST, Proto3Message.class));
-    builder.withField(forField(field("fieldBytesList28_"), 28, FieldType.BYTES_LIST, true));
-    builder.withField(forField(field("fieldUint32List29_"), 29, FieldType.UINT32_LIST, true));
-    builder.withField(forField(field("fieldEnumList30_"), 30, FieldType.ENUM_LIST, true));
-    builder.withField(forField(field("fieldSfixed32List31_"), 31, FieldType.SFIXED32_LIST, true));
-    builder.withField(forField(field("fieldSfixed64List32_"), 32, FieldType.SFIXED64_LIST, true));
-    builder.withField(forField(field("fieldSint32List33_"), 33, FieldType.SINT32_LIST, true));
-    builder.withField(forField(field("fieldSint64List34_"), 34, FieldType.SINT64_LIST, true));
-    builder.withField(
-        forField(field("fieldDoubleListPacked35_"), 35, FieldType.DOUBLE_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldFloatListPacked36_"), 36, FieldType.FLOAT_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldInt64ListPacked37_"), 37, FieldType.INT64_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldUint64ListPacked38_"), 38, FieldType.UINT64_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldInt32ListPacked39_"), 39, FieldType.INT32_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldFixed64ListPacked40_"), 40, FieldType.FIXED64_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldFixed32ListPacked41_"), 41, FieldType.FIXED32_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldBoolListPacked42_"), 42, FieldType.BOOL_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldUint32ListPacked43_"), 43, FieldType.UINT32_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldEnumListPacked44_"), 44, FieldType.ENUM_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldSfixed32ListPacked45_"), 45, FieldType.SFIXED32_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldSfixed64ListPacked46_"), 46, FieldType.SFIXED64_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldSint32ListPacked47_"), 47, FieldType.SINT32_LIST_PACKED, true));
-    builder.withField(
-        forField(field("fieldSint64ListPacked48_"), 48, FieldType.SINT64_LIST_PACKED, true));
-
-    OneofInfo oneof = new OneofInfo(0, field("testOneofCase_"), field("testOneof_"));
-    builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, true, null));
-    builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, true, null));
-    builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, true, null));
-    builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, true, null));
-    builder.withField(
-        forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto3Message.class, true, null));
-    builder.withField(
-        forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, true, null));
-    builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, true, null));
-    builder.withField(
-        forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, true, null));
-  }
-
-  private StructuralMessageInfo newMessageInfoForProto3Empty() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO3);
-    return builder.build();
-  }
-
-  private StructuralMessageInfo newMessageInfoForProto3MessageWithMaps() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder();
-    builder.withSyntax(ProtoSyntax.PROTO3);
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_bool_1", 1));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_bytes_2", 2));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_double_3", 3));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_enum_4", 4));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_fixed32_5", 5));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_fixed64_6", 6));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_float_7", 7));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_int32_8", 8));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_int64_9", 9));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_message_10", 10));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sfixed32_11", 11));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sfixed64_12", 12));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sint32_13", 13));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_sint64_14", 14));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_string_15", 15));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_uint32_16", 16));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_bool_uint64_17", 17));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_bool_18", 18));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_bytes_19", 19));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_double_20", 20));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_enum_21", 21));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_fixed32_22", 22));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_fixed64_23", 23));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_float_24", 24));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_int32_25", 25));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_int64_26", 26));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_message_27", 27));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sfixed32_28", 28));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sfixed64_29", 29));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sint32_30", 30));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_sint64_31", 31));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_string_32", 32));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_uint32_33", 33));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed32_uint64_34", 34));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_bool_35", 35));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_bytes_36", 36));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_double_37", 37));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_enum_38", 38));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_fixed32_39", 39));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_fixed64_40", 40));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_float_41", 41));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_int32_42", 42));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_int64_43", 43));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_message_44", 44));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sfixed32_45", 45));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sfixed64_46", 46));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sint32_47", 47));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_sint64_48", 48));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_string_49", 49));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_uint32_50", 50));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_fixed64_uint64_51", 51));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_bool_52", 52));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_bytes_53", 53));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_double_54", 54));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_enum_55", 55));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_fixed32_56", 56));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_fixed64_57", 57));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_float_58", 58));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_int32_59", 59));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_int64_60", 60));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_message_61", 61));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sfixed32_62", 62));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sfixed64_63", 63));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sint32_64", 64));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_sint64_65", 65));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_string_66", 66));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_uint32_67", 67));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int32_uint64_68", 68));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_bool_69", 69));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_bytes_70", 70));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_double_71", 71));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_enum_72", 72));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_fixed32_73", 73));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_fixed64_74", 74));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_float_75", 75));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_int32_76", 76));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_int64_77", 77));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_message_78", 78));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sfixed32_79", 79));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sfixed64_80", 80));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sint32_81", 81));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_sint64_82", 82));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_string_83", 83));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_uint32_84", 84));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_int64_uint64_85", 85));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_bool_86", 86));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_bytes_87", 87));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_double_88", 88));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_enum_89", 89));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_fixed32_90", 90));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_fixed64_91", 91));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_float_92", 92));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_int32_93", 93));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_int64_94", 94));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_message_95", 95));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sfixed32_96", 96));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sfixed64_97", 97));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sint32_98", 98));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_sint64_99", 99));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_string_100", 100));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_uint32_101", 101));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed32_uint64_102", 102));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_bool_103", 103));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_bytes_104", 104));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_double_105", 105));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_enum_106", 106));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_fixed32_107", 107));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_fixed64_108", 108));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_float_109", 109));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_int32_110", 110));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_int64_111", 111));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_message_112", 112));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sfixed32_113", 113));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sfixed64_114", 114));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sint32_115", 115));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_sint64_116", 116));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_string_117", 117));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_uint32_118", 118));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sfixed64_uint64_119", 119));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_bool_120", 120));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_bytes_121", 121));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_double_122", 122));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_enum_123", 123));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_fixed32_124", 124));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_fixed64_125", 125));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_float_126", 126));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_int32_127", 127));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_int64_128", 128));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_message_129", 129));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sfixed32_130", 130));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sfixed64_131", 131));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sint32_132", 132));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_sint64_133", 133));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_string_134", 134));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_uint32_135", 135));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint32_uint64_136", 136));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_bool_137", 137));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_bytes_138", 138));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_double_139", 139));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_enum_140", 140));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_fixed32_141", 141));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_fixed64_142", 142));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_float_143", 143));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_int32_144", 144));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_int64_145", 145));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_message_146", 146));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sfixed32_147", 147));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sfixed64_148", 148));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sint32_149", 149));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_sint64_150", 150));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_string_151", 151));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_uint32_152", 152));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_sint64_uint64_153", 153));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_bool_154", 154));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_bytes_155", 155));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_double_156", 156));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_enum_157", 157));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_fixed32_158", 158));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_fixed64_159", 159));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_float_160", 160));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_int32_161", 161));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_int64_162", 162));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_message_163", 163));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sfixed32_164", 164));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sfixed64_165", 165));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sint32_166", 166));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_sint64_167", 167));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_string_168", 168));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_uint32_169", 169));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_string_uint64_170", 170));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_bool_171", 171));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_bytes_172", 172));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_double_173", 173));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_enum_174", 174));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_fixed32_175", 175));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_fixed64_176", 176));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_float_177", 177));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_int32_178", 178));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_int64_179", 179));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_message_180", 180));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sfixed32_181", 181));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sfixed64_182", 182));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sint32_183", 183));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_sint64_184", 184));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_string_185", 185));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_uint32_186", 186));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint32_uint64_187", 187));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_bool_188", 188));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_bytes_189", 189));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_double_190", 190));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_enum_191", 191));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_fixed32_192", 192));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_fixed64_193", 193));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_float_194", 194));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_int32_195", 195));
-    builder.withField(mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_int64_196", 196));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_message_197", 197));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sfixed32_198", 198));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sfixed64_199", 199));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sint32_200", 200));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_sint64_201", 201));
-    builder.withField(
-        mapFieldInfo(Proto3MessageWithMaps.class, "field_map_uint64_string_202", 202));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint32_203", 203));
-    builder.withField(
-        mapFieldInfo(Proto2MessageWithMaps.class, "field_map_uint64_uint64_204", 204));
-    return builder.build();
-  }
-
-  private static Field field(String name) {
-    return field(Proto3Message.class, name);
-  }
-
-  private static Field field(Class<?> clazz, String name) {
-    try {
-      return clazz.getDeclaredField(name);
-    } catch (NoSuchFieldException | SecurityException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) {
-    try {
-      return forMapField(
-          field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"),
-          fieldNumber,
-          SchemaUtil.getMapDefaultEntry(clazz, fieldName),
-          null);
-    } catch (Throwable t) {
-      throw new RuntimeException(t);
-    }
-  }
-}
diff --git a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java b/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java
deleted file mode 100644
index 3c0c629..0000000
--- a/java/core/src/test/java/com/google/protobuf/Proto3MessageLiteInfoFactory.java
+++ /dev/null
@@ -1,816 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static com.google.protobuf.FieldInfo.forField;
-import static com.google.protobuf.FieldInfo.forMapField;
-import static com.google.protobuf.FieldInfo.forOneofMemberField;
-import static com.google.protobuf.FieldInfo.forRepeatedMessageField;
-
-import com.google.protobuf.testing.Proto3TestingLite.Proto3EmptyLite;
-import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLite;
-import com.google.protobuf.testing.Proto3TestingLite.Proto3MessageLiteWithMaps;
-import java.lang.reflect.Field;
-
-/** A factory that generates a hard-coded info for {@link Proto3MessageLite}. */
-public final class Proto3MessageLiteInfoFactory implements MessageInfoFactory {
-  private static final Proto3MessageLiteInfoFactory instanceForRawMessageInfo =
-      new Proto3MessageLiteInfoFactory(true);
-  private static final Proto3MessageLiteInfoFactory instanceForStructuralMessageInfo =
-      new Proto3MessageLiteInfoFactory(false);
-
-  public static Proto3MessageLiteInfoFactory getInstanceForRawMessageInfo() {
-    return instanceForRawMessageInfo;
-  }
-
-  public static Proto3MessageLiteInfoFactory getInstanceForStructuralMessageInfo() {
-    return instanceForStructuralMessageInfo;
-  }
-
-  private final boolean produceRawMessageInfo;
-
-  private Proto3MessageLiteInfoFactory(boolean produceRawMessageInfo) {
-    this.produceRawMessageInfo = produceRawMessageInfo;
-  }
-
-  @Override
-  public boolean isSupported(Class<?> clazz) {
-    return true;
-  }
-
-  @Override
-  public MessageInfo messageInfoFor(Class<?> clazz) {
-    return produceRawMessageInfo ? rawMessageInfoFor(clazz) : structuralMessageInfoFor(clazz);
-  }
-
-  private MessageInfo rawMessageInfoFor(Class<?> clazz) {
-    if (Proto3MessageLite.class.isAssignableFrom(clazz)) {
-      return newRawMessageInfoForProto3MessageLite();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  private MessageInfo newRawMessageInfoForProto3MessageLite() {
-    java.lang.Object[] objects =
-        new java.lang.Object[] {
-          "testOneof_",
-          "testOneofCase_",
-          "fieldDouble1_",
-          "fieldFloat2_",
-          "fieldInt643_",
-          "fieldUint644_",
-          "fieldInt325_",
-          "fieldFixed646_",
-          "fieldFixed327_",
-          "fieldBool8_",
-          "fieldString9_",
-          "fieldMessage10_",
-          "fieldBytes11_",
-          "fieldUint3212_",
-          "fieldEnum13_",
-          "fieldSfixed3214_",
-          "fieldSfixed6415_",
-          "fieldSint3216_",
-          "fieldSint6417_",
-          "fieldDoubleList18_",
-          "fieldFloatList19_",
-          "fieldInt64List20_",
-          "fieldUint64List21_",
-          "fieldInt32List22_",
-          "fieldFixed64List23_",
-          "fieldFixed32List24_",
-          "fieldBoolList25_",
-          "fieldStringList26_",
-          "fieldMessageList27_",
-          Proto3MessageLite.class,
-          "fieldBytesList28_",
-          "fieldUint32List29_",
-          "fieldEnumList30_",
-          "fieldSfixed32List31_",
-          "fieldSfixed64List32_",
-          "fieldSint32List33_",
-          "fieldSint64List34_",
-          "fieldDoubleListPacked35_",
-          "fieldFloatListPacked36_",
-          "fieldInt64ListPacked37_",
-          "fieldUint64ListPacked38_",
-          "fieldInt32ListPacked39_",
-          "fieldFixed64ListPacked40_",
-          "fieldFixed32ListPacked41_",
-          "fieldBoolListPacked42_",
-          "fieldUint32ListPacked43_",
-          "fieldEnumListPacked44_",
-          "fieldSfixed32ListPacked45_",
-          "fieldSfixed64ListPacked46_",
-          "fieldSint32ListPacked47_",
-          "fieldSint64ListPacked48_",
-          Proto3MessageLite.class,
-        };
-    // To update this after a proto change, run protoc on proto3_message_lite.proto and copy over
-    // the content of the generated buildMessageInfo() method here.
-    java.lang.String info =
-        "\u0000@\u0001\u0000\u0001D@\u0000\u001f\u0000\u0001\u0000\u0002\u0001\u0003\u0002"
-        + "\u0004\u0003\u0005\u0004\u0006\u0005\u0007\u0006\b\u0007\t\u0208\n\t\u000b\n\f\u000b"
-        + "\r\f\u000e\r\u000f\u000e\u0010\u000f\u0011\u0010\u0012\u0012\u0013\u0013\u0014\u0014"
-        + "\u0015\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u021a\u001b\u001b"
-        + "\u001c\u001c\u001d\u001d\u001e\u001e\u001f\u001f  !!\"\"##$$%%&&\'\'(())**++,,--"
-        + "..//0053\u000064\u000075\u000086\u000097\u0000:8\u0000;9\u0000<:\u0000=\u023b\u0000"
-        + "><\u0000?=\u0000@>\u0000A@\u0000BA\u0000CB\u0000DC\u0000";
-    return new RawMessageInfo(Proto3MessageLite.getDefaultInstance(), info, objects);
-  }
-
-  private MessageInfo structuralMessageInfoFor(Class<?> clazz) {
-    if (Proto3MessageLite.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3MessageLite();
-    } else if (Proto3EmptyLite.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3EmptyLite();
-    } else if (Proto3MessageLiteWithMaps.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto3MessageLiteWithMaps();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  /**
-   * Creates a new hard-coded info for {@link Proto3MessageLite}. Each time this is called, we
-   * manually go through the entire process of what a message would do if it self-registered its own
-   * info, including looking up each field by name. This is done for benchmarking purposes, so that
-   * we get a more accurate representation of the time it takes to perform this process.
-   */
-  private static StructuralMessageInfo newMessageInfoForProto3MessageLite() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48);
-    lookupFieldsByName(builder);
-    return builder.build();
-  }
-
-  private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) {
-    builder.withDefaultInstance(Proto3MessageLite.getDefaultInstance());
-    builder.withSyntax(ProtoSyntax.PROTO3);
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldDouble1_"), 1, FieldType.DOUBLE, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldFloat2_"), 2, FieldType.FLOAT, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldInt643_"), 3, FieldType.INT64, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldUint644_"), 4, FieldType.UINT64, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldInt325_"), 5, FieldType.INT32, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldFixed646_"), 6, FieldType.FIXED64, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldFixed327_"), 7, FieldType.FIXED32, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldBool8_"), 8, FieldType.BOOL, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldString9_"), 9, FieldType.STRING, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldMessage10_"), 10, FieldType.MESSAGE, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldBytes11_"), 11, FieldType.BYTES, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldUint3212_"), 12, FieldType.UINT32, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldEnum13_"), 13, FieldType.ENUM, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldSfixed3214_"), 14, FieldType.SFIXED32, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldSfixed6415_"), 15, FieldType.SFIXED64, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldSint3216_"), 16, FieldType.SINT32, true));
-    builder.withField(
-        forField(field(Proto3MessageLite.class, "fieldSint6417_"), 17, FieldType.SINT64, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldDoubleList18_"), 18, FieldType.DOUBLE_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFloatList19_"), 19, FieldType.FLOAT_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldInt64List20_"), 20, FieldType.INT64_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldUint64List21_"), 21, FieldType.UINT64_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldInt32List22_"), 22, FieldType.INT32_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFixed64List23_"),
-            23,
-            FieldType.FIXED64_LIST,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFixed32List24_"),
-            24,
-            FieldType.FIXED32_LIST,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldBoolList25_"), 25, FieldType.BOOL_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldStringList26_"), 26, FieldType.STRING_LIST, true));
-    builder.withField(
-        forRepeatedMessageField(
-            field(Proto3MessageLite.class, "fieldMessageList27_"),
-            27,
-            FieldType.MESSAGE_LIST,
-            Proto3MessageLite.class));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldBytesList28_"), 28, FieldType.BYTES_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldUint32List29_"), 29, FieldType.UINT32_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldEnumList30_"), 30, FieldType.ENUM_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSfixed32List31_"),
-            31,
-            FieldType.SFIXED32_LIST,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSfixed64List32_"),
-            32,
-            FieldType.SFIXED64_LIST,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSint32List33_"), 33, FieldType.SINT32_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSint64List34_"), 34, FieldType.SINT64_LIST, true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldDoubleListPacked35_"),
-            35,
-            FieldType.DOUBLE_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFloatListPacked36_"),
-            36,
-            FieldType.FLOAT_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldInt64ListPacked37_"),
-            37,
-            FieldType.INT64_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldUint64ListPacked38_"),
-            38,
-            FieldType.UINT64_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldInt32ListPacked39_"),
-            39,
-            FieldType.INT32_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFixed64ListPacked40_"),
-            40,
-            FieldType.FIXED64_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldFixed32ListPacked41_"),
-            41,
-            FieldType.FIXED32_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldBoolListPacked42_"),
-            42,
-            FieldType.BOOL_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldUint32ListPacked43_"),
-            43,
-            FieldType.UINT32_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldEnumListPacked44_"),
-            44,
-            FieldType.ENUM_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSfixed32ListPacked45_"),
-            45,
-            FieldType.SFIXED32_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSfixed64ListPacked46_"),
-            46,
-            FieldType.SFIXED64_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSint32ListPacked47_"),
-            47,
-            FieldType.SINT32_LIST_PACKED,
-            true));
-    builder.withField(
-        forField(
-            field(Proto3MessageLite.class, "fieldSint64ListPacked48_"),
-            48,
-            FieldType.SINT64_LIST_PACKED,
-            true));
-
-    OneofInfo oneof =
-        new OneofInfo(
-            0,
-            field(Proto3MessageLite.class, "testOneofCase_"),
-            field(Proto3MessageLite.class, "testOneof_"));
-    builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, true, null));
-    builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, true, null));
-    builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, true, null));
-    builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, true, null));
-    builder.withField(
-        forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto3MessageLite.class, true, null));
-    builder.withField(
-        forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, true, null));
-    builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, true, null));
-    builder.withField(
-        forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, true, null));
-    builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, true, null));
-    builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, true, null));
-  }
-
-  private StructuralMessageInfo newMessageInfoForProto3EmptyLite() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO3);
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto3MessageLiteWithMaps() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder();
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_bool_1", 1));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_bytes_2", 2));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_double_3", 3));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_enum_4", 4));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_fixed32_5", 5));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_fixed64_6", 6));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_float_7", 7));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_int32_8", 8));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_int64_9", 9));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_message_10", 10));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sfixed32_11", 11));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sfixed64_12", 12));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sint32_13", 13));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_sint64_14", 14));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_string_15", 15));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_uint32_16", 16));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_bool_uint64_17", 17));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_bool_18", 18));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_bytes_19", 19));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_double_20", 20));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_enum_21", 21));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_fixed32_22", 22));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_fixed64_23", 23));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_float_24", 24));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_int32_25", 25));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_int64_26", 26));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_message_27", 27));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sfixed32_28", 28));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sfixed64_29", 29));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sint32_30", 30));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_sint64_31", 31));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_string_32", 32));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_uint32_33", 33));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed32_uint64_34", 34));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_bool_35", 35));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_bytes_36", 36));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_double_37", 37));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_enum_38", 38));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_fixed32_39", 39));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_fixed64_40", 40));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_float_41", 41));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_int32_42", 42));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_int64_43", 43));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_message_44", 44));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sfixed32_45", 45));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sfixed64_46", 46));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sint32_47", 47));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_sint64_48", 48));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_string_49", 49));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_uint32_50", 50));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_fixed64_uint64_51", 51));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_bool_52", 52));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_bytes_53", 53));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_double_54", 54));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_enum_55", 55));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_fixed32_56", 56));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_fixed64_57", 57));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_float_58", 58));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_int32_59", 59));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_int64_60", 60));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_message_61", 61));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sfixed32_62", 62));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sfixed64_63", 63));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sint32_64", 64));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_sint64_65", 65));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_string_66", 66));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_uint32_67", 67));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int32_uint64_68", 68));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_bool_69", 69));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_bytes_70", 70));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_double_71", 71));
-    builder.withField(mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_enum_72", 72));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_fixed32_73", 73));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_fixed64_74", 74));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_float_75", 75));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_int32_76", 76));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_int64_77", 77));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_message_78", 78));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sfixed32_79", 79));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sfixed64_80", 80));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sint32_81", 81));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_sint64_82", 82));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_string_83", 83));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_uint32_84", 84));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_int64_uint64_85", 85));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_bool_86", 86));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_bytes_87", 87));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_double_88", 88));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_enum_89", 89));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_fixed32_90", 90));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_fixed64_91", 91));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_float_92", 92));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_int32_93", 93));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_int64_94", 94));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_message_95", 95));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sfixed32_96", 96));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sfixed64_97", 97));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sint32_98", 98));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_sint64_99", 99));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_string_100", 100));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_uint32_101", 101));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed32_uint64_102", 102));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_bool_103", 103));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_bytes_104", 104));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_double_105", 105));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_enum_106", 106));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_fixed32_107", 107));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_fixed64_108", 108));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_float_109", 109));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_int32_110", 110));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_int64_111", 111));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_message_112", 112));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sfixed32_113", 113));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sfixed64_114", 114));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sint32_115", 115));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_sint64_116", 116));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_string_117", 117));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_uint32_118", 118));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sfixed64_uint64_119", 119));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_bool_120", 120));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_bytes_121", 121));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_double_122", 122));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_enum_123", 123));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_fixed32_124", 124));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_fixed64_125", 125));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_float_126", 126));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_int32_127", 127));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_int64_128", 128));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_message_129", 129));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sfixed32_130", 130));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sfixed64_131", 131));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sint32_132", 132));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_sint64_133", 133));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_string_134", 134));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_uint32_135", 135));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint32_uint64_136", 136));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_bool_137", 137));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_bytes_138", 138));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_double_139", 139));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_enum_140", 140));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_fixed32_141", 141));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_fixed64_142", 142));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_float_143", 143));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_int32_144", 144));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_int64_145", 145));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_message_146", 146));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sfixed32_147", 147));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sfixed64_148", 148));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sint32_149", 149));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_sint64_150", 150));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_string_151", 151));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_uint32_152", 152));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_sint64_uint64_153", 153));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_bool_154", 154));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_bytes_155", 155));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_double_156", 156));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_enum_157", 157));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_fixed32_158", 158));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_fixed64_159", 159));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_float_160", 160));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_int32_161", 161));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_int64_162", 162));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_message_163", 163));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sfixed32_164", 164));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sfixed64_165", 165));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sint32_166", 166));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_sint64_167", 167));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_string_168", 168));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_uint32_169", 169));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_string_uint64_170", 170));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_bool_171", 171));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_bytes_172", 172));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_double_173", 173));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_enum_174", 174));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_fixed32_175", 175));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_fixed64_176", 176));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_float_177", 177));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_int32_178", 178));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_int64_179", 179));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_message_180", 180));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sfixed32_181", 181));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sfixed64_182", 182));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sint32_183", 183));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_sint64_184", 184));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_string_185", 185));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_uint32_186", 186));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint32_uint64_187", 187));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_bool_188", 188));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_bytes_189", 189));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_double_190", 190));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_enum_191", 191));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_fixed32_192", 192));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_fixed64_193", 193));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_float_194", 194));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_int32_195", 195));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_int64_196", 196));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_message_197", 197));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sfixed32_198", 198));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sfixed64_199", 199));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sint32_200", 200));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_sint64_201", 201));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_string_202", 202));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_uint32_203", 203));
-    builder.withField(
-        mapFieldInfo(Proto3MessageLiteWithMaps.class, "field_map_uint64_uint64_204", 204));
-
-    return builder.build();
-  }
-
-  private static Field field(Class<?> clazz, String name) {
-    try {
-      return clazz.getDeclaredField(name);
-    } catch (NoSuchFieldException | SecurityException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) {
-    try {
-      return forMapField(
-          field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"),
-          fieldNumber,
-          SchemaUtil.getMapDefaultEntry(clazz, fieldName),
-          null);
-    } catch (Throwable t) {
-      throw new RuntimeException(t);
-    }
-  }
-}
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/UnknownFieldSetPerformanceTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java
new file mode 100644
index 0000000..6ce0fc7
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java
@@ -0,0 +1,78 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class UnknownFieldSetPerformanceTest {
+
+  private static byte[] generateBytes(int length) {
+    assertThat(length % 4).isEqualTo(0);
+    byte[] input = new byte[length];
+    for (int i = 0; i < length; i += 4) {
+        input[i] =     (byte) 0x08; // field 1, wiretype 0
+        input[i + 1] = (byte) 0x08; // field 1, payload 8
+        input[i + 2] = (byte) 0x20; // field 4, wiretype 0
+        input[i + 3] = (byte) 0x20; // field 4, payload 32
+    }
+    return input;
+  }
+
+  @Test
+  // This is a performance test. Failure here is a timeout.
+  public void testAlternatingFieldNumbers() throws IOException {
+    byte[] input = generateBytes(800000);
+    InputStream in = new ByteArrayInputStream(input);
+    UnknownFieldSet.Builder builder = UnknownFieldSet.newBuilder();
+    CodedInputStream codedInput = CodedInputStream.newInstance(in);
+    builder.mergeFrom(codedInput);
+  }
+
+  @Test
+  // This is a performance test. Failure here is a timeout.
+  public void testAddField() {
+    UnknownFieldSet.Builder builder = UnknownFieldSet.newBuilder();
+    for (int i = 1; i <= 100000; i++) {
+      UnknownFieldSet.Field field = UnknownFieldSet.Field.newBuilder().addFixed32(i).build();
+      builder.addField(i, field);
+    }
+    UnknownFieldSet fieldSet = builder.build();
+    assertThat(fieldSet.getField(100000).getFixed32List().get(0)).isEqualTo(100000);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index 1e5bc96..fbc3bb8 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -42,7 +42,9 @@
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import proto3_unittest.UnittestProto3;
+import java.util.List;
 import java.util.Map;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -61,7 +63,7 @@
     unknownFields = emptyMessage.getUnknownFields();
   }
 
-  UnknownFieldSet.Field getField(String name) {
+  private UnknownFieldSet.Field getField(String name) {
     Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
     assertThat(field).isNotNull();
     return unknownFields.getField(field.getNumber());
@@ -101,6 +103,174 @@
   // =================================================================
 
   @Test
+  public void testFieldBuildersAreReusable() {
+    UnknownFieldSet.Field.Builder fieldBuilder = UnknownFieldSet.Field.newBuilder();
+    fieldBuilder.addFixed32(10);
+    UnknownFieldSet.Field first = fieldBuilder.build();
+    UnknownFieldSet.Field second = fieldBuilder.build();
+    fieldBuilder.addFixed32(11);
+    UnknownFieldSet.Field third = fieldBuilder.build();
+
+    assertThat(first).isEqualTo(second);
+    assertThat(first).isNotEqualTo(third);
+  }
+
+  @Test
+  public void testClone() {
+    UnknownFieldSet.Builder unknownSetBuilder = UnknownFieldSet.newBuilder();
+    UnknownFieldSet.Field.Builder fieldBuilder = UnknownFieldSet.Field.newBuilder();
+    fieldBuilder.addFixed32(10);
+    unknownSetBuilder.addField(8, fieldBuilder.build());
+    // necessary to call clone twice to expose the bug
+    UnknownFieldSet.Builder clone1 = unknownSetBuilder.clone();
+    UnknownFieldSet.Builder clone2 = unknownSetBuilder.clone(); // failure is a NullPointerException
+    assertThat(clone1).isNotSameInstanceAs(clone2);
+  }
+
+  @Test
+  public void testClone_lengthDelimited() {
+    UnknownFieldSet.Builder destUnknownFieldSet =
+        UnknownFieldSet.newBuilder()
+            .addField(997, UnknownFieldSet.Field.newBuilder().addVarint(99).build())
+            .addField(
+                999,
+                UnknownFieldSet.Field.newBuilder()
+                    .addLengthDelimited(ByteString.copyFromUtf8("some data"))
+                    .addLengthDelimited(ByteString.copyFromUtf8("some more data"))
+                    .build());
+    UnknownFieldSet clone = destUnknownFieldSet.clone().build();
+    assertThat(clone.getField(997)).isNotNull();
+    UnknownFieldSet.Field field999 = clone.getField(999);
+    List<ByteString> lengthDelimited = field999.getLengthDelimitedList();
+    assertThat(lengthDelimited.get(0).toStringUtf8()).isEqualTo("some data");
+    assertThat(lengthDelimited.get(1).toStringUtf8()).isEqualTo("some more data");
+
+    UnknownFieldSet clone2 = destUnknownFieldSet.clone().build();
+    assertThat(clone2.getField(997)).isNotNull();
+    UnknownFieldSet.Field secondField = clone2.getField(999);
+    List<ByteString> lengthDelimited2 = secondField.getLengthDelimitedList();
+    assertThat(lengthDelimited2.get(0).toStringUtf8()).isEqualTo("some data");
+    assertThat(lengthDelimited2.get(1).toStringUtf8()).isEqualTo("some more data");
+  }
+
+  @Test
+  public void testReuse() {
+    UnknownFieldSet.Builder builder =
+        UnknownFieldSet.newBuilder()
+            .addField(997, UnknownFieldSet.Field.newBuilder().addVarint(99).build())
+            .addField(
+                999,
+                UnknownFieldSet.Field.newBuilder()
+                    .addLengthDelimited(ByteString.copyFromUtf8("some data"))
+                    .addLengthDelimited(ByteString.copyFromUtf8("some more data"))
+                    .build());
+
+    UnknownFieldSet fieldSet1 = builder.build();
+    UnknownFieldSet fieldSet2 = builder.build();
+    builder.addField(1000, UnknownFieldSet.Field.newBuilder().addVarint(-90).build());
+    UnknownFieldSet fieldSet3 = builder.build();
+
+    assertThat(fieldSet1).isEqualTo(fieldSet2);
+    assertThat(fieldSet1).isNotEqualTo(fieldSet3);
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testAddField_zero() {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    try {
+      UnknownFieldSet.newBuilder().addField(0, field);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("0 is not a valid field number.");
+    }
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testAddField_negative() {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    try {
+      UnknownFieldSet.newBuilder().addField(-2, field);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
+    }
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testClearField_negative() {
+    try {
+      UnknownFieldSet.newBuilder().clearField(-28);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("-28 is not a valid field number.");
+    }
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testMergeField_negative() {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    try {
+      UnknownFieldSet.newBuilder().mergeField(-2, field);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
+    }
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testMergeVarintField_negative() {
+    try {
+      UnknownFieldSet.newBuilder().mergeVarintField(-2, 78);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
+    }
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testHasField_negative() {
+    assertThat(UnknownFieldSet.newBuilder().hasField(-2)).isFalse();
+  }
+
+  @Test
+  @SuppressWarnings("ModifiedButNotUsed")
+  public void testMergeLengthDelimitedField_negative() {
+    ByteString byteString = ByteString.copyFromUtf8("some data");
+    try {
+      UnknownFieldSet.newBuilder().mergeLengthDelimitedField(-2, byteString);
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
+    }
+  }
+
+  @Test
+  public void testAddField() {
+    UnknownFieldSet.Field field = getField("optional_int32");
+    UnknownFieldSet fieldSet = UnknownFieldSet.newBuilder().addField(1, field).build();
+    assertThat(fieldSet.getField(1)).isEqualTo(field);
+  }
+
+  @Test
+  public void testAddField_withReplacement() {
+    UnknownFieldSet.Field first = UnknownFieldSet.Field.newBuilder().addFixed32(56).build();
+    UnknownFieldSet.Field second = UnknownFieldSet.Field.newBuilder().addFixed32(25).build();
+    UnknownFieldSet fieldSet = UnknownFieldSet.newBuilder()
+        .addField(1, first)
+        .addField(1, second)
+        .build();
+    List<Integer> list = fieldSet.getField(1).getFixed32List();
+    assertThat(list).hasSize(1);
+    assertThat(list.get(0)).isEqualTo(25);
+  }
+
+  @Test
   public void testVarint() throws Exception {
     UnknownFieldSet.Field field = getField("optional_int32");
     assertThat(field.getVarintList()).hasSize(1);
@@ -186,6 +356,16 @@
   }
 
   @Test
+  public void testAsMap() throws Exception {
+    UnknownFieldSet.Builder builder = UnknownFieldSet.newBuilder().mergeFrom(unknownFields);
+    Map<Integer, UnknownFieldSet.Field> mapFromBuilder = builder.asMap();
+    assertThat(mapFromBuilder).isNotEmpty();
+    UnknownFieldSet fields = builder.build();
+    Map<Integer, UnknownFieldSet.Field> mapFromFieldSet = fields.asMap();
+    assertThat(mapFromFieldSet).containsExactlyEntriesIn(mapFromBuilder);
+  }
+
+  @Test
   public void testClear() throws Exception {
     UnknownFieldSet fields = UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
     assertThat(fields.asMap()).isEmpty();
diff --git a/java/core/src/test/java/com/google/protobuf/Utf8Test.java b/java/core/src/test/java/com/google/protobuf/Utf8Test.java
index 89f080e..44f7cf1 100644
--- a/java/core/src/test/java/com/google/protobuf/Utf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/Utf8Test.java
@@ -101,7 +101,7 @@
       int codePoint;
       do {
         codePoint = rnd.nextInt(maxCodePoint);
-      } while (Utf8Utils.isSurrogate(codePoint));
+      } while (Character.isSurrogate((char) codePoint));
       sb.appendCodePoint(codePoint);
     }
     return sb.toString();
diff --git a/java/core/src/test/java/com/google/protobuf/Utf8Utils.java b/java/core/src/test/java/com/google/protobuf/Utf8Utils.java
deleted file mode 100644
index 6b03186..0000000
--- a/java/core/src/test/java/com/google/protobuf/Utf8Utils.java
+++ /dev/null
@@ -1,192 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static java.lang.Character.MIN_HIGH_SURROGATE;
-import static java.lang.Character.MIN_LOW_SURROGATE;
-import static java.lang.Character.MIN_SURROGATE;
-
-import java.util.Random;
-
-/** Utilities for benchmarking UTF-8. */
-final class Utf8Utils {
-  private Utf8Utils() {}
-
-  static class MaxCodePoint {
-    final int value;
-
-    /**
-     * Convert the input string to a code point. Accepts regular decimal numerals, hex strings, and
-     * some symbolic names meaningful to humans.
-     */
-    private static int decode(String userFriendly) {
-      try {
-        return Integer.decode(userFriendly);
-      } catch (NumberFormatException ignored) {
-        if (userFriendly.matches("(?i)(?:American|English|ASCII)")) {
-          // 1-byte UTF-8 sequences - "American" ASCII text
-          return 0x80;
-        } else if (userFriendly.matches("(?i)(?:Danish|Latin|Western.*European)")) {
-          // Mostly 1-byte UTF-8 sequences, mixed with occasional 2-byte
-          // sequences - "Western European" text
-          return 0x90;
-        } else if (userFriendly.matches("(?i)(?:Greek|Cyrillic|European|ISO.?8859)")) {
-          // Mostly 2-byte UTF-8 sequences - "European" text
-          return 0x800;
-        } else if (userFriendly.matches("(?i)(?:Chinese|Han|Asian|BMP)")) {
-          // Mostly 3-byte UTF-8 sequences - "Asian" text
-          return Character.MIN_SUPPLEMENTARY_CODE_POINT;
-        } else if (userFriendly.matches("(?i)(?:Cuneiform|rare|exotic|supplementary.*)")) {
-          // Mostly 4-byte UTF-8 sequences - "rare exotic" text
-          return Character.MAX_CODE_POINT;
-        } else {
-          throw new IllegalArgumentException("Can't decode codepoint " + userFriendly);
-        }
-      }
-    }
-
-    public static MaxCodePoint valueOf(String userFriendly) {
-      return new MaxCodePoint(userFriendly);
-    }
-
-    public MaxCodePoint(String userFriendly) {
-      value = decode(userFriendly);
-    }
-  }
-
-  /**
-   * The Utf8 distribution of real data. The distribution is an array with length 4.
-   * "distribution[i]" means the total number of characters who are encoded with (i + 1) bytes.
-   *
-   * <p>GMM_UTF8_DISTRIBUTION is the distribution of gmm data set. GSR_UTF8_DISTRIBUTION is the
-   * distribution of gsreq/gsresp data set
-   */
-  public enum Utf8Distribution {
-    GMM_UTF8_DISTRIBUTION {
-      @Override
-      public int[] getDistribution() {
-        return new int[] {53059, 104, 0, 0};
-      }
-    },
-    GSR_UTF8_DISTRIBUTION {
-      @Override
-      public int[] getDistribution() {
-        return new int[] {119458, 74, 2706, 0};
-      }
-    };
-
-    public abstract int[] getDistribution();
-  }
-
-  /**
-   * Creates an array of random strings.
-   *
-   * @param stringCount the number of strings to be created.
-   * @param charCount the number of characters per string.
-   * @param maxCodePoint the maximum code point for the characters in the strings.
-   * @return an array of random strings.
-   */
-  static String[] randomStrings(int stringCount, int charCount, MaxCodePoint maxCodePoint) {
-    final long seed = 99;
-    final Random rnd = new Random(seed);
-    String[] strings = new String[stringCount];
-    for (int i = 0; i < stringCount; i++) {
-      strings[i] = randomString(rnd, charCount, maxCodePoint);
-    }
-    return strings;
-  }
-
-  /**
-   * Creates a random string
-   *
-   * @param rnd the random generator.
-   * @param charCount the number of characters per string.
-   * @param maxCodePoint the maximum code point for the characters in the strings.
-   */
-  static String randomString(Random rnd, int charCount, MaxCodePoint maxCodePoint) {
-    StringBuilder sb = new StringBuilder();
-    for (int i = 0; i < charCount; i++) {
-      int codePoint;
-      do {
-        codePoint = rnd.nextInt(maxCodePoint.value);
-      } while (Utf8Utils.isSurrogate(codePoint));
-      sb.appendCodePoint(codePoint);
-    }
-    return sb.toString();
-  }
-
-  /** Character.isSurrogate was added in Java SE 7. */
-  static boolean isSurrogate(int c) {
-    return Character.MIN_HIGH_SURROGATE <= c && c <= Character.MAX_LOW_SURROGATE;
-  }
-
-  /**
-   * Creates an array of random strings according to UTF8 distribution.
-   *
-   * @param stringCount the number of strings to be created.
-   * @param charCount the number of characters per string.
-   */
-  static String[] randomStringsWithDistribution(
-      int stringCount, int charCount, Utf8Distribution utf8Distribution) {
-    final int[] distribution = utf8Distribution.getDistribution();
-    for (int i = 0; i < 3; i++) {
-      distribution[i + 1] += distribution[i];
-    }
-    final long seed = 99;
-    final Random rnd = new Random(seed);
-    String[] strings = new String[stringCount];
-    for (int i = 0; i < stringCount; i++) {
-      StringBuilder sb = new StringBuilder();
-      for (int j = 0; j < charCount; j++) {
-        int codePoint;
-        do {
-          codePoint = rnd.nextInt(distribution[3]);
-          if (codePoint < distribution[0]) {
-            // 1 bytes
-            sb.append((char) 0x7F);
-          } else if (codePoint < distribution[1]) {
-            // 2 bytes
-            sb.append((char) 0x7FF);
-          } else if (codePoint < distribution[2]) {
-            // 3 bytes
-            sb.append((char) (MIN_SURROGATE - 1));
-          } else {
-            // 4 bytes
-            sb.append(MIN_HIGH_SURROGATE);
-            sb.append(MIN_LOW_SURROGATE);
-          }
-        } while (Utf8Utils.isSurrogate(codePoint));
-      }
-      strings[i] = sb.toString();
-    }
-    return strings;
-  }
-}
diff --git a/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto b/java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
similarity index 82%
rename from java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto
rename to java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
index 9baf948..a0f28ac 100644
--- a/java/core/src/test/proto/com/google/protobuf/message_lite_extension_util_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/dynamic_message_test.proto
@@ -28,21 +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.
 
-// Proto definitions used to test MessageLiteExtensionUtil
 syntax = "proto2";
 
-package protobuf_unittest;
+package dynamic_message_test;
 
-option java_outer_classname = "MessageLiteExtensionTestProtos";
+option java_package = "dynamicmessagetest";
+option java_outer_classname = "DynamicMessageTestProto";
 
-message Car {
-  optional string make = 1;
-  extensions 1000 to max;
-}
+message EmptyMessage {}
 
-extend Car {
-  optional bool turbo = 1001;
-  optional bool self_driving = 1002;
-  optional bool flies = 1003;
-  optional string plate = 9999;
+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 8bf1691..e513725 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/kotlin-lite/BUILD b/java/kotlin-lite/BUILD
new file mode 100644
index 0000000..bfd7b8d
--- /dev/null
+++ b/java/kotlin-lite/BUILD
@@ -0,0 +1,184 @@
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_lite_proto_library")
+
+java_lite_proto_library(
+    name = "example_extensible_message_java_proto_lite",
+    deps = ["//java/kotlin:example_extensible_message_proto"],
+)
+
+kt_jvm_library(
+    name = "lite_extensions",
+    srcs = ["src/main/kotlin/com/google/protobuf/ExtendableMessageLiteExtensions.kt"],
+    deps = ["//java/lite"],
+)
+
+test_suite(
+    name = "tests",
+    tests = [
+        "test_lite_extensions",
+        "proto2_test_lite",
+        "proto3_test_lite",
+    ],
+)
+
+kt_jvm_library(
+    name = "test_lite_extensions_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/ExtendableMessageLiteExtensionsTest.kt"],
+    deps = [
+        ":example_extensible_message_java_proto_lite",
+        ":lite_extensions",
+        "//java/lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "test_lite_extensions",
+    runtime_deps = [":test_lite_extensions_library"],
+    test_class = "com.google.protobuf.kotlin.ExtendableMessageLiteExtensionsTest",
+)
+
+java_lite_proto_library(
+    name = "evil_names_proto2_java_proto_lite",
+    deps = ["//java/kotlin:evil_names_proto2"],
+)
+
+java_lite_proto_library(
+    name = "evil_names_proto3_java_proto_lite",
+    deps = ["//java/kotlin:evil_names_proto3"],
+)
+
+java_lite_proto_library(
+    name = "multiple_files_proto3_java_proto_lite",
+    deps = ["//java/kotlin:multiple_files_proto3"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_java_multiple_files_lite",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    outs = [
+        "MultipleFilesMessageALiteKt.kt",
+        "MultipleFilesMessageBLiteKt.kt",
+        "MultipleFilesProto3LiteKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
+          "$(location MultipleFilesMessageALiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
+          "$(location MultipleFilesMessageBLiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
+          "$(location MultipleFilesProto3LiteKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto2_lite",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    outs = [
+        "EvilNamesProto2LiteKt.kt",
+        "HardKeywordsAllTypesProto2LiteKt.kt",
+        "InterfaceKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
+          "$(location EvilNamesProto2LiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
+          "$(location HardKeywordsAllTypesProto2LiteKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
+          "$(location InterfaceKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto3_lite",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    outs = [
+        "ClassKt.kt",
+        "EvilNamesProto3Kt.kt",
+        "HardKeywordsAllTypesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=lite:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
+          "$(location ClassKt.kt) && " + 
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
+          "$(location EvilNamesProto3Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
+          "$(location HardKeywordsAllTypesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+kt_jvm_library(
+    name = "kotlin_unittest_lite",
+    srcs = [
+        ":gen_evil_names_proto2_lite",
+        "//:gen_kotlin_unittest_lite",
+    ],
+    deps = [
+        ":evil_names_proto2_java_proto_lite",
+        "//java/lite:lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "//:java_lite_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "kotlin_proto3_unittest_lite",
+    srcs = [
+        ":gen_evil_names_proto3_lite",
+        ":gen_kotlin_proto3_java_multiple_files_lite",
+        "//:gen_kotlin_proto3_unittest_lite",
+    ],
+    deps = [
+        ":evil_names_proto3_java_proto_lite",
+        ":multiple_files_proto3_java_proto_lite",
+        "//java/lite:lite",
+        "//java/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/kotlin:shared_runtime",
+        "//:java_lite_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "proto2_test_lite_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt"],
+    deps = [
+        ":kotlin_unittest_lite",
+        "//java/core:test_util_lite",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "proto2_test_lite",
+    runtime_deps = [":proto2_test_lite_library"],
+    test_class = "com.google.protobuf.kotlin.Proto2LiteTest",
+)
+
+kt_jvm_library(
+    name = "proto3_test_lite_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto3LiteTest.kt"],
+    deps = [
+        ":kotlin_proto3_unittest_lite",
+        "//java/core:test_util_lite",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "proto3_test_lite",
+    runtime_deps = [":proto3_test_lite_library"],
+    test_class = "com.google.protobuf.kotlin.Proto3LiteTest",
+)
diff --git a/java/kotlin-lite/generate-test-sources-build.xml b/java/kotlin-lite/generate-test-sources-build.xml
index c5f60b8..ed88620 100644
--- a/java/kotlin-lite/generate-test-sources-build.xml
+++ b/java/kotlin-lite/generate-test-sources-build.xml
@@ -12,7 +12,7 @@
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_import_public_lite.proto"/>
         <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
-        <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
+        <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3_lite.proto"/>
         <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
         <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
         <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/example_extensible_message.proto"/>
@@ -25,7 +25,7 @@
       <arg value="--experimental_allow_proto3_optional"/>
       <arg value="${protobuf.source.dir}/google/protobuf/map_lite_unittest.proto"/>
       <arg value="${protobuf.source.dir}/google/protobuf/unittest_lite.proto"/>
-      <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3.proto"/>
+      <arg value="${protobuf.source.dir}/google/protobuf/unittest_proto3_lite.proto"/>
       <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto2.proto"/>
       <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/evil_names_proto3.proto"/>
       <arg value="${protobuf.basedir}/java/kotlin/${test.proto.dir}/com/google/protobuf/example_extensible_message.proto"/>
diff --git a/java/kotlin-lite/pom.xml b/java/kotlin-lite/pom.xml
index 57416d3..1f02c4d 100644
--- a/java/kotlin-lite/pom.xml
+++ b/java/kotlin-lite/pom.xml
@@ -4,14 +4,14 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
   </parent>
 
   <artifactId>protobuf-kotlin-lite</artifactId>
 
-  <name>Protocol Buffers [Lite]</name>
+  <name>Protocol Buffers [Kotlin-Lite]</name>
   <description>
-    Lite version of Protocol Buffers library. This version is optimized for code size, but does
+    Lite version of Kotlin Protocol Buffers library. This version is optimized for code size, but does
     not guarantee API/ABI stability.
   </description>
 
@@ -94,7 +94,6 @@
                     <include>DslList.kt</include>
                     <include>DslMap.kt</include>
                     <include>DslProxy.kt</include>
-                    <include>ExtendableMessageLiteExtensions.kt</include>
                     <include>ExtensionList.kt</include>
                     <include>OnlyForUseByGeneratedProtoCode.kt</include>
                     <include>ProtoDslMarker.kt</include>
@@ -119,14 +118,6 @@
                     <include>TestUtilLite.java</include>
                   </includes>
                 </resource>
-                <resource>
-                  <directory>${basedir}/../kotlin/src/test/kotlin/com/google/protobuf</directory>
-                  <excludes>
-                    <exclude>ExtendableMessageExtensionsTest.kt</exclude>
-                    <exclude>Proto2Test.kt</exclude>
-                    <exclude>ProtoUtil.java</exclude>
-                  </excludes>
-                </resource>
               </resources>
             </configuration>
           </execution>
@@ -223,8 +214,8 @@
             <goals> <goal>compile</goal> </goals>
             <configuration>
               <sourceDirs>
-                <sourceDir>${generated.sources.dir}</sourceDir>
                 <sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
+                <sourceDir>${generated.sources.dir}</sourceDir>
               </sourceDirs>
             </configuration>
           </execution>
diff --git a/java/kotlin-lite/pom_template.xml b/java/kotlin-lite/pom_template.xml
new file mode 100644
index 0000000..92be0ea
--- /dev/null
+++ b/java/kotlin-lite/pom_template.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>{groupId}</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>{version}</version>
+  </parent>
+
+  <artifactId>{artifactId}</artifactId>
+  <packaging>{type}</packaging>
+
+  <name>Protocol Buffers [Kotlin-Lite]</name>
+  <description>
+    Kotlin lite Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <properties>
+    <kotlin.version>1.5.0</kotlin.version>
+  </properties>
+</project>
diff --git a/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt
index 76d4847..1f45f65 100644
--- a/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt
+++ b/java/kotlin-lite/src/test/kotlin/com/google/protobuf/Proto2LiteTest.kt
@@ -71,123 +71,110 @@
   @Test
   fun testSetters() {
     assertThat(
-      testAllTypesLite {
-        optionalInt32 = 101
-        optionalInt64 = 102
-        optionalUint32 = 103
-        optionalUint64 = 104
-        optionalSint32 = 105
-        optionalSint64 = 106
-        optionalFixed32 = 107
-        optionalFixed64 = 108
-        optionalSfixed32 = 109
-        optionalSfixed64 = 110
-        optionalFloat = 111.0f
-        optionalDouble = 112.0
-        optionalBool = true
-        optionalString = "115"
-        optionalBytes = toBytes("116")
-        optionalGroup =
-          TestAllTypesLiteKt.optionalGroup { a = 117 }
-        optionalNestedMessage = nestedMessage { bb = 118 }
-        optionalForeignMessage =
-          foreignMessageLite { c = 119 }
-        optionalImportMessage =
-          ImportMessageLite.newBuilder().setD(120).build()
-        optionalPublicImportMessage =
-          PublicImportMessageLite.newBuilder().setE(126).build()
-        optionalLazyMessage = nestedMessage { bb = 127 }
-        optionalNestedEnum = NestedEnum.BAZ
-        optionalForeignEnum = ForeignEnumLite.FOREIGN_LITE_BAZ
-        optionalImportEnum = ImportEnumLite.IMPORT_LITE_BAZ
-        optionalStringPiece = "124"
-        optionalCord = "125"
-        repeatedInt32.add(201)
-        repeatedInt64.add(202)
-        repeatedUint32.add(203)
-        repeatedUint64.add(204)
-        repeatedSint32.add(205)
-        repeatedSint64.add(206)
-        repeatedFixed32.add(207)
-        repeatedFixed64.add(208)
-        repeatedSfixed32.add(209)
-        repeatedSfixed64.add(210)
-        repeatedFloat.add(211f)
-        repeatedDouble.add(212.0)
-        repeatedBool.add(true)
-        repeatedString.add("215")
-        repeatedBytes.add(toBytes("216"))
-        repeatedGroup.add(TestAllTypesLiteKt.repeatedGroup { a = 217 })
-        repeatedNestedMessage.add(nestedMessage { bb = 218 })
-        repeatedForeignMessage.add(
-          foreignMessageLite { c = 219 }
-        )
-        repeatedImportMessage.add(
-          ImportMessageLite.newBuilder().setD(220).build()
-        )
-        repeatedLazyMessage.add(nestedMessage { bb = 227 })
-        repeatedNestedEnum.add(NestedEnum.BAR)
-        repeatedForeignEnum.add(ForeignEnumLite.FOREIGN_LITE_BAR)
-        repeatedImportEnum.add(ImportEnumLite.IMPORT_LITE_BAR)
-        repeatedStringPiece.add("224")
-        repeatedCord.add("225")
-        repeatedInt32 += 301
-        repeatedInt64 += 302
-        repeatedUint32 += 303
-        repeatedUint64 += 304
-        repeatedSint32 += 305
-        repeatedSint64 += 306
-        repeatedFixed32 += 307
-        repeatedFixed64 += 308
-        repeatedSfixed32 += 309
-        repeatedSfixed64 += 310
-        repeatedFloat += 311f
-        repeatedDouble += 312.0
-        repeatedBool += false
-        repeatedString += "315"
-        repeatedBytes += toBytes("316")
-        repeatedGroup += TestAllTypesLiteKt.repeatedGroup { a = 317 }
-        repeatedNestedMessage += nestedMessage { bb = 318 }
-        repeatedForeignMessage +=
-          foreignMessageLite { c = 319 }
-        repeatedImportMessage +=
-          ImportMessageLite.newBuilder().setD(320).build()
-        repeatedLazyMessage +=
-          TestAllTypesLiteKt.nestedMessage { bb = 327 }
-        repeatedNestedEnum += NestedEnum.BAZ
-        repeatedForeignEnum += ForeignEnumLite.FOREIGN_LITE_BAZ
-        repeatedImportEnum += ImportEnumLite.IMPORT_LITE_BAZ
-        repeatedStringPiece += "324"
-        repeatedCord += "325"
-        defaultInt32 = 401
-        defaultInt64 = 402
-        defaultUint32 = 403
-        defaultUint64 = 404
-        defaultSint32 = 405
-        defaultSint64 = 406
-        defaultFixed32 = 407
-        defaultFixed64 = 408
-        defaultSfixed32 = 409
-        defaultSfixed64 = 410
-        defaultFloat = 411f
-        defaultDouble = 412.0
-        defaultBool = false
-        defaultString = "415"
-        defaultBytes = toBytes("416")
-        defaultNestedEnum = NestedEnum.FOO
-        defaultForeignEnum = ForeignEnumLite.FOREIGN_LITE_FOO
-        defaultImportEnum = ImportEnumLite.IMPORT_LITE_FOO
-        defaultStringPiece = "424"
-        defaultCord = "425"
-        oneofUint32 = 601
-        oneofNestedMessage =
-          TestAllTypesLiteKt.nestedMessage { bb = 602 }
-        oneofString = "603"
-        oneofBytes = toBytes("604")
-      }
-    ).isEqualTo(
-      TestUtilLite.getAllLiteSetBuilder().build()
-    )
+        testAllTypesLite {
+          optionalInt32 = 101
+          optionalInt64 = 102
+          optionalUint32 = 103
+          optionalUint64 = 104
+          optionalSint32 = 105
+          optionalSint64 = 106
+          optionalFixed32 = 107
+          optionalFixed64 = 108
+          optionalSfixed32 = 109
+          optionalSfixed64 = 110
+          optionalFloat = 111.0f
+          optionalDouble = 112.0
+          optionalBool = true
+          optionalString = "115"
+          optionalBytes = toBytes("116")
+          optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+          optionalNestedMessage = nestedMessage { bb = 118 }
+          optionalForeignMessage = foreignMessageLite { c = 119 }
+          optionalImportMessage = ImportMessageLite.newBuilder().setD(120).build()
+          optionalPublicImportMessage = PublicImportMessageLite.newBuilder().setE(126).build()
+          optionalLazyMessage = nestedMessage { bb = 127 }
+          optionalNestedEnum = NestedEnum.BAZ
+          optionalForeignEnum = ForeignEnumLite.FOREIGN_LITE_BAZ
+          optionalImportEnum = ImportEnumLite.IMPORT_LITE_BAZ
+          optionalStringPiece = "124"
+          optionalCord = "125"
+          repeatedInt32.add(201)
+          repeatedInt64.add(202)
+          repeatedUint32.add(203)
+          repeatedUint64.add(204)
+          repeatedSint32.add(205)
+          repeatedSint64.add(206)
+          repeatedFixed32.add(207)
+          repeatedFixed64.add(208)
+          repeatedSfixed32.add(209)
+          repeatedSfixed64.add(210)
+          repeatedFloat.add(211f)
+          repeatedDouble.add(212.0)
+          repeatedBool.add(true)
+          repeatedString.add("215")
+          repeatedBytes.add(toBytes("216"))
+          repeatedGroup.add(TestAllTypesLiteKt.repeatedGroup { a = 217 })
+          repeatedNestedMessage.add(nestedMessage { bb = 218 })
+          repeatedForeignMessage.add(foreignMessageLite { c = 219 })
+          repeatedImportMessage.add(ImportMessageLite.newBuilder().setD(220).build())
+          repeatedLazyMessage.add(nestedMessage { bb = 227 })
+          repeatedNestedEnum.add(NestedEnum.BAR)
+          repeatedForeignEnum.add(ForeignEnumLite.FOREIGN_LITE_BAR)
+          repeatedImportEnum.add(ImportEnumLite.IMPORT_LITE_BAR)
+          repeatedStringPiece.add("224")
+          repeatedCord.add("225")
+          repeatedInt32 += 301
+          repeatedInt64 += 302
+          repeatedUint32 += 303
+          repeatedUint64 += 304
+          repeatedSint32 += 305
+          repeatedSint64 += 306
+          repeatedFixed32 += 307
+          repeatedFixed64 += 308
+          repeatedSfixed32 += 309
+          repeatedSfixed64 += 310
+          repeatedFloat += 311f
+          repeatedDouble += 312.0
+          repeatedBool += false
+          repeatedString += "315"
+          repeatedBytes += toBytes("316")
+          repeatedGroup += TestAllTypesLiteKt.repeatedGroup { a = 317 }
+          repeatedNestedMessage += nestedMessage { bb = 318 }
+          repeatedForeignMessage += foreignMessageLite { c = 319 }
+          repeatedImportMessage += ImportMessageLite.newBuilder().setD(320).build()
+          repeatedLazyMessage += TestAllTypesLiteKt.nestedMessage { bb = 327 }
+          repeatedNestedEnum += NestedEnum.BAZ
+          repeatedForeignEnum += ForeignEnumLite.FOREIGN_LITE_BAZ
+          repeatedImportEnum += ImportEnumLite.IMPORT_LITE_BAZ
+          repeatedStringPiece += "324"
+          repeatedCord += "325"
+          defaultInt32 = 401
+          defaultInt64 = 402
+          defaultUint32 = 403
+          defaultUint64 = 404
+          defaultSint32 = 405
+          defaultSint64 = 406
+          defaultFixed32 = 407
+          defaultFixed64 = 408
+          defaultSfixed32 = 409
+          defaultSfixed64 = 410
+          defaultFloat = 411f
+          defaultDouble = 412.0
+          defaultBool = false
+          defaultString = "415"
+          defaultBytes = toBytes("416")
+          defaultNestedEnum = NestedEnum.FOO
+          defaultForeignEnum = ForeignEnumLite.FOREIGN_LITE_FOO
+          defaultImportEnum = ImportEnumLite.IMPORT_LITE_FOO
+          defaultStringPiece = "424"
+          defaultCord = "425"
+          oneofUint32 = 601
+          oneofNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 602 }
+          oneofString = "603"
+          oneofBytes = toBytes("604")
+        }
+      )
+      .isEqualTo(TestUtilLite.getAllLiteSetBuilder().build())
   }
 
   @Test
@@ -243,71 +230,70 @@
           TestAllTypesLiteKt.repeatedGroup { a = 2 }
         )
       )
-      assertThat(repeatedGroup).isEqualTo(
-        listOf(
-          TestAllTypesLiteKt.repeatedGroup { a = 1 },
-          TestAllTypesLiteKt.repeatedGroup { a = 2 }
+      assertThat(repeatedGroup)
+        .isEqualTo(
+          listOf(
+            TestAllTypesLiteKt.repeatedGroup { a = 1 },
+            TestAllTypesLiteKt.repeatedGroup { a = 2 }
+          )
         )
-      )
       repeatedGroup +=
         listOf(
           TestAllTypesLiteKt.repeatedGroup { a = 3 },
           TestAllTypesLiteKt.repeatedGroup { a = 4 }
         )
-      assertThat(repeatedGroup).isEqualTo(
-        listOf(
-          TestAllTypesLiteKt.repeatedGroup { a = 1 },
-          TestAllTypesLiteKt.repeatedGroup { a = 2 },
-          TestAllTypesLiteKt.repeatedGroup { a = 3 },
-          TestAllTypesLiteKt.repeatedGroup { a = 4 }
+      assertThat(repeatedGroup)
+        .isEqualTo(
+          listOf(
+            TestAllTypesLiteKt.repeatedGroup { a = 1 },
+            TestAllTypesLiteKt.repeatedGroup { a = 2 },
+            TestAllTypesLiteKt.repeatedGroup { a = 3 },
+            TestAllTypesLiteKt.repeatedGroup { a = 4 }
+          )
         )
-      )
       repeatedGroup[0] = TestAllTypesLiteKt.repeatedGroup { a = 5 }
-      assertThat(repeatedGroup).isEqualTo(
-        listOf(
-          TestAllTypesLiteKt.repeatedGroup { a = 5 },
-          TestAllTypesLiteKt.repeatedGroup { a = 2 },
-          TestAllTypesLiteKt.repeatedGroup { a = 3 },
-          TestAllTypesLiteKt.repeatedGroup { a = 4 }
+      assertThat(repeatedGroup)
+        .isEqualTo(
+          listOf(
+            TestAllTypesLiteKt.repeatedGroup { a = 5 },
+            TestAllTypesLiteKt.repeatedGroup { a = 2 },
+            TestAllTypesLiteKt.repeatedGroup { a = 3 },
+            TestAllTypesLiteKt.repeatedGroup { a = 4 }
+          )
         )
-      )
 
       repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 1 },
-          nestedMessage { bb = 2 }
-        )
-      )
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
       repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 1 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 1 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
       repeatedNestedMessage[0] = nestedMessage { bb = 5 }
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 5 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 5 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
 
       repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
       assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
       repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
-      assertThat(repeatedNestedEnum).isEqualTo(
-        listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(repeatedNestedEnum)
+        .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
       repeatedNestedEnum[0] = NestedEnum.BAR
-      assertThat(repeatedNestedEnum).isEqualTo(
-        listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(repeatedNestedEnum)
+        .isEqualTo(listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
     }
   }
 
@@ -380,165 +366,155 @@
       optionalInt32 = 101
       optionalString = "115"
     }
-    val modifiedMessage = message.copy {
-      optionalInt32 = 201
-    }
+    val modifiedMessage = message.copy { optionalInt32 = 201 }
 
-    assertThat(message).isEqualTo(
-      TestAllTypesLite.newBuilder()
-        .setOptionalInt32(101)
-        .setOptionalString("115")
-        .build()
-    )
-    assertThat(modifiedMessage).isEqualTo(
-      TestAllTypesLite.newBuilder()
-        .setOptionalInt32(201)
-        .setOptionalString("115")
-        .build()
-    )
+    assertThat(message)
+      .isEqualTo(
+        TestAllTypesLite.newBuilder().setOptionalInt32(101).setOptionalString("115").build()
+      )
+    assertThat(modifiedMessage)
+      .isEqualTo(
+        TestAllTypesLite.newBuilder().setOptionalInt32(201).setOptionalString("115").build()
+      )
   }
 
   @Test
   fun testOneof() {
     val message = testAllTypesLite {
       oneofString = "foo"
-      assertThat(oneofFieldCase)
-        .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_STRING)
+      assertThat(oneofFieldCase).isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_STRING)
       assertThat(oneofString).isEqualTo("foo")
       clearOneofField()
       assertThat(hasOneofUint32()).isFalse()
-      assertThat(oneofFieldCase)
-        .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOFFIELD_NOT_SET)
+      assertThat(oneofFieldCase).isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOFFIELD_NOT_SET)
       oneofUint32 = 5
     }
 
-    assertThat(message.getOneofFieldCase())
-      .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_UINT32)
+    assertThat(message.getOneofFieldCase()).isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_UINT32)
     assertThat(message.getOneofUint32()).isEqualTo(5)
   }
 
   @Test
   fun testExtensionsSet() {
     assertThat(
-      testAllExtensionsLite {
-        this[UnittestLite.optionalInt32ExtensionLite] = 101
-        this[UnittestLite.optionalInt64ExtensionLite] = 102L
-        this[UnittestLite.optionalUint32ExtensionLite] = 103
-        this[UnittestLite.optionalUint64ExtensionLite] = 104L
-        this[UnittestLite.optionalSint32ExtensionLite] = 105
-        this[UnittestLite.optionalSint64ExtensionLite] = 106L
-        this[UnittestLite.optionalFixed32ExtensionLite] = 107
-        this[UnittestLite.optionalFixed64ExtensionLite] = 108L
-        this[UnittestLite.optionalSfixed32ExtensionLite] = 109
-        this[UnittestLite.optionalSfixed64ExtensionLite] = 110L
-        this[UnittestLite.optionalFloatExtensionLite] = 111F
-        this[UnittestLite.optionalDoubleExtensionLite] = 112.0
-        this[UnittestLite.optionalBoolExtensionLite] = true
-        this[UnittestLite.optionalStringExtensionLite] = "115"
-        this[UnittestLite.optionalBytesExtensionLite] = toBytes("116")
-        this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
-        this[UnittestLite.optionalNestedMessageExtensionLite] =
-          TestAllTypesLiteKt.nestedMessage { bb = 118 }
-        this[UnittestLite.optionalForeignMessageExtensionLite] = foreignMessageLite { c = 119 }
-        this[UnittestLite.optionalImportMessageExtensionLite] =
-          ImportMessageLite.newBuilder().setD(120).build()
-        this[UnittestLite.optionalPublicImportMessageExtensionLite] =
-          PublicImportMessageLite.newBuilder().setE(126).build()
-        this[UnittestLite.optionalLazyMessageExtensionLite] =
-          TestAllTypesLiteKt.nestedMessage { bb = 127 }
-        this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
-        this[UnittestLite.optionalForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_BAZ
-        this[UnittestLite.optionalImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_BAZ
-        this[UnittestLite.optionalStringPieceExtensionLite] = "124"
-        this[UnittestLite.optionalCordExtensionLite] = "125"
-        this[UnittestLite.repeatedInt32ExtensionLite].add(201)
-        this[UnittestLite.repeatedInt64ExtensionLite].add(202L)
-        this[UnittestLite.repeatedUint32ExtensionLite].add(203)
-        this[UnittestLite.repeatedUint64ExtensionLite].add(204L)
-        this[UnittestLite.repeatedSint32ExtensionLite].add(205)
-        this[UnittestLite.repeatedSint64ExtensionLite].add(206L)
-        this[UnittestLite.repeatedFixed32ExtensionLite].add(207)
-        this[UnittestLite.repeatedFixed64ExtensionLite].add(208L)
-        this[UnittestLite.repeatedSfixed32ExtensionLite].add(209)
-        this[UnittestLite.repeatedSfixed64ExtensionLite].add(210L)
-        this[UnittestLite.repeatedFloatExtensionLite].add(211F)
-        this[UnittestLite.repeatedDoubleExtensionLite].add(212.0)
-        this[UnittestLite.repeatedBoolExtensionLite].add(true)
-        this[UnittestLite.repeatedStringExtensionLite].add("215")
-        this[UnittestLite.repeatedBytesExtensionLite].add(toBytes("216"))
-        this[UnittestLite.repeatedGroupExtensionLite].add(repeatedGroupExtensionLite { a = 217 })
-        this[UnittestLite.repeatedNestedMessageExtensionLite].add(
-          TestAllTypesLiteKt.nestedMessage { bb = 218 }
-        )
-        this[UnittestLite.repeatedForeignMessageExtensionLite].add(foreignMessageLite { c = 219 })
-        this[UnittestLite.repeatedImportMessageExtensionLite].add(
-          ImportMessageLite.newBuilder().setD(220).build()
-        )
-        this[UnittestLite.repeatedLazyMessageExtensionLite].add(
-          TestAllTypesLiteKt.nestedMessage { bb = 227 }
-        )
-        this[UnittestLite.repeatedNestedEnumExtensionLite].add(NestedEnum.BAR)
-        this[UnittestLite.repeatedForeignEnumExtensionLite].add(ForeignEnumLite.FOREIGN_LITE_BAR)
-        this[UnittestLite.repeatedImportEnumExtensionLite].add(ImportEnumLite.IMPORT_LITE_BAR)
-        this[UnittestLite.repeatedStringPieceExtensionLite].add("224")
-        this[UnittestLite.repeatedCordExtensionLite].add("225")
-        this[UnittestLite.repeatedInt32ExtensionLite] += 301
-        this[UnittestLite.repeatedInt64ExtensionLite] += 302L
-        this[UnittestLite.repeatedUint32ExtensionLite] += 303
-        this[UnittestLite.repeatedUint64ExtensionLite] += 304L
-        this[UnittestLite.repeatedSint32ExtensionLite] += 305
-        this[UnittestLite.repeatedSint64ExtensionLite] += 306L
-        this[UnittestLite.repeatedFixed32ExtensionLite] += 307
-        this[UnittestLite.repeatedFixed64ExtensionLite] += 308L
-        this[UnittestLite.repeatedSfixed32ExtensionLite] += 309
-        this[UnittestLite.repeatedSfixed64ExtensionLite] += 310L
-        this[UnittestLite.repeatedFloatExtensionLite] += 311F
-        this[UnittestLite.repeatedDoubleExtensionLite] += 312.0
-        this[UnittestLite.repeatedBoolExtensionLite] += false
-        this[UnittestLite.repeatedStringExtensionLite] += "315"
-        this[UnittestLite.repeatedBytesExtensionLite] += toBytes("316")
-        this[UnittestLite.repeatedGroupExtensionLite] += repeatedGroupExtensionLite { a = 317 }
-        this[UnittestLite.repeatedNestedMessageExtensionLite] +=
-          TestAllTypesLiteKt.nestedMessage { bb = 318 }
-        this[UnittestLite.repeatedForeignMessageExtensionLite] += foreignMessageLite { c = 319 }
-        this[UnittestLite.repeatedImportMessageExtensionLite] +=
-          ImportMessageLite.newBuilder().setD(320).build()
-        this[UnittestLite.repeatedLazyMessageExtensionLite] +=
-          TestAllTypesLiteKt.nestedMessage { bb = 327 }
-        this[UnittestLite.repeatedNestedEnumExtensionLite] += NestedEnum.BAZ
-        this[UnittestLite.repeatedForeignEnumExtensionLite] += ForeignEnumLite.FOREIGN_LITE_BAZ
-        this[UnittestLite.repeatedImportEnumExtensionLite] += ImportEnumLite.IMPORT_LITE_BAZ
-        this[UnittestLite.repeatedStringPieceExtensionLite] += "324"
-        this[UnittestLite.repeatedCordExtensionLite] += "325"
-        this[UnittestLite.defaultInt32ExtensionLite] = 401
-        this[UnittestLite.defaultInt64ExtensionLite] = 402L
-        this[UnittestLite.defaultUint32ExtensionLite] = 403
-        this[UnittestLite.defaultUint64ExtensionLite] = 404L
-        this[UnittestLite.defaultSint32ExtensionLite] = 405
-        this[UnittestLite.defaultSint64ExtensionLite] = 406L
-        this[UnittestLite.defaultFixed32ExtensionLite] = 407
-        this[UnittestLite.defaultFixed64ExtensionLite] = 408L
-        this[UnittestLite.defaultSfixed32ExtensionLite] = 409
-        this[UnittestLite.defaultSfixed64ExtensionLite] = 410L
-        this[UnittestLite.defaultFloatExtensionLite] = 411F
-        this[UnittestLite.defaultDoubleExtensionLite] = 412.0
-        this[UnittestLite.defaultBoolExtensionLite] = false
-        this[UnittestLite.defaultStringExtensionLite] = "415"
-        this[UnittestLite.defaultBytesExtensionLite] = toBytes("416")
-        this[UnittestLite.defaultNestedEnumExtensionLite] = NestedEnum.FOO
-        this[UnittestLite.defaultForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_FOO
-        this[UnittestLite.defaultImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_FOO
-        this[UnittestLite.defaultStringPieceExtensionLite] = "424"
-        this[UnittestLite.defaultCordExtensionLite] = "425"
-        this[UnittestLite.oneofUint32ExtensionLite] = 601
-        this[UnittestLite.oneofNestedMessageExtensionLite] =
-          TestAllTypesLiteKt.nestedMessage { bb = 602 }
-        this[UnittestLite.oneofStringExtensionLite] = "603"
-        this[UnittestLite.oneofBytesExtensionLite] = toBytes("604")
-      }
-    ).isEqualTo(
-      TestUtilLite.getAllLiteExtensionsSet()
-    )
+        testAllExtensionsLite {
+          this[UnittestLite.optionalInt32ExtensionLite] = 101
+          this[UnittestLite.optionalInt64ExtensionLite] = 102L
+          this[UnittestLite.optionalUint32ExtensionLite] = 103
+          this[UnittestLite.optionalUint64ExtensionLite] = 104L
+          this[UnittestLite.optionalSint32ExtensionLite] = 105
+          this[UnittestLite.optionalSint64ExtensionLite] = 106L
+          this[UnittestLite.optionalFixed32ExtensionLite] = 107
+          this[UnittestLite.optionalFixed64ExtensionLite] = 108L
+          this[UnittestLite.optionalSfixed32ExtensionLite] = 109
+          this[UnittestLite.optionalSfixed64ExtensionLite] = 110L
+          this[UnittestLite.optionalFloatExtensionLite] = 111F
+          this[UnittestLite.optionalDoubleExtensionLite] = 112.0
+          this[UnittestLite.optionalBoolExtensionLite] = true
+          this[UnittestLite.optionalStringExtensionLite] = "115"
+          this[UnittestLite.optionalBytesExtensionLite] = toBytes("116")
+          this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+          this[UnittestLite.optionalNestedMessageExtensionLite] =
+            TestAllTypesLiteKt.nestedMessage { bb = 118 }
+          this[UnittestLite.optionalForeignMessageExtensionLite] = foreignMessageLite { c = 119 }
+          this[UnittestLite.optionalImportMessageExtensionLite] =
+            ImportMessageLite.newBuilder().setD(120).build()
+          this[UnittestLite.optionalPublicImportMessageExtensionLite] =
+            PublicImportMessageLite.newBuilder().setE(126).build()
+          this[UnittestLite.optionalLazyMessageExtensionLite] =
+            TestAllTypesLiteKt.nestedMessage { bb = 127 }
+          this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+          this[UnittestLite.optionalForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_BAZ
+          this[UnittestLite.optionalImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_BAZ
+          this[UnittestLite.optionalStringPieceExtensionLite] = "124"
+          this[UnittestLite.optionalCordExtensionLite] = "125"
+          this[UnittestLite.repeatedInt32ExtensionLite].add(201)
+          this[UnittestLite.repeatedInt64ExtensionLite].add(202L)
+          this[UnittestLite.repeatedUint32ExtensionLite].add(203)
+          this[UnittestLite.repeatedUint64ExtensionLite].add(204L)
+          this[UnittestLite.repeatedSint32ExtensionLite].add(205)
+          this[UnittestLite.repeatedSint64ExtensionLite].add(206L)
+          this[UnittestLite.repeatedFixed32ExtensionLite].add(207)
+          this[UnittestLite.repeatedFixed64ExtensionLite].add(208L)
+          this[UnittestLite.repeatedSfixed32ExtensionLite].add(209)
+          this[UnittestLite.repeatedSfixed64ExtensionLite].add(210L)
+          this[UnittestLite.repeatedFloatExtensionLite].add(211F)
+          this[UnittestLite.repeatedDoubleExtensionLite].add(212.0)
+          this[UnittestLite.repeatedBoolExtensionLite].add(true)
+          this[UnittestLite.repeatedStringExtensionLite].add("215")
+          this[UnittestLite.repeatedBytesExtensionLite].add(toBytes("216"))
+          this[UnittestLite.repeatedGroupExtensionLite].add(repeatedGroupExtensionLite { a = 217 })
+          this[UnittestLite.repeatedNestedMessageExtensionLite].add(
+            TestAllTypesLiteKt.nestedMessage { bb = 218 }
+          )
+          this[UnittestLite.repeatedForeignMessageExtensionLite].add(foreignMessageLite { c = 219 })
+          this[UnittestLite.repeatedImportMessageExtensionLite].add(
+            ImportMessageLite.newBuilder().setD(220).build()
+          )
+          this[UnittestLite.repeatedLazyMessageExtensionLite].add(
+            TestAllTypesLiteKt.nestedMessage { bb = 227 }
+          )
+          this[UnittestLite.repeatedNestedEnumExtensionLite].add(NestedEnum.BAR)
+          this[UnittestLite.repeatedForeignEnumExtensionLite].add(ForeignEnumLite.FOREIGN_LITE_BAR)
+          this[UnittestLite.repeatedImportEnumExtensionLite].add(ImportEnumLite.IMPORT_LITE_BAR)
+          this[UnittestLite.repeatedStringPieceExtensionLite].add("224")
+          this[UnittestLite.repeatedCordExtensionLite].add("225")
+          this[UnittestLite.repeatedInt32ExtensionLite] += 301
+          this[UnittestLite.repeatedInt64ExtensionLite] += 302L
+          this[UnittestLite.repeatedUint32ExtensionLite] += 303
+          this[UnittestLite.repeatedUint64ExtensionLite] += 304L
+          this[UnittestLite.repeatedSint32ExtensionLite] += 305
+          this[UnittestLite.repeatedSint64ExtensionLite] += 306L
+          this[UnittestLite.repeatedFixed32ExtensionLite] += 307
+          this[UnittestLite.repeatedFixed64ExtensionLite] += 308L
+          this[UnittestLite.repeatedSfixed32ExtensionLite] += 309
+          this[UnittestLite.repeatedSfixed64ExtensionLite] += 310L
+          this[UnittestLite.repeatedFloatExtensionLite] += 311F
+          this[UnittestLite.repeatedDoubleExtensionLite] += 312.0
+          this[UnittestLite.repeatedBoolExtensionLite] += false
+          this[UnittestLite.repeatedStringExtensionLite] += "315"
+          this[UnittestLite.repeatedBytesExtensionLite] += toBytes("316")
+          this[UnittestLite.repeatedGroupExtensionLite] += repeatedGroupExtensionLite { a = 317 }
+          this[UnittestLite.repeatedNestedMessageExtensionLite] +=
+            TestAllTypesLiteKt.nestedMessage { bb = 318 }
+          this[UnittestLite.repeatedForeignMessageExtensionLite] += foreignMessageLite { c = 319 }
+          this[UnittestLite.repeatedImportMessageExtensionLite] +=
+            ImportMessageLite.newBuilder().setD(320).build()
+          this[UnittestLite.repeatedLazyMessageExtensionLite] +=
+            TestAllTypesLiteKt.nestedMessage { bb = 327 }
+          this[UnittestLite.repeatedNestedEnumExtensionLite] += NestedEnum.BAZ
+          this[UnittestLite.repeatedForeignEnumExtensionLite] += ForeignEnumLite.FOREIGN_LITE_BAZ
+          this[UnittestLite.repeatedImportEnumExtensionLite] += ImportEnumLite.IMPORT_LITE_BAZ
+          this[UnittestLite.repeatedStringPieceExtensionLite] += "324"
+          this[UnittestLite.repeatedCordExtensionLite] += "325"
+          this[UnittestLite.defaultInt32ExtensionLite] = 401
+          this[UnittestLite.defaultInt64ExtensionLite] = 402L
+          this[UnittestLite.defaultUint32ExtensionLite] = 403
+          this[UnittestLite.defaultUint64ExtensionLite] = 404L
+          this[UnittestLite.defaultSint32ExtensionLite] = 405
+          this[UnittestLite.defaultSint64ExtensionLite] = 406L
+          this[UnittestLite.defaultFixed32ExtensionLite] = 407
+          this[UnittestLite.defaultFixed64ExtensionLite] = 408L
+          this[UnittestLite.defaultSfixed32ExtensionLite] = 409
+          this[UnittestLite.defaultSfixed64ExtensionLite] = 410L
+          this[UnittestLite.defaultFloatExtensionLite] = 411F
+          this[UnittestLite.defaultDoubleExtensionLite] = 412.0
+          this[UnittestLite.defaultBoolExtensionLite] = false
+          this[UnittestLite.defaultStringExtensionLite] = "415"
+          this[UnittestLite.defaultBytesExtensionLite] = toBytes("416")
+          this[UnittestLite.defaultNestedEnumExtensionLite] = NestedEnum.FOO
+          this[UnittestLite.defaultForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_FOO
+          this[UnittestLite.defaultImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_FOO
+          this[UnittestLite.defaultStringPieceExtensionLite] = "424"
+          this[UnittestLite.defaultCordExtensionLite] = "425"
+          this[UnittestLite.oneofUint32ExtensionLite] = 601
+          this[UnittestLite.oneofNestedMessageExtensionLite] =
+            TestAllTypesLiteKt.nestedMessage { bb = 602 }
+          this[UnittestLite.oneofStringExtensionLite] = "603"
+          this[UnittestLite.oneofBytesExtensionLite] = toBytes("604")
+        }
+      )
+      .isEqualTo(TestUtilLite.getAllLiteExtensionsSet())
   }
 
   @Test
@@ -584,78 +560,72 @@
         .isEqualTo(listOf("5", "2", "3", "4"))
 
       this[UnittestLite.repeatedGroupExtensionLite].addAll(
-        listOf(
-          repeatedGroupExtensionLite { a = 1 },
-          repeatedGroupExtensionLite { a = 2 }
-        )
+        listOf(repeatedGroupExtensionLite { a = 1 }, repeatedGroupExtensionLite { a = 2 })
       )
-      assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
-        listOf(
-          repeatedGroupExtensionLite { a = 1 },
-          repeatedGroupExtensionLite { a = 2 }
+      assertThat(this[UnittestLite.repeatedGroupExtensionLite])
+        .isEqualTo(
+          listOf(repeatedGroupExtensionLite { a = 1 }, repeatedGroupExtensionLite { a = 2 })
         )
-      )
       this[UnittestLite.repeatedGroupExtensionLite] +=
-        listOf(
-          repeatedGroupExtensionLite { a = 3 },
-          repeatedGroupExtensionLite { a = 4 }
+        listOf(repeatedGroupExtensionLite { a = 3 }, repeatedGroupExtensionLite { a = 4 })
+      assertThat(this[UnittestLite.repeatedGroupExtensionLite])
+        .isEqualTo(
+          listOf(
+            repeatedGroupExtensionLite { a = 1 },
+            repeatedGroupExtensionLite { a = 2 },
+            repeatedGroupExtensionLite { a = 3 },
+            repeatedGroupExtensionLite { a = 4 }
+          )
         )
-      assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
-        listOf(
-          repeatedGroupExtensionLite { a = 1 },
-          repeatedGroupExtensionLite { a = 2 },
-          repeatedGroupExtensionLite { a = 3 },
-          repeatedGroupExtensionLite { a = 4 }
-        )
-      )
       this[UnittestLite.repeatedGroupExtensionLite][0] = repeatedGroupExtensionLite { a = 5 }
-      assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
-        listOf(
-          repeatedGroupExtensionLite { a = 5 },
-          repeatedGroupExtensionLite { a = 2 },
-          repeatedGroupExtensionLite { a = 3 },
-          repeatedGroupExtensionLite { a = 4 }
+      assertThat(this[UnittestLite.repeatedGroupExtensionLite])
+        .isEqualTo(
+          listOf(
+            repeatedGroupExtensionLite { a = 5 },
+            repeatedGroupExtensionLite { a = 2 },
+            repeatedGroupExtensionLite { a = 3 },
+            repeatedGroupExtensionLite { a = 4 }
+          )
         )
-      )
 
       this[UnittestLite.repeatedNestedMessageExtensionLite].addAll(
         listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
       )
-      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
-        listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
-      )
+      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite])
+        .isEqualTo(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
       this[UnittestLite.repeatedNestedMessageExtensionLite] +=
         listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
-      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
-        listOf(
-          nestedMessage { bb = 1 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite])
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 1 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
       this[UnittestLite.repeatedNestedMessageExtensionLite][0] = nestedMessage { bb = 5 }
-      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
-        listOf(
-          nestedMessage { bb = 5 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite])
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 5 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
 
-      this[UnittestLite.repeatedNestedEnumExtensionLite]
-        .addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+      this[UnittestLite.repeatedNestedEnumExtensionLite].addAll(
+        listOf(NestedEnum.FOO, NestedEnum.BAR)
+      )
       assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite])
         .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
       this[UnittestLite.repeatedNestedEnumExtensionLite] += listOf(NestedEnum.BAZ, NestedEnum.FOO)
-      assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
-        listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite])
+        .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
       this[UnittestLite.repeatedNestedEnumExtensionLite][0] = NestedEnum.BAR
-      assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
-        listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite])
+        .isEqualTo(listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
     }
   }
 
@@ -726,62 +696,56 @@
 
   @Test
   fun testEmptyMessages() {
-    assertThat(
-      testEmptyMessageLite {}
-    ).isEqualTo(
-      TestEmptyMessageLite.newBuilder().build()
-    )
+    assertThat(testEmptyMessageLite {}).isEqualTo(TestEmptyMessageLite.newBuilder().build())
 
-    assertThat(
-      testEmptyMessageWithExtensionsLite {}
-    ).isEqualTo(
-      TestEmptyMessageWithExtensionsLite.newBuilder().build()
-    )
+    assertThat(testEmptyMessageWithExtensionsLite {})
+      .isEqualTo(TestEmptyMessageWithExtensionsLite.newBuilder().build())
   }
 
   @Test
   fun testMapSetters() {
     assertThat(
-      testMapLite {
-        mapInt32Int32[1] = 2
-        mapInt64Int64[1L] = 2L
-        mapUint32Uint32[1] = 2
-        mapUint64Uint64[1L] = 2L
-        mapSint32Sint32[1] = 2
-        mapSint64Sint64[1L] = 2L
-        mapFixed32Fixed32[1] = 2
-        mapFixed64Fixed64[1L] = 2L
-        mapSfixed32Sfixed32[1] = 2
-        mapSfixed64Sfixed64[1L] = 2L
-        mapInt32Float[1] = 2F
-        mapInt32Double[1] = 2.0
-        mapBoolBool[true] = true
-        mapStringString["1"] = "2"
-        mapInt32Bytes[1] = toBytes("2")
-        mapInt32Enum[1] = MapEnumLite.MAP_ENUM_FOO_LITE
-        mapInt32ForeignMessage[1] = foreignMessageLite { c = 1 }
-      }
-    ).isEqualTo(
-      TestMapLite.newBuilder()
-        .putMapInt32Int32(1, 2)
-        .putMapInt64Int64(1L, 2L)
-        .putMapUint32Uint32(1, 2)
-        .putMapUint64Uint64(1L, 2L)
-        .putMapSint32Sint32(1, 2)
-        .putMapSint64Sint64(1L, 2L)
-        .putMapFixed32Fixed32(1, 2)
-        .putMapFixed64Fixed64(1L, 2L)
-        .putMapSfixed32Sfixed32(1, 2)
-        .putMapSfixed64Sfixed64(1L, 2L)
-        .putMapInt32Float(1, 2F)
-        .putMapInt32Double(1, 2.0)
-        .putMapBoolBool(true, true)
-        .putMapStringString("1", "2")
-        .putMapInt32Bytes(1, toBytes("2"))
-        .putMapInt32Enum(1, MapEnumLite.MAP_ENUM_FOO_LITE)
-        .putMapInt32ForeignMessage(1, foreignMessageLite { c = 1 })
-        .build()
-    )
+        testMapLite {
+          mapInt32Int32[1] = 2
+          mapInt64Int64[1L] = 2L
+          mapUint32Uint32[1] = 2
+          mapUint64Uint64[1L] = 2L
+          mapSint32Sint32[1] = 2
+          mapSint64Sint64[1L] = 2L
+          mapFixed32Fixed32[1] = 2
+          mapFixed64Fixed64[1L] = 2L
+          mapSfixed32Sfixed32[1] = 2
+          mapSfixed64Sfixed64[1L] = 2L
+          mapInt32Float[1] = 2F
+          mapInt32Double[1] = 2.0
+          mapBoolBool[true] = true
+          mapStringString["1"] = "2"
+          mapInt32Bytes[1] = toBytes("2")
+          mapInt32Enum[1] = MapEnumLite.MAP_ENUM_FOO_LITE
+          mapInt32ForeignMessage[1] = foreignMessageLite { c = 1 }
+        }
+      )
+      .isEqualTo(
+        TestMapLite.newBuilder()
+          .putMapInt32Int32(1, 2)
+          .putMapInt64Int64(1L, 2L)
+          .putMapUint32Uint32(1, 2)
+          .putMapUint64Uint64(1L, 2L)
+          .putMapSint32Sint32(1, 2)
+          .putMapSint64Sint64(1L, 2L)
+          .putMapFixed32Fixed32(1, 2)
+          .putMapFixed64Fixed64(1L, 2L)
+          .putMapSfixed32Sfixed32(1, 2)
+          .putMapSfixed64Sfixed64(1L, 2L)
+          .putMapInt32Float(1, 2F)
+          .putMapInt32Double(1, 2.0)
+          .putMapBoolBool(true, true)
+          .putMapStringString("1", "2")
+          .putMapInt32Bytes(1, toBytes("2"))
+          .putMapInt32Enum(1, MapEnumLite.MAP_ENUM_FOO_LITE)
+          .putMapInt32ForeignMessage(1, foreignMessageLite { c = 1 })
+          .build()
+      )
   }
 
   @Test
@@ -804,38 +768,38 @@
       mapInt32Enum.put(1, MapEnumLite.MAP_ENUM_FOO_LITE)
       assertThat(mapInt32Enum).isEqualTo(mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE))
       mapInt32Enum[2] = MapEnumLite.MAP_ENUM_BAR_LITE
-      assertThat(mapInt32Enum).isEqualTo(
-        mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
-      )
+      assertThat(mapInt32Enum)
+        .isEqualTo(mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE))
       mapInt32Enum.putAll(
         mapOf(3 to MapEnumLite.MAP_ENUM_BAZ_LITE, 4 to MapEnumLite.MAP_ENUM_FOO_LITE)
       )
-      assertThat(mapInt32Enum).isEqualTo(
-        mapOf(
-          1 to MapEnumLite.MAP_ENUM_FOO_LITE,
-          2 to MapEnumLite.MAP_ENUM_BAR_LITE,
-          3 to MapEnumLite.MAP_ENUM_BAZ_LITE,
-          4 to MapEnumLite.MAP_ENUM_FOO_LITE
+      assertThat(mapInt32Enum)
+        .isEqualTo(
+          mapOf(
+            1 to MapEnumLite.MAP_ENUM_FOO_LITE,
+            2 to MapEnumLite.MAP_ENUM_BAR_LITE,
+            3 to MapEnumLite.MAP_ENUM_BAZ_LITE,
+            4 to MapEnumLite.MAP_ENUM_FOO_LITE
+          )
         )
-      )
 
       mapInt32ForeignMessage.put(1, foreignMessageLite { c = 1 })
       assertThat(mapInt32ForeignMessage).isEqualTo(mapOf(1 to foreignMessageLite { c = 1 }))
       mapInt32ForeignMessage[2] = foreignMessageLite { c = 2 }
-      assertThat(mapInt32ForeignMessage).isEqualTo(
-        mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
-      )
+      assertThat(mapInt32ForeignMessage)
+        .isEqualTo(mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 }))
       mapInt32ForeignMessage.putAll(
         mapOf(3 to foreignMessageLite { c = 3 }, 4 to foreignMessageLite { c = 4 })
       )
-      assertThat(mapInt32ForeignMessage).isEqualTo(
-        mapOf(
-          1 to foreignMessageLite { c = 1 },
-          2 to foreignMessageLite { c = 2 },
-          3 to foreignMessageLite { c = 3 },
-          4 to foreignMessageLite { c = 4 }
+      assertThat(mapInt32ForeignMessage)
+        .isEqualTo(
+          mapOf(
+            1 to foreignMessageLite { c = 1 },
+            2 to foreignMessageLite { c = 2 },
+            3 to foreignMessageLite { c = 3 },
+            4 to foreignMessageLite { c = 4 }
+          )
         )
-      )
     }
   }
 
@@ -892,56 +856,57 @@
   @Test
   fun testEvilNames() {
     assertThat(
-      evilNamesProto2 {
-        initialized = true
-        hasFoo = true
-        bar = "foo"
-        isInitialized = true
-        fooBar = "foo"
-        aLLCAPS += "foo"
-        aLLCAPSMAP[1] = true
-        hasUnderbarPrecedingNumeric1Foo = true
-        hasUnderbarPrecedingNumeric42Bar = true
-        hasUnderbarPrecedingNumeric123Foo42BarBaz = true
-        extension += "foo"
-        class_ += 1
-        int = 1.0
-        long = true
-        boolean = 1L
-        sealed = "foo"
-        interface_ = 1F
-        in_ = 1
-        object_ = "foo"
-        cachedSize_ = "foo"
-        serializedSize_ = true
-        by = "foo"
-      }
-    ).isEqualTo(
-      EvilNamesProto2.newBuilder()
-        .setInitialized(true)
-        .setHasFoo(true)
-        .setBar("foo")
-        .setIsInitialized(true)
-        .setFooBar("foo")
-        .addALLCAPS("foo")
-        .putALLCAPSMAP(1, true)
-        .setHasUnderbarPrecedingNumeric1Foo(true)
-        .setHasUnderbarPrecedingNumeric42Bar(true)
-        .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
-        .addExtension("foo")
-        .addClass_(1)
-        .setInt(1.0)
-        .setLong(true)
-        .setBoolean(1L)
-        .setSealed("foo")
-        .setInterface(1F)
-        .setIn(1)
-        .setObject("foo")
-        .setCachedSize_("foo")
-        .setSerializedSize_(true)
-        .setBy("foo")
-        .build()
-    )
+        evilNamesProto2 {
+          initialized = true
+          hasFoo = true
+          bar = "foo"
+          isInitialized = true
+          fooBar = "foo"
+          aLLCAPS += "foo"
+          aLLCAPSMAP[1] = true
+          hasUnderbarPrecedingNumeric1Foo = true
+          hasUnderbarPrecedingNumeric42Bar = true
+          hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+          extension += "foo"
+          class_ += 1
+          int = 1.0
+          long = true
+          boolean = 1L
+          sealed = "foo"
+          interface_ = 1F
+          in_ = 1
+          object_ = "foo"
+          cachedSize_ = "foo"
+          serializedSize_ = true
+          by = "foo"
+        }
+      )
+      .isEqualTo(
+        EvilNamesProto2.newBuilder()
+          .setInitialized(true)
+          .setHasFoo(true)
+          .setBar("foo")
+          .setIsInitialized(true)
+          .setFooBar("foo")
+          .addALLCAPS("foo")
+          .putALLCAPSMAP(1, true)
+          .setHasUnderbarPrecedingNumeric1Foo(true)
+          .setHasUnderbarPrecedingNumeric42Bar(true)
+          .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+          .addExtension("foo")
+          .addClass_(1)
+          .setInt(1.0)
+          .setLong(true)
+          .setBoolean(1L)
+          .setSealed("foo")
+          .setInterface(1F)
+          .setIn(1)
+          .setObject("foo")
+          .setCachedSize_("foo")
+          .setSerializedSize_(true)
+          .setBy("foo")
+          .build()
+      )
 
     assertThat(interface_ {}).isEqualTo(Interface.newBuilder().build())
   }
diff --git a/java/kotlin/BUILD b/java/kotlin/BUILD
new file mode 100644
index 0000000..5403e6f
--- /dev/null
+++ b/java/kotlin/BUILD
@@ -0,0 +1,284 @@
+load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
+load("@rules_java//java:defs.bzl", "java_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("//:protobuf_version.bzl", "PROTOBUF_VERSION")
+
+# Kotlin generated protos depend on this and only this.
+kt_jvm_library(
+    name = "shared_runtime",
+    srcs = [
+        "src/main/kotlin/com/google/protobuf/DslList.kt",
+        "src/main/kotlin/com/google/protobuf/DslMap.kt",
+        "src/main/kotlin/com/google/protobuf/DslProxy.kt",
+        "src/main/kotlin/com/google/protobuf/ExtensionList.kt",
+        "src/main/kotlin/com/google/protobuf/ProtoDslMarker.kt",
+        "src/main/kotlin/com/google/protobuf/UnmodifiableCollections.kt",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        "//java/lite",
+    ],
+)
+
+kt_jvm_library(
+    name = "only_for_use_in_proto_generated_code_its_generator_and_tests",
+    srcs = ["src/main/kotlin/com/google/protobuf/OnlyForUseByGeneratedProtoCode.kt"],
+    visibility = ["//java:__subpackages__"],
+)
+
+kt_jvm_library(
+    name = "bytestring_lib",
+    srcs = ["src/main/kotlin/com/google/protobuf/ByteStrings.kt"],
+    deps = ["//java/lite"],
+)
+
+kt_jvm_library(
+    name = "full_extensions",
+    srcs = ["src/main/kotlin/com/google/protobuf/ExtendableMessageExtensions.kt"],
+    deps = ["//java/core"],
+)
+
+test_suite(
+    name = "tests",
+    tests = [
+        "bytestring_test",
+        "shared_tests",
+        "test_extensions",
+        "proto2_test",
+        "proto3_test",
+    ],
+)
+
+kt_jvm_library(
+    name = "bytestring_test_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/ByteStringsTest.kt"],
+    deps = [
+        ":bytestring_lib",
+        "//java/lite",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "bytestring_test",
+    runtime_deps = [":bytestring_test_library"],
+    test_class = "com.google.protobuf.kotlin.ByteStringsTest",
+)
+
+proto_library(
+    name = "example_extensible_message_proto",
+    srcs = ["src/test/proto/com/google/protobuf/example_extensible_message.proto"],
+    visibility = ["//java:__subpackages__"],
+)
+
+java_proto_library(
+    name = "example_extensible_message_java_proto",
+    deps = [":example_extensible_message_proto"],
+)
+
+kt_jvm_library(
+    name = "shared_tests_library",
+    srcs = [
+        "src/test/kotlin/com/google/protobuf/DslListTest.kt",
+        "src/test/kotlin/com/google/protobuf/DslMapTest.kt",
+        "src/test/kotlin/com/google/protobuf/ExtensionListTest.kt",
+    ],
+    deps = [
+        ":bytestring_lib",
+        ":example_extensible_message_java_proto",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:com_google_guava_guava_testlib",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "shared_tests",
+    runtime_deps = [":shared_tests_library"],
+    test_class = "com.google.protobuf.kotlin.DslListTest",
+)
+
+kt_jvm_library(
+    name = "test_extensions_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/ExtendableMessageExtensionsTest.kt"],
+    deps = [
+        ":example_extensible_message_java_proto",
+        ":full_extensions",
+        "//java/lite",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "@com_github_jetbrains_kotlin//:kotlin-test",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "test_extensions",
+    runtime_deps = [":test_extensions_library"],
+    test_class = "com.google.protobuf.kotlin.ExtendableMessageExtensionsTest",
+)
+
+proto_library(
+    name = "evil_names_proto2",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+proto_library(
+    name = "evil_names_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+java_proto_library(
+    name = "evil_names_proto2_java_proto",
+    deps = [":evil_names_proto2"],
+)
+
+java_proto_library(
+    name = "evil_names_proto3_java_proto",
+    deps = [":evil_names_proto3"],
+)
+
+proto_library(
+    name = "multiple_files_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    visibility = ["//:__subpackages__"],
+)
+
+java_proto_library( name = "multiple_files_proto3_java_proto",
+    deps = [":multiple_files_proto3"],
+)
+
+genrule(
+    name = "gen_kotlin_proto3_java_multiple_files",
+    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
+    outs = [
+        "MultipleFilesMessageAKt.kt",
+        "MultipleFilesMessageBKt.kt",
+        "MultipleFilesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
+          "$(location MultipleFilesMessageAKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
+          "$(location MultipleFilesMessageBKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
+          "$(location MultipleFilesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto2",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
+    outs = [
+        "EvilNamesProto2Kt.kt",
+        "HardKeywordsAllTypesProto2Kt.kt",
+        "InterfaceKt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
+          "$(location EvilNamesProto2Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
+          "$(location HardKeywordsAllTypesProto2Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
+          "$(location InterfaceKt.kt)",
+    tools = ["//:protoc"],
+)
+
+genrule(
+    name = "gen_evil_names_proto3",
+    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
+    outs = [
+        "ClassKt.kt",
+        "EvilNamesProto3Kt.kt",
+        "HardKeywordsAllTypesProto3Kt.kt",
+    ],
+    cmd = "$(location //:protoc) " +
+          "--kotlin_out=shared,immutable:$(@D) " +
+          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
+          "$(location ClassKt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
+          "$(location EvilNamesProto3Kt.kt) && " +
+          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
+          "$(location HardKeywordsAllTypesProto3Kt.kt)",
+    tools = ["//:protoc"],
+)
+
+kt_jvm_library(
+    name = "kotlin_unittest",
+    srcs = [
+        ":gen_evil_names_proto2",
+        "//:gen_kotlin_unittest",
+    ],
+    deps = [
+        ":evil_names_proto2_java_proto",
+        "//java/core:core",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "//:java_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "kotlin_proto3_unittest",
+    srcs = [
+        ":gen_evil_names_proto3",
+        ":gen_kotlin_proto3_java_multiple_files",
+        "//:gen_kotlin_proto3_unittest",
+    ],
+    deps = [
+        ":evil_names_proto3_java_proto",
+        ":multiple_files_proto3_java_proto",
+        "//java/core:core",
+        ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+        ":shared_runtime",
+        "//:java_test_protos",
+    ],
+)
+
+kt_jvm_library(
+    name = "proto2_test_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto2Test.kt"],
+    deps = [
+        ":kotlin_unittest",
+        "//java/core:test_util",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "proto2_test",
+    runtime_deps = [":proto2_test_library"],
+    test_class = "com.google.protobuf.kotlin.Proto2Test",
+)
+
+kt_jvm_library(
+    name = "proto3_test_library",
+    srcs = ["src/test/kotlin/com/google/protobuf/Proto3Test.kt"],
+    deps = [
+        ":kotlin_proto3_unittest",
+        "//java/core:test_util",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
+    ],
+)
+
+java_test(
+    name = "proto3_test",
+    runtime_deps = [":proto3_test_library"],
+    test_class = "com.google.protobuf.kotlin.Proto3Test",
+)
diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml
index 40394eb..0f6feb2 100644
--- a/java/kotlin/pom.xml
+++ b/java/kotlin/pom.xml
@@ -4,14 +4,14 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
   </parent>
 
   <artifactId>protobuf-kotlin</artifactId>
 
-  <name>Protocol Buffers [Core]</name>
+  <name>Protocol Buffers [Kotlin-Core]</name>
   <description>
-    Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    Kotlin core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
     efficient yet extensible format.
   </description>
 
diff --git a/java/kotlin/pom_template.xml b/java/kotlin/pom_template.xml
new file mode 100644
index 0000000..c8ddcad
--- /dev/null
+++ b/java/kotlin/pom_template.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>{groupId}</groupId>
+    <artifactId>protobuf-parent</artifactId>
+    <version>{version}</version>
+  </parent>
+
+  <artifactId>{artifactId}</artifactId>
+  <packaging>{type}</packaging>
+
+  <name>Protocol Buffers [Kotlin-Core]</name>
+  <description>
+    Kotlin core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an
+    efficient yet extensible format.
+  </description>
+
+  <properties>
+    <kotlin.version>1.5.0</kotlin.version>
+  </properties>
+
+</project>
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
index f3cbf2d..4463bc1 100644
--- a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto2Test.kt
@@ -58,6 +58,7 @@
 import protobuf_unittest.copy
 import protobuf_unittest.foreignMessage
 import protobuf_unittest.optionalGroupExtension
+import protobuf_unittest.optionalNestedMessageOrNull
 import protobuf_unittest.repeatedGroupExtension
 import protobuf_unittest.testAllExtensions
 import protobuf_unittest.testAllTypes
@@ -953,4 +954,16 @@
       assertThat(hasDo_()).isFalse()
     }
   }
+
+  @Test
+  fun testGetOrNull() {
+    val noNestedMessage = testAllTypes {}
+    assertThat(noNestedMessage.optionalNestedMessageOrNull).isEqualTo(null)
+
+    val someNestedMessage = testAllTypes {
+      optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+    }
+    assertThat(someNestedMessage.optionalNestedMessageOrNull)
+      .isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+  }
 }
diff --git a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
index 7b394da..ba69dca 100644
--- a/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
+++ b/java/kotlin/src/test/kotlin/com/google/protobuf/Proto3Test.kt
@@ -44,6 +44,7 @@
 import proto3_unittest.UnittestProto3.TestAllTypes.NestedEnum
 import proto3_unittest.UnittestProto3.TestEmptyMessage
 import proto3_unittest.copy
+import proto3_unittest.optionalNestedMessageOrNull
 import proto3_unittest.testAllTypes
 import proto3_unittest.testEmptyMessage
 import org.junit.Test
@@ -86,66 +87,61 @@
       assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
 
       repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 1 },
-          nestedMessage { bb = 2 }
-        )
-      )
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
       repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 1 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 1 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
       repeatedNestedMessage[0] = nestedMessage { bb = 5 }
-      assertThat(repeatedNestedMessage).isEqualTo(
-        listOf(
-          nestedMessage { bb = 5 },
-          nestedMessage { bb = 2 },
-          nestedMessage { bb = 3 },
-          nestedMessage { bb = 4 }
+      assertThat(repeatedNestedMessage)
+        .isEqualTo(
+          listOf(
+            nestedMessage { bb = 5 },
+            nestedMessage { bb = 2 },
+            nestedMessage { bb = 3 },
+            nestedMessage { bb = 4 }
+          )
         )
-      )
 
       repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
       assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
       repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
-      assertThat(repeatedNestedEnum).isEqualTo(
-        listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(repeatedNestedEnum)
+        .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
       repeatedNestedEnum[0] = NestedEnum.BAR
-      assertThat(repeatedNestedEnum).isEqualTo(
-        listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
-      )
+      assertThat(repeatedNestedEnum)
+        .isEqualTo(listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO))
     }
   }
 
   @Test
   fun testClears() {
     assertThat(
-      testAllTypes {
-        optionalInt32 = 101
-        clearOptionalInt32()
+        testAllTypes {
+          optionalInt32 = 101
+          clearOptionalInt32()
 
-        optionalString = "115"
-        clearOptionalString()
+          optionalString = "115"
+          clearOptionalString()
 
-        optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
-        clearOptionalNestedMessage()
+          optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+          clearOptionalNestedMessage()
 
-        optionalNestedEnum = NestedEnum.BAZ
-        clearOptionalNestedEnum()
+          optionalNestedEnum = NestedEnum.BAZ
+          clearOptionalNestedEnum()
 
-        oneofUint32 = 601
-        clearOneofUint32()
-      }
-    ).isEqualTo(
-      TestAllTypes.newBuilder().build()
-    )
+          oneofUint32 = 601
+          clearOneofUint32()
+        }
+      )
+      .isEqualTo(TestAllTypes.newBuilder().build())
   }
 
   @Test
@@ -154,126 +150,110 @@
       optionalInt32 = 101
       optionalString = "115"
     }
-    val modifiedMessage = message.copy {
-      optionalInt32 = 201
-    }
+    val modifiedMessage = message.copy { optionalInt32 = 201 }
 
-    assertThat(message).isEqualTo(
-      TestAllTypes.newBuilder()
-        .setOptionalInt32(101)
-        .setOptionalString("115")
-        .build()
-    )
-    assertThat(modifiedMessage).isEqualTo(
-      TestAllTypes.newBuilder()
-        .setOptionalInt32(201)
-        .setOptionalString("115")
-        .build()
-    )
+    assertThat(message)
+      .isEqualTo(TestAllTypes.newBuilder().setOptionalInt32(101).setOptionalString("115").build())
+    assertThat(modifiedMessage)
+      .isEqualTo(TestAllTypes.newBuilder().setOptionalInt32(201).setOptionalString("115").build())
   }
 
   @Test
   fun testOneof() {
     val message = testAllTypes {
       oneofString = "foo"
-      assertThat(oneofFieldCase)
-        .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
+      assertThat(oneofFieldCase).isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
       assertThat(oneofString).isEqualTo("foo")
       clearOneofField()
-      assertThat(oneofFieldCase)
-        .isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
+      assertThat(oneofFieldCase).isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
       oneofUint32 = 5
     }
 
-    assertThat(message.getOneofFieldCase())
-      .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
+    assertThat(message.getOneofFieldCase()).isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
     assertThat(message.getOneofUint32()).isEqualTo(5)
   }
 
   @Test
   fun testEmptyMessages() {
-    assertThat(
-      testEmptyMessage {}
-    ).isEqualTo(
-      TestEmptyMessage.newBuilder().build()
-    )
+    assertThat(testEmptyMessage {}).isEqualTo(TestEmptyMessage.newBuilder().build())
   }
 
   @Test
   fun testEvilNames() {
     assertThat(
-      evilNamesProto3 {
-        initialized = true
-        hasFoo = true
-        bar = "foo"
-        isInitialized = true
-        fooBar = "foo"
-        aLLCAPS += "foo"
-        aLLCAPSMAP[1] = true
-        hasUnderbarPrecedingNumeric1Foo = true
-        hasUnderbarPrecedingNumeric42Bar = true
-        hasUnderbarPrecedingNumeric123Foo42BarBaz = true
-        extension += "foo"
-        class_ = "foo"
-        int = 1.0
-        long = true
-        boolean = 1L
-        sealed = "foo"
-        interface_ = 1F
-        in_ = 1
-        object_ = "foo"
-        cachedSize_ = "foo"
-        serializedSize_ = true
-        value = "foo"
-        index = 1L
-        values += "foo"
-        newValues += "foo"
-        builder = true
-        k[1] = 1
-        v["foo"] = "foo"
-        key["foo"] = 1
-        map[1] = "foo"
-        pairs["foo"] = 1
-        LeadingUnderscore = "foo"
-        option = 1
-      }
-    ).isEqualTo(
-      EvilNamesProto3.newBuilder()
-        .setInitialized(true)
-        .setHasFoo(true)
-        .setBar("foo")
-        .setIsInitialized(true)
-        .setFooBar("foo")
-        .addALLCAPS("foo")
-        .putALLCAPSMAP(1, true)
-        .setHasUnderbarPrecedingNumeric1Foo(true)
-        .setHasUnderbarPrecedingNumeric42Bar(true)
-        .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
-        .addExtension("foo")
-        .setClass_("foo")
-        .setInt(1.0)
-        .setLong(true)
-        .setBoolean(1L)
-        .setSealed("foo")
-        .setInterface(1F)
-        .setIn(1)
-        .setObject("foo")
-        .setCachedSize_("foo")
-        .setSerializedSize_(true)
-        .setValue("foo")
-        .setIndex(1L)
-        .addValues("foo")
-        .addNewValues("foo")
-        .setBuilder(true)
-        .putK(1, 1)
-        .putV("foo", "foo")
-        .putKey("foo", 1)
-        .putMap(1, "foo")
-        .putPairs("foo", 1)
-        .setLeadingUnderscore("foo")
-        .setOption(1)
-        .build()
-    )
+        evilNamesProto3 {
+          initialized = true
+          hasFoo = true
+          bar = "foo"
+          isInitialized = true
+          fooBar = "foo"
+          aLLCAPS += "foo"
+          aLLCAPSMAP[1] = true
+          hasUnderbarPrecedingNumeric1Foo = true
+          hasUnderbarPrecedingNumeric42Bar = true
+          hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+          extension += "foo"
+          class_ = "foo"
+          int = 1.0
+          long = true
+          boolean = 1L
+          sealed = "foo"
+          interface_ = 1F
+          in_ = 1
+          object_ = "foo"
+          cachedSize_ = "foo"
+          serializedSize_ = true
+          value = "foo"
+          index = 1L
+          values += "foo"
+          newValues += "foo"
+          builder = true
+          k[1] = 1
+          v["foo"] = "foo"
+          key["foo"] = 1
+          map[1] = "foo"
+          pairs["foo"] = 1
+          LeadingUnderscore = "foo"
+          option = 1
+        }
+      )
+      .isEqualTo(
+        EvilNamesProto3.newBuilder()
+          .setInitialized(true)
+          .setHasFoo(true)
+          .setBar("foo")
+          .setIsInitialized(true)
+          .setFooBar("foo")
+          .addALLCAPS("foo")
+          .putALLCAPSMAP(1, true)
+          .setHasUnderbarPrecedingNumeric1Foo(true)
+          .setHasUnderbarPrecedingNumeric42Bar(true)
+          .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+          .addExtension("foo")
+          .setClass_("foo")
+          .setInt(1.0)
+          .setLong(true)
+          .setBoolean(1L)
+          .setSealed("foo")
+          .setInterface(1F)
+          .setIn(1)
+          .setObject("foo")
+          .setCachedSize_("foo")
+          .setSerializedSize_(true)
+          .setValue("foo")
+          .setIndex(1L)
+          .addValues("foo")
+          .addNewValues("foo")
+          .setBuilder(true)
+          .putK(1, 1)
+          .putV("foo", "foo")
+          .putKey("foo", 1)
+          .putMap(1, "foo")
+          .putPairs("foo", 1)
+          .setLeadingUnderscore("foo")
+          .setOption(1)
+          .build()
+      )
 
     assertThat(class_ {}).isEqualTo(Class.newBuilder().build())
   }
@@ -350,16 +330,22 @@
 
   @Test
   fun testMultipleFiles() {
-    assertThat(
-      com.google.protobuf.kotlin.generator.multipleFilesMessageA {}
-    ).isEqualTo(
-      com.google.protobuf.kotlin.generator.MultipleFilesMessageA.newBuilder().build()
-    )
+    assertThat(com.google.protobuf.kotlin.generator.multipleFilesMessageA {})
+      .isEqualTo(com.google.protobuf.kotlin.generator.MultipleFilesMessageA.newBuilder().build())
 
-    assertThat(
-      com.google.protobuf.kotlin.generator.multipleFilesMessageB {}
-    ).isEqualTo(
-      com.google.protobuf.kotlin.generator.MultipleFilesMessageB.newBuilder().build()
-    )
+    assertThat(com.google.protobuf.kotlin.generator.multipleFilesMessageB {})
+      .isEqualTo(com.google.protobuf.kotlin.generator.MultipleFilesMessageB.newBuilder().build())
+  }
+
+  @Test
+  fun testGetOrNull() {
+    val noNestedMessage = testAllTypes {}
+    assertThat(noNestedMessage.optionalNestedMessageOrNull).isEqualTo(null)
+
+    val someNestedMessage = testAllTypes {
+      optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+    }
+    assertThat(someNestedMessage.optionalNestedMessageOrNull)
+      .isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
   }
 }
diff --git a/java/lite.md b/java/lite.md
index 603609f..755a1a6 100644
--- a/java/lite.md
+++ b/java/lite.md
@@ -30,7 +30,7 @@
 <dependency>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-javalite</artifactId>
-  <version>3.18.1</version>
+  <version>3.19.4</version>
 </dependency>
 ```
 
diff --git a/java/lite/BUILD b/java/lite/BUILD
index 7089f95..fac19f6 100644
--- a/java/lite/BUILD
+++ b/java/lite/BUILD
@@ -3,8 +3,15 @@
 load("//:internal.bzl", "conformance_test")
 load("//java/internal:testing.bzl", "junit_tests")
 
-exports_files(["lite.awk"], visibility = ["//java/core:__pkg__"])
-exports_files(["pom_template.xml"], visibility = ["//java/core:__pkg__"])
+exports_files(
+    ["lite.awk"],
+    visibility = ["//java/core:__pkg__"],
+)
+
+exports_files(
+    ["pom_template.xml"],
+    visibility = ["//java/core:__pkg__"],
+)
 
 alias(
     name = "lite",
@@ -17,13 +24,26 @@
     command_line = "--java_out=lite:$(OUT)",
     runtime = ":lite",
     visibility = ["//visibility:public"],
+    # keep this in sync w/ LITE_WELL_KNOWN_PROTO_MAP in //:BUILD
+    blacklisted_protos = [
+        "//:any_proto",
+        "//:api_proto",
+        "//:duration_proto",
+        "//:empty_proto",
+        "//:field_mask_proto",
+        "//:source_context_proto",
+        "//:struct_proto",
+        "//:timestamp_proto",
+        "//:type_proto",
+        "//:wrappers_proto",
+    ],
 )
 
 test_suite(
     name = "tests",
     tests = [
-        "lite_build_test",
         "conformance_test",
+        "lite_build_test",
         "lite_tests",
         "//java/core:lite_tests",
     ],
@@ -38,21 +58,21 @@
 
 conformance_test(
     name = "conformance_test",
-    testee = "//:conformance_java_lite",
     failure_list = "//:conformance/failure_list_java_lite.txt",
+    testee = "//:conformance_java_lite",
     text_format_failure_list = "//:conformance/text_format_failure_list_java_lite.txt",
 )
 
 junit_tests(
     name = "lite_tests",
-    srcs = glob(["src/test/**/*.java"]),
     size = "small",
+    srcs = glob(["src/test/**/*.java"]),
     deps = [
         ":lite",
-        "//external:junit",
-        "//external:truth",
         "//java/core:generic_test_protos_java_proto_lite",
         "//java/core:java_test_protos_java_proto_lite",
         "//java/core:test_util_lite",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
     ],
 )
diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml
index 65e62ce..365194e 100644
--- a/java/lite/generate-test-sources-build.xml
+++ b/java/lite/generate-test-sources-build.xml
@@ -29,7 +29,6 @@
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/map_initialization_order_test.proto"/>
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/map_lite_test.proto"/>
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/map_test.proto"/>
-        <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/message_lite_extension_util_test.proto"/>
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/nested_builders_test.proto"/>
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/nested_extension.proto"/>
         <arg value="${protobuf.basedir}/java/core/${test.proto.dir}/com/google/protobuf/nested_extension_lite.proto"/>
diff --git a/java/lite/pom.xml b/java/lite/pom.xml
index ac4f25c..901ae67 100644
--- a/java/lite/pom.xml
+++ b/java/lite/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
   </parent>
 
   <artifactId>protobuf-javalite</artifactId>
@@ -232,6 +232,7 @@
                     <exclude>TypeRegistryTest.java</exclude>
                     <exclude>UnknownEnumValueTest.java</exclude>
                     <exclude>UnknownFieldSetLiteTest.java</exclude>
+                    <exclude>UnknownFieldSetPerformanceTest.java</exclude>
                     <exclude>UnknownFieldSetTest.java</exclude>
                     <exclude>WellKnownTypesTest.java</exclude>
                     <exclude>WireFormatTest.java</exclude>
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/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java b/java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java
deleted file mode 100644
index a17dda5..0000000
--- a/java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java
+++ /dev/null
@@ -1,1332 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package com.google.protobuf;
-
-import static com.google.protobuf.FieldInfo.forField;
-import static com.google.protobuf.FieldInfo.forFieldWithEnumVerifier;
-import static com.google.protobuf.FieldInfo.forMapField;
-import static com.google.protobuf.FieldInfo.forOneofMemberField;
-import static com.google.protobuf.FieldInfo.forProto2OptionalField;
-import static com.google.protobuf.FieldInfo.forProto2RequiredField;
-import static com.google.protobuf.FieldInfo.forRepeatedMessageField;
-
-import com.google.protobuf.testing.Proto2TestingLite;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2EmptyLite;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroup49;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroup69;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldGroupList51;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.FieldRequiredGroup88;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.RequiredNestedMessage;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLite.TestEnum;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithExtensions;
-import com.google.protobuf.testing.Proto2TestingLite.Proto2MessageLiteWithMaps;
-import java.lang.reflect.Field;
-
-/** A factory that generates a hard-coded info for {@link Proto2MessageLite}. */
-public final class Proto2MessageLiteInfoFactory implements MessageInfoFactory {
-  private static final Proto2MessageLiteInfoFactory instanceForRawMessageInfo =
-      new Proto2MessageLiteInfoFactory(true);
-  private static final Proto2MessageLiteInfoFactory instanceForStructuralMessageInfo =
-      new Proto2MessageLiteInfoFactory(false);
-
-  public static Proto2MessageLiteInfoFactory getInstanceForRawMessageInfo() {
-    return instanceForRawMessageInfo;
-  }
-
-  public static Proto2MessageLiteInfoFactory getInstanceForStructuralMessageInfo() {
-    return instanceForStructuralMessageInfo;
-  }
-
-  private final boolean produceRawMessageInfo;
-
-  private Proto2MessageLiteInfoFactory(boolean produceRawMessageInfo) {
-    this.produceRawMessageInfo = produceRawMessageInfo;
-  }
-
-  @Override
-  public boolean isSupported(Class<?> clazz) {
-    return true;
-  }
-
-  @Override
-  public MessageInfo messageInfoFor(Class<?> clazz) {
-    return produceRawMessageInfo ? rawMessageInfoFor(clazz) : structuralMessageInfoFor(clazz);
-  }
-
-  private MessageInfo rawMessageInfoFor(Class<?> clazz) {
-    if (Proto2MessageLite.class.isAssignableFrom(clazz)) {
-      return newRawMessageInfoForProto2MessageLite();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  private MessageInfo newRawMessageInfoForProto2MessageLite() {
-    java.lang.Object[] objects =
-        new java.lang.Object[] {
-          "testOneof_",
-          "testOneofCase_",
-          "bitField0_",
-          "bitField1_",
-          "fieldDouble1_",
-          "fieldFloat2_",
-          "fieldInt643_",
-          "fieldUint644_",
-          "fieldInt325_",
-          "fieldFixed646_",
-          "fieldFixed327_",
-          "fieldBool8_",
-          "fieldString9_",
-          "fieldMessage10_",
-          "fieldBytes11_",
-          "fieldUint3212_",
-          "fieldEnum13_",
-          Proto2MessageLite.TestEnum.internalGetVerifier(),
-          "fieldSfixed3214_",
-          "fieldSfixed6415_",
-          "fieldSint3216_",
-          "fieldSint6417_",
-          "fieldDoubleList18_",
-          "fieldFloatList19_",
-          "fieldInt64List20_",
-          "fieldUint64List21_",
-          "fieldInt32List22_",
-          "fieldFixed64List23_",
-          "fieldFixed32List24_",
-          "fieldBoolList25_",
-          "fieldStringList26_",
-          "fieldMessageList27_",
-          Proto2MessageLite.class,
-          "fieldBytesList28_",
-          "fieldUint32List29_",
-          "fieldEnumList30_",
-          Proto2MessageLite.TestEnum.internalGetVerifier(),
-          "fieldSfixed32List31_",
-          "fieldSfixed64List32_",
-          "fieldSint32List33_",
-          "fieldSint64List34_",
-          "fieldDoubleListPacked35_",
-          "fieldFloatListPacked36_",
-          "fieldInt64ListPacked37_",
-          "fieldUint64ListPacked38_",
-          "fieldInt32ListPacked39_",
-          "fieldFixed64ListPacked40_",
-          "fieldFixed32ListPacked41_",
-          "fieldBoolListPacked42_",
-          "fieldUint32ListPacked43_",
-          "fieldEnumListPacked44_",
-          Proto2MessageLite.TestEnum.internalGetVerifier(),
-          "fieldSfixed32ListPacked45_",
-          "fieldSfixed64ListPacked46_",
-          "fieldSint32ListPacked47_",
-          "fieldSint64ListPacked48_",
-          "fieldGroup49_",
-          "fieldGroupList51_",
-          Proto2MessageLite.FieldGroupList51.class,
-          Proto2MessageLite.class,
-          Proto2MessageLite.FieldGroup69.class,
-          "fieldRequiredDouble71_",
-          "fieldRequiredFloat72_",
-          "fieldRequiredInt6473_",
-          "fieldRequiredUint6474_",
-          "fieldRequiredInt3275_",
-          "fieldRequiredFixed6476_",
-          "fieldRequiredFixed3277_",
-          "fieldRequiredBool78_",
-          "fieldRequiredString79_",
-          "fieldRequiredMessage80_",
-          "fieldRequiredBytes81_",
-          "fieldRequiredUint3282_",
-          "fieldRequiredEnum83_",
-          Proto2MessageLite.TestEnum.internalGetVerifier(),
-          "fieldRequiredSfixed3284_",
-          "fieldRequiredSfixed6485_",
-          "fieldRequiredSint3286_",
-          "fieldRequiredSint6487_",
-          "fieldRequiredGroup88_",
-        };
-    // To update this after a proto change, run blaze build on proto2_message_lite.proto and copy
-    // over the String info from the proto2_message_lite_proto-lite-src.jar file in the
-    // blaze-genfiles directory.
-    java.lang.String info =
-        "\u0001U\u0001\u0002\u0001XU\u0000 \u0015\u0001\u1000\u0000\u0002\u1001\u0001\u0003"
-            + "\u1002\u0002\u0004\u1003\u0003\u0005\u1004\u0004\u0006\u1005\u0005\u0007\u1006\u0006\b\u1007\u0007"
-            + "\t\u1008\b\n"
-            + "\u1409\t\u000b\u100a\n"
-            + "\f\u100b\u000b\r"
-            + "\u100c\f\u000e\u100d\r"
-            + "\u000f\u100e\u000e\u0010\u100f\u000f\u0011\u1010\u0010\u0012\u0012\u0013\u0013"
-            + "\u0014\u0014\u0015\u0015\u0016\u0016\u0017\u0017\u0018\u0018\u0019\u0019\u001a\u001a\u001b\u041b\u001c\u001c\u001d\u001d\u001e\u001e\u001f\u001f"
-            + "  !!\"\"##$$%%&&\'\'"
-            + "(())**++,,--..//001\u1011\u0011315\u1033\u00006\u1034\u00007\u1035\u00008\u1036\u0000"
-            + "9\u1037\u0000:\u1038\u0000;\u1039\u0000<\u103a\u0000=\u103b\u0000>\u143c\u0000?\u103d"
-            + "\u0000@\u103e\u0000A\u1040\u0000B\u1041\u0000C\u1042\u0000D\u1043\u0000E\u1044\u0000"
-            + "G\u1500#H\u1501$I\u1502%J\u1503&K\u1504\'L\u1505(M\u1506)N\u1507*O\u1508+P\u1509"
-            + ",Q\u150a-R\u150b.S\u150c/T\u150d0U\u150e1V\u150f2W\u15103X\u15114";
-    return new RawMessageInfo(Proto2MessageLite.getDefaultInstance(), info, objects);
-  }
-
-  private MessageInfo structuralMessageInfoFor(Class<?> clazz) {
-    if (Proto2MessageLite.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2MessageLite();
-    } else if (FieldGroup49.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroup49();
-    } else if (FieldGroupList51.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroupList51();
-    } else if (FieldGroup69.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldGroup69();
-    } else if (FieldRequiredGroup88.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForFieldRequiredGroup88();
-    } else if (RequiredNestedMessage.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForRequiredNestedMessage();
-    } else if (Proto2EmptyLite.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2EmptyLite();
-    } else if (Proto2MessageLiteWithExtensions.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2MessageLiteWithExtensions();
-    } else if (Proto2TestingLite.FieldGroup49.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForExtensionFieldGroup49();
-    } else if (Proto2TestingLite.FieldGroupList51.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForExtensionFieldGroupList51();
-    } else if (Proto2TestingLite.Proto2MessageLiteWithMaps.class.isAssignableFrom(clazz)) {
-      return newMessageInfoForProto2MessageLiteWithMaps();
-    } else {
-      throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
-    }
-  }
-
-  /**
-   * Creates a new hard-coded info for {@link Proto2MessageLite}. Each time this is called, we
-   * manually go through the entire process of what a message would do if it self-registered its own
-   * info, including looking up each field by name. This is done for benchmarking purposes, so that
-   * we get a more accurate representation of the time it takes to perform this process.
-   */
-  private static StructuralMessageInfo newMessageInfoForProto2MessageLite() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(48);
-    builder.withCheckInitialized(
-        new int[] {
-          10, 27, 62, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
-        });
-    lookupFieldsByName(builder);
-    return builder.build();
-  }
-
-  private static void lookupFieldsByName(StructuralMessageInfo.Builder builder) {
-    Field bitField0 = field(Proto2MessageLite.class, "bitField0_");
-
-    builder.withDefaultInstance(Proto2MessageLite.getDefaultInstance());
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldDouble1_"),
-            1,
-            FieldType.DOUBLE,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldFloat2_"),
-            2,
-            FieldType.FLOAT,
-            bitField0,
-            0x00000002,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldInt643_"),
-            3,
-            FieldType.INT64,
-            bitField0,
-            0x00000004,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldUint644_"),
-            4,
-            FieldType.UINT64,
-            bitField0,
-            0x00000008,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldInt325_"),
-            5,
-            FieldType.INT32,
-            bitField0,
-            0x00000010,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldFixed646_"),
-            6,
-            FieldType.FIXED64,
-            bitField0,
-            0x00000020,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldFixed327_"),
-            7,
-            FieldType.FIXED32,
-            bitField0,
-            0x00000040,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldBool8_"),
-            8,
-            FieldType.BOOL,
-            bitField0,
-            0x00000080,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldString9_"),
-            9,
-            FieldType.STRING,
-            bitField0,
-            0x00000100,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldMessage10_"),
-            10,
-            FieldType.MESSAGE,
-            bitField0,
-            0x00000200,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldBytes11_"),
-            11,
-            FieldType.BYTES,
-            bitField0,
-            0x00000400,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldUint3212_"),
-            12,
-            FieldType.UINT32,
-            bitField0,
-            0x00000800,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldEnum13_"),
-            13,
-            FieldType.ENUM,
-            bitField0,
-            0x00001000,
-            false,
-            TestEnum.internalGetVerifier()));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldSfixed3214_"),
-            14,
-            FieldType.SFIXED32,
-            bitField0,
-            0x00002000,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldSfixed6415_"),
-            15,
-            FieldType.SFIXED64,
-            bitField0,
-            0x00004000,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldSint3216_"),
-            16,
-            FieldType.SINT32,
-            bitField0,
-            0x00008000,
-            false,
-            null));
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldSint6417_"),
-            17,
-            FieldType.SINT64,
-            bitField0,
-            0x00010000,
-            false,
-            null));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldDoubleList18_"),
-            18,
-            FieldType.DOUBLE_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFloatList19_"), 19, FieldType.FLOAT_LIST, false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldInt64List20_"), 20, FieldType.INT64_LIST, false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldUint64List21_"),
-            21,
-            FieldType.UINT64_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldInt32List22_"), 22, FieldType.INT32_LIST, false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFixed64List23_"),
-            23,
-            FieldType.FIXED64_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFixed32List24_"),
-            24,
-            FieldType.FIXED32_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldBoolList25_"), 25, FieldType.BOOL_LIST, false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldStringList26_"),
-            26,
-            FieldType.STRING_LIST,
-            false));
-    builder.withField(
-        forRepeatedMessageField(
-            field(Proto2MessageLite.class, "fieldMessageList27_"),
-            27,
-            FieldType.MESSAGE_LIST,
-            Proto2MessageLite.class));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldBytesList28_"), 28, FieldType.BYTES_LIST, false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldUint32List29_"),
-            29,
-            FieldType.UINT32_LIST,
-            false));
-    builder.withField(
-        forFieldWithEnumVerifier(
-            field(Proto2MessageLite.class, "fieldEnumList30_"),
-            30,
-            FieldType.ENUM_LIST,
-            TestEnum.internalGetVerifier()));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSfixed32List31_"),
-            31,
-            FieldType.SFIXED32_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSfixed64List32_"),
-            32,
-            FieldType.SFIXED64_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSint32List33_"),
-            33,
-            FieldType.SINT32_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSint64List34_"),
-            34,
-            FieldType.SINT64_LIST,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldDoubleListPacked35_"),
-            35,
-            FieldType.DOUBLE_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFloatListPacked36_"),
-            36,
-            FieldType.FLOAT_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldInt64ListPacked37_"),
-            37,
-            FieldType.INT64_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldUint64ListPacked38_"),
-            38,
-            FieldType.UINT64_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldInt32ListPacked39_"),
-            39,
-            FieldType.INT32_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFixed64ListPacked40_"),
-            40,
-            FieldType.FIXED64_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldFixed32ListPacked41_"),
-            41,
-            FieldType.FIXED32_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldBoolListPacked42_"),
-            42,
-            FieldType.BOOL_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldUint32ListPacked43_"),
-            43,
-            FieldType.UINT32_LIST_PACKED,
-            false));
-    builder.withField(
-        forFieldWithEnumVerifier(
-            field(Proto2MessageLite.class, "fieldEnumListPacked44_"),
-            44,
-            FieldType.ENUM_LIST_PACKED,
-            TestEnum.internalGetVerifier()));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSfixed32ListPacked45_"),
-            45,
-            FieldType.SFIXED32_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSfixed64ListPacked46_"),
-            46,
-            FieldType.SFIXED64_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSint32ListPacked47_"),
-            47,
-            FieldType.SINT32_LIST_PACKED,
-            false));
-    builder.withField(
-        forField(
-            field(Proto2MessageLite.class, "fieldSint64ListPacked48_"),
-            48,
-            FieldType.SINT64_LIST_PACKED,
-            false));
-
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2MessageLite.class, "fieldGroup49_"),
-            49,
-            FieldType.GROUP,
-            bitField0,
-            0x00020000,
-            false,
-            null));
-    builder.withField(
-        forRepeatedMessageField(
-            field(Proto2MessageLite.class, "fieldGroupList51_"),
-            51,
-            FieldType.GROUP_LIST,
-            Proto2MessageLite.FieldGroupList51.class));
-
-    OneofInfo oneof =
-        new OneofInfo(
-            0,
-            field(Proto2MessageLite.class, "testOneofCase_"),
-            field(Proto2MessageLite.class, "testOneof_"));
-    builder.withField(forOneofMemberField(53, FieldType.DOUBLE, oneof, Double.class, false, null));
-    builder.withField(forOneofMemberField(54, FieldType.FLOAT, oneof, Float.class, false, null));
-    builder.withField(forOneofMemberField(55, FieldType.INT64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(56, FieldType.UINT64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(57, FieldType.INT32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(58, FieldType.FIXED64, oneof, Long.class, false, null));
-    builder.withField(
-        forOneofMemberField(59, FieldType.FIXED32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(60, FieldType.BOOL, oneof, Boolean.class, false, null));
-    builder.withField(forOneofMemberField(61, FieldType.STRING, oneof, String.class, false, null));
-    builder.withField(
-        forOneofMemberField(62, FieldType.MESSAGE, oneof, Proto2MessageLite.class, false, null));
-    builder.withField(
-        forOneofMemberField(63, FieldType.BYTES, oneof, ByteString.class, false, null));
-    builder.withField(forOneofMemberField(64, FieldType.UINT32, oneof, Integer.class, false, null));
-    builder.withField(
-        forOneofMemberField(65, FieldType.SFIXED32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(66, FieldType.SFIXED64, oneof, Long.class, false, null));
-    builder.withField(forOneofMemberField(67, FieldType.SINT32, oneof, Integer.class, false, null));
-    builder.withField(forOneofMemberField(68, FieldType.SINT64, oneof, Long.class, false, null));
-    builder.withField(
-        forOneofMemberField(
-            69, FieldType.GROUP, oneof, Proto2MessageLite.FieldGroup69.class, false, null));
-
-    Field bitField1 = field(Proto2MessageLite.class, "bitField1_");
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredDouble71_"),
-            71,
-            FieldType.DOUBLE,
-            bitField1,
-            0x00000008,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredFloat72_"),
-            72,
-            FieldType.FLOAT,
-            bitField1,
-            0x00000010,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredInt6473_"),
-            73,
-            FieldType.INT64,
-            bitField1,
-            0x00000020,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredUint6474_"),
-            74,
-            FieldType.UINT64,
-            bitField1,
-            0x00000040,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredInt3275_"),
-            75,
-            FieldType.INT32,
-            bitField1,
-            0x00000080,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredFixed6476_"),
-            76,
-            FieldType.FIXED64,
-            bitField1,
-            0x00000100,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredFixed3277_"),
-            77,
-            FieldType.FIXED32,
-            bitField1,
-            0x00000200,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredBool78_"),
-            78,
-            FieldType.BOOL,
-            bitField1,
-            0x00000400,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredString79_"),
-            79,
-            FieldType.STRING,
-            bitField1,
-            0x00000800,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredMessage80_"),
-            80,
-            FieldType.MESSAGE,
-            bitField1,
-            0x00001000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredBytes81_"),
-            81,
-            FieldType.BYTES,
-            bitField1,
-            0x00002000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredUint3282_"),
-            82,
-            FieldType.UINT32,
-            bitField1,
-            0x00004000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredEnum83_"),
-            83,
-            FieldType.ENUM,
-            bitField1,
-            0x00008000,
-            false,
-            TestEnum.internalGetVerifier()));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredSfixed3284_"),
-            84,
-            FieldType.SFIXED32,
-            bitField1,
-            0x00010000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredSfixed6485_"),
-            85,
-            FieldType.SFIXED64,
-            bitField1,
-            0x00020000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredSint3286_"),
-            86,
-            FieldType.SINT32,
-            bitField1,
-            0x00040000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredSint6487_"),
-            87,
-            FieldType.SINT64,
-            bitField1,
-            0x00080000,
-            false,
-            null));
-    builder.withField(
-        forProto2RequiredField(
-            field(Proto2MessageLite.class, "fieldRequiredGroup88_"),
-            88,
-            FieldType.GROUP,
-            bitField1,
-            0x00100000,
-            false,
-            null));
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroup49() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroup49.class, "fieldInt3250_"),
-            50,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroupList51() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroupList51.class, "fieldInt3252_"),
-            52,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldGroup69() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldGroup69.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldGroup69.class, "fieldInt3270_"),
-            70,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForRequiredNestedMessage() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(RequiredNestedMessage.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(RequiredNestedMessage.class, "value_"),
-            1,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForFieldRequiredGroup88() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(FieldRequiredGroup88.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(FieldRequiredGroup88.class, "fieldInt3289_"),
-            89,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto2EmptyLite() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForProto2MessageLiteWithExtensions() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(0);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForExtensionFieldGroup49() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(Proto2TestingLite.FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2TestingLite.FieldGroup49.class, "fieldInt3250_"),
-            50,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-  private static StructuralMessageInfo newMessageInfoForExtensionFieldGroupList51() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder(1);
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    Field bitField0 = field(Proto2TestingLite.FieldGroup49.class, "bitField0_");
-    builder.withField(
-        forProto2OptionalField(
-            field(Proto2TestingLite.FieldGroupList51.class, "fieldInt3252_"),
-            52,
-            FieldType.INT32,
-            bitField0,
-            0x00000001,
-            false,
-            null));
-    return builder.build();
-  }
-
-
-  private static StructuralMessageInfo newMessageInfoForProto2MessageLiteWithMaps() {
-    StructuralMessageInfo.Builder builder = StructuralMessageInfo.newBuilder();
-    builder.withCheckInitialized(
-        new int[] {
-          10, 27, 44, 61, 78, 95, 112, 129, 146, 163, 180, 197,
-        });
-    builder.withSyntax(ProtoSyntax.PROTO2);
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_bool_1", 1));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_bytes_2", 2));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_double_3", 3));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_enum_4", 4));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_fixed32_5", 5));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_fixed64_6", 6));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_float_7", 7));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_int32_8", 8));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_int64_9", 9));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_message_10", 10));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sfixed32_11", 11));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sfixed64_12", 12));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sint32_13", 13));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_sint64_14", 14));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_string_15", 15));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_uint32_16", 16));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_bool_uint64_17", 17));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_bool_18", 18));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_bytes_19", 19));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_double_20", 20));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_enum_21", 21));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_fixed32_22", 22));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_fixed64_23", 23));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_float_24", 24));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_int32_25", 25));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_int64_26", 26));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_message_27", 27));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sfixed32_28", 28));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sfixed64_29", 29));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sint32_30", 30));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_sint64_31", 31));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_string_32", 32));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_uint32_33", 33));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed32_uint64_34", 34));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_bool_35", 35));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_bytes_36", 36));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_double_37", 37));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_enum_38", 38));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_fixed32_39", 39));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_fixed64_40", 40));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_float_41", 41));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_int32_42", 42));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_int64_43", 43));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_message_44", 44));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sfixed32_45", 45));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sfixed64_46", 46));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sint32_47", 47));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_sint64_48", 48));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_string_49", 49));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_uint32_50", 50));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_fixed64_uint64_51", 51));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_bool_52", 52));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_bytes_53", 53));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_double_54", 54));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_enum_55", 55));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_fixed32_56", 56));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_fixed64_57", 57));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_float_58", 58));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_int32_59", 59));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_int64_60", 60));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_message_61", 61));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sfixed32_62", 62));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sfixed64_63", 63));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sint32_64", 64));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_sint64_65", 65));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_string_66", 66));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_uint32_67", 67));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int32_uint64_68", 68));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_bool_69", 69));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_bytes_70", 70));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_double_71", 71));
-    builder.withField(mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_enum_72", 72));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_fixed32_73", 73));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_fixed64_74", 74));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_float_75", 75));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_int32_76", 76));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_int64_77", 77));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_message_78", 78));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sfixed32_79", 79));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sfixed64_80", 80));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sint32_81", 81));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_sint64_82", 82));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_string_83", 83));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_uint32_84", 84));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_int64_uint64_85", 85));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_bool_86", 86));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_bytes_87", 87));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_double_88", 88));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_enum_89", 89));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_fixed32_90", 90));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_fixed64_91", 91));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_float_92", 92));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_int32_93", 93));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_int64_94", 94));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_message_95", 95));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sfixed32_96", 96));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sfixed64_97", 97));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sint32_98", 98));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_sint64_99", 99));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_string_100", 100));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_uint32_101", 101));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed32_uint64_102", 102));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_bool_103", 103));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_bytes_104", 104));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_double_105", 105));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_enum_106", 106));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_fixed32_107", 107));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_fixed64_108", 108));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_float_109", 109));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_int32_110", 110));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_int64_111", 111));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_message_112", 112));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sfixed32_113", 113));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sfixed64_114", 114));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sint32_115", 115));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_sint64_116", 116));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_string_117", 117));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_uint32_118", 118));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sfixed64_uint64_119", 119));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_bool_120", 120));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_bytes_121", 121));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_double_122", 122));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_enum_123", 123));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_fixed32_124", 124));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_fixed64_125", 125));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_float_126", 126));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_int32_127", 127));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_int64_128", 128));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_message_129", 129));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sfixed32_130", 130));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sfixed64_131", 131));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sint32_132", 132));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_sint64_133", 133));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_string_134", 134));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_uint32_135", 135));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint32_uint64_136", 136));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_bool_137", 137));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_bytes_138", 138));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_double_139", 139));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_enum_140", 140));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_fixed32_141", 141));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_fixed64_142", 142));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_float_143", 143));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_int32_144", 144));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_int64_145", 145));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_message_146", 146));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sfixed32_147", 147));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sfixed64_148", 148));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sint32_149", 149));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_sint64_150", 150));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_string_151", 151));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_uint32_152", 152));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_sint64_uint64_153", 153));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_bool_154", 154));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_bytes_155", 155));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_double_156", 156));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_enum_157", 157));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_fixed32_158", 158));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_fixed64_159", 159));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_float_160", 160));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_int32_161", 161));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_int64_162", 162));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_message_163", 163));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sfixed32_164", 164));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sfixed64_165", 165));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sint32_166", 166));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_sint64_167", 167));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_string_168", 168));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_uint32_169", 169));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_string_uint64_170", 170));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_bool_171", 171));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_bytes_172", 172));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_double_173", 173));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_enum_174", 174));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_fixed32_175", 175));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_fixed64_176", 176));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_float_177", 177));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_int32_178", 178));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_int64_179", 179));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_message_180", 180));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sfixed32_181", 181));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sfixed64_182", 182));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sint32_183", 183));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_sint64_184", 184));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_string_185", 185));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_uint32_186", 186));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint32_uint64_187", 187));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_bool_188", 188));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_bytes_189", 189));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_double_190", 190));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_enum_191", 191));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_fixed32_192", 192));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_fixed64_193", 193));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_float_194", 194));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_int32_195", 195));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_int64_196", 196));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_message_197", 197));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sfixed32_198", 198));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sfixed64_199", 199));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sint32_200", 200));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_sint64_201", 201));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_string_202", 202));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_uint32_203", 203));
-    builder.withField(
-        mapFieldInfo(Proto2MessageLiteWithMaps.class, "field_map_uint64_uint64_204", 204));
-
-    return builder.build();
-  }
-
-  private static Field field(Class<?> clazz, String name) {
-    try {
-      return clazz.getDeclaredField(name);
-    } catch (NoSuchFieldException | SecurityException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private static FieldInfo mapFieldInfo(Class<?> clazz, String fieldName, int fieldNumber) {
-    try {
-      return forMapField(
-          field(clazz, SchemaUtil.toCamelCase(fieldName, false) + "_"),
-          fieldNumber,
-          SchemaUtil.getMapDefaultEntry(clazz, fieldName),
-          fieldName.contains("_enum_") ? TestEnum.internalGetVerifier() : null);
-    } catch (Throwable t) {
-      throw new RuntimeException(t);
-    }
-  }
-}
diff --git a/java/pom.xml b/java/pom.xml
index 9864f73..e102597 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -4,7 +4,7 @@
 
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-parent</artifactId>
-  <version>3.18.1</version>
+  <version>3.19.4</version>
   <packaging>pom</packaging>
 
   <name>Protocol Buffers [Parent]</name>
@@ -41,7 +41,7 @@
 
   <licenses>
     <license>
-      <name>3-Clause BSD License</name>
+      <name>BSD-3-Clause</name>
       <url>https://opensource.org/licenses/BSD-3-Clause</url>
       <distribution>repo</distribution>
     </license>
@@ -158,31 +158,45 @@
         </plugin>
         <plugin>
           <artifactId>maven-antrun-plugin</artifactId>
-          <version>1.8</version>
+          <version>3.0.0</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>3.0.0-M5</version>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>animal-sniffer-maven-plugin</artifactId>
           <version>1.20</version>
-          <configuration>
-            <signature>
-              <groupId>net.sf.androidscents.signature</groupId>
-              <artifactId>android-api-level-14</artifactId>
-              <version>4.0_r4</version>
-            </signature>
-          </configuration>
-          <executions>
-            <execution>
-              <id>android</id>
-              <phase>test</phase>
-              <goals>
-                <goal>check</goal>
-              </goals>
-            </execution>
-          </executions>
         </plugin>
       </plugins>
     </pluginManagement>
+    
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>animal-sniffer-maven-plugin</artifactId>
+        <configuration>
+          <signature>
+            <groupId>net.sf.androidscents.signature</groupId>
+            <artifactId>android-api-level-14</artifactId>
+            <version>4.0_r4</version>
+          </signature>
+          <ignores>
+            <ignore>sun.misc.Unsafe</ignore>
+          </ignores>
+        </configuration>
+        <executions>
+          <execution>
+            <id>android</id>
+            <phase>test</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
   </build>
 
   <profiles>
diff --git a/java/util/BUILD b/java/util/BUILD
index 02e5549..2714917 100644
--- a/java/util/BUILD
+++ b/java/util/BUILD
@@ -11,32 +11,33 @@
     ]),
     visibility = ["//visibility:public"],
     deps = [
-        "//external:error_prone_annotations",
-        "//external:j2objc_annotations",
-        "//external:gson",
-        "//external:guava",
         "//java/core",
-        "//java/lite",
+        "@maven//:com_google_code_findbugs_jsr305",
+        "@maven//:com_google_code_gson_gson",
+        "@maven//:com_google_errorprone_error_prone_annotations",
+        "@maven//:com_google_guava_guava",
+        "@maven//:com_google_j2objc_j2objc_annotations",
     ],
 )
+
 # Bazel users, don't depend on this target, use :util.
 java_export(
     name = "util_mvn",
     maven_coordinates = "com.google.protobuf:protobuf-java-util:%s" % PROTOBUF_VERSION,
     pom_template = "pom_template.xml",
-    runtime_deps = [":util"],
     visibility = ["//java:__pkg__"],
+    runtime_deps = [":util"],
 )
 
 filegroup(
     name = "release",
-    visibility = ["//java:__pkg__"],
     srcs = [
-        ":util_mvn-pom",
-        ":util_mvn-maven-source",
         ":util_mvn-docs",
+        ":util_mvn-maven-source",
+        ":util_mvn-pom",
         ":util_mvn-project",
-    ]
+    ],
+    visibility = ["//java:__pkg__"],
 )
 
 proto_library(
@@ -59,15 +60,15 @@
 
 junit_tests(
     name = "tests",
-    srcs = glob(["src/test/java/**/*.java"]),
     package_name = "com.google.protobuf.util",
+    srcs = glob(["src/test/java/**/*.java"]),
     deps = [
         ":test_protos_java_proto",
         ":util",
-        "//external:guava",
-        "//external:junit",
-        "//external:truth",
         "//java/core",
         "//java/core:generic_test_protos_java_proto",
+        "@maven//:com_google_guava_guava",
+        "@maven//:com_google_truth_truth",
+        "@maven//:junit_junit",
     ],
 )
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 31ccf5d..27c82be 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.google.protobuf</groupId>
     <artifactId>protobuf-parent</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
   </parent>
 
   <artifactId>protobuf-java-util</artifactId>
@@ -33,6 +33,11 @@
       <version>1.3</version>
     </dependency>
     <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+      <version>3.0.2</version>
+    </dependency>
+    <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava-testlib</artifactId>
       <scope>test</scope>
@@ -40,7 +45,7 @@
     <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
-      <version>2.8.6</version>
+      <version>2.8.9</version>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
@@ -112,7 +117,27 @@
           </execution>
         </executions>
       </plugin>
-
+      
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>animal-sniffer-maven-plugin</artifactId>
+        <configuration>
+          <signature>
+            <groupId>net.sf.androidscents.signature</groupId>
+            <artifactId>android-api-level-19</artifactId>
+            <version>4.4.2_r4</version>
+          </signature>
+        </configuration>
+        <executions>
+          <execution>
+            <id>android</id>
+            <phase>test</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
       <!-- Configure the OSGI bundle -->
       <plugin>
         <groupId>org.apache.felix</groupId>
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 a9932e9..29a8713 100644
--- a/js/commonjs/export.js
+++ b/js/commonjs/export.js
@@ -15,15 +15,18 @@
 goog.require('jspb.Message');
 goog.require('jspb.Map');
 
-exports.Map = jspb.Map;
-exports.Message = jspb.Message;
-exports.BinaryReader = jspb.BinaryReader;
-exports.BinaryWriter = jspb.BinaryWriter;
-exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
-exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo;
+if (typeof exports === 'object') {
+  exports.Map = jspb.Map;
+  exports.Message = jspb.Message;
+  exports.BinaryReader = jspb.BinaryReader;
+  exports.BinaryWriter = jspb.BinaryWriter;
+  exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo;
+  exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo;
 
-// These are used by generated code but should not be used directly by clients.
-exports.exportSymbol = goog.exportSymbol;
-exports.inherits = goog.inherits;
-exports.object = {extend: goog.object.extend};
-exports.typeOf = goog.typeOf;
+  // 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};
+  exports.typeOf = goog.typeOf;
+}
\ No newline at end of file
diff --git a/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto2.js b/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto2.js
index 252520f..94c2598 100644
--- a/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto2.js
+++ b/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto2.js
@@ -119,7 +119,7 @@
   arrayVal[0] = true;
   msgAllTypes.setRepeatedBoolList(arrayVal);
   msgAllTypes.setRepeatedBytesList(['']);
-  arrayVal = msgAllTypes.getRepeatedBytesList();
+  arrayVal = msgAllTypes.getRepeatedBytesList_asB64();
   arrayVal[0] = '';
   msgAllTypes.setRepeatedBytesList(arrayVal);
   msgPackedTypes.setPackedDoubleList([1.0]);
@@ -233,8 +233,7 @@
 
   let s = '';
   s += msgAllTypes.getOptionalBool() || false;
-  s += msgAllTypes.getOptionalBytes() || '';
-  // s += msgAllTypes.getOptionalBytes_asB64() || "";
+  s += msgAllTypes.getOptionalBytes_asB64() || '';
   // s += msgAllTypes.getOptionalBytes_asU8() || new Uint8Array([]);
   s += msgAllTypes.getOptionalDouble() || 0.0;
   s += msgAllTypes.getOptionalFixed32() || 0;
@@ -254,10 +253,9 @@
   s += msgAllTypes.getRepeatedBoolList();
   s += msgAllTypes.getRepeatedBoolList()[0];
   s += msgAllTypes.getRepeatedBoolList().length;
-  s += msgAllTypes.getRepeatedBytesList();
-  s += msgAllTypes.getRepeatedBytesList()[0];
-  s += msgAllTypes.getRepeatedBytesList().length;
   s += msgAllTypes.getRepeatedBytesList_asB64();
+  s += msgAllTypes.getRepeatedBytesList_asB64()[0];
+  s += msgAllTypes.getRepeatedBytesList_asB64().length;
   s += msgAllTypes.getRepeatedBytesList_asU8();
   s += msgAllTypes.getRepeatedDoubleList();
   s += msgAllTypes.getRepeatedDoubleList()[0];
diff --git a/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto3.js b/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto3.js
index 3637df6..9eb8126 100644
--- a/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto3.js
+++ b/js/experimental/benchmarks/code_size/apps_jspb/all_types_proto3.js
@@ -119,7 +119,7 @@
   arrayVal[0] = true;
   msgAllTypes.setRepeatedBoolList(arrayVal);
   msgAllTypes.setRepeatedBytesList(['']);
-  arrayVal = msgAllTypes.getRepeatedBytesList();
+  arrayVal = msgAllTypes.getRepeatedBytesList_asB64();
   arrayVal[0] = '';
   msgAllTypes.setRepeatedBytesList(arrayVal);
   msgPackedTypes.setPackedDoubleList([1.0]);
@@ -233,8 +233,7 @@
 
   let s = '';
   s += msgAllTypes.getOptionalBool() || false;
-  s += msgAllTypes.getOptionalBytes() || '';
-  // s += msgAllTypes.getOptionalBytes_asB64() || "";
+  s += msgAllTypes.getOptionalBytes_asB64() || '';
   // s += msgAllTypes.getOptionalBytes_asU8() || new Uint8Array([]);
   s += msgAllTypes.getOptionalDouble() || 0.0;
   s += msgAllTypes.getOptionalFixed32() || 0;
@@ -254,10 +253,9 @@
   s += msgAllTypes.getRepeatedBoolList();
   s += msgAllTypes.getRepeatedBoolList()[0];
   s += msgAllTypes.getRepeatedBoolList().length;
-  s += msgAllTypes.getRepeatedBytesList();
-  s += msgAllTypes.getRepeatedBytesList()[0];
-  s += msgAllTypes.getRepeatedBytesList().length;
   s += msgAllTypes.getRepeatedBytesList_asB64();
+  s += msgAllTypes.getRepeatedBytesList_asB64()[0];
+  s += msgAllTypes.getRepeatedBytesList_asB64().length;
   s += msgAllTypes.getRepeatedBytesList_asU8();
   s += msgAllTypes.getRepeatedDoubleList();
   s += msgAllTypes.getRepeatedDoubleList()[0];
diff --git a/js/experimental/runtime/kernel/reader.js b/js/experimental/runtime/kernel/reader.js
index 2b80e15..44708b5 100644
--- a/js/experimental/runtime/kernel/reader.js
+++ b/js/experimental/runtime/kernel/reader.js
@@ -98,19 +98,6 @@
 }
 
 /**
- * Reads a sint32 value from the binary bytes encoded as varint.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} start Start of the data.
- * @return {number}
- * @package
- */
-function readSint32(bufferDecoder, start) {
-  const bits = bufferDecoder.getUnsignedVarint32At(start);
-  // Truncate upper bits and convert from zig zag to signd int
-  return (bits >>> 1) ^ -(bits & 0x01);
-}
-
-/**
  * Reads a sint64 value from the binary bytes encoded as varint.
  * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
  * @param {number} start Start of the data.
@@ -126,6 +113,17 @@
 }
 
 /**
+ * Reads a sint32 value from the binary bytes encoded as varint.
+ * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
+ * @param {number} start Start of the data.
+ * @return {number}
+ * @package
+ */
+function readSint32(bufferDecoder, start) {
+  return readSint64(bufferDecoder, start).getLowBits();
+}
+
+/**
  * Read a subarray of bytes representing a length delimited field.
  * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
  * @param {number} start Start of the data.
diff --git a/kokoro/linux/64-bit/Dockerfile b/kokoro/linux/64-bit/Dockerfile
index 3a279e6..189d0cf 100644
--- a/kokoro/linux/64-bit/Dockerfile
+++ b/kokoro/linux/64-bit/Dockerfile
@@ -60,8 +60,6 @@
   nunit \
   # -- For all Java builds -- \
   maven \
-  # -- For java_jdk6 -- \
-  #   oops! not in jessie. too old? openjdk-6-jdk \
   # -- For java_jdk7 -- \
   openjdk-7-jdk \
   # -- For java_oracle7 -- \
diff --git a/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh b/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh
index 527fc48..5026d04 100755
--- a/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh
+++ b/kokoro/linux/aarch64/python_run_tests_with_qemu_aarch64.sh
@@ -7,7 +7,7 @@
 cd python
 
 PYTHON="/opt/python/cp38-cp38/bin/python"
-${PYTHON} -m pip install --user six pytest auditwheel
+${PYTHON} -m pip install --user pytest auditwheel
 
 # check that we are really using aarch64 python
 (${PYTHON} -c 'import sysconfig; print(sysconfig.get_platform())' | grep -q "linux-aarch64") || (echo "Wrong python platform, needs to be aarch64 python."; exit 1)
diff --git a/kokoro/linux/aarch64/test_csharp_aarch64.sh b/kokoro/linux/aarch64/test_csharp_aarch64.sh
index 450bb1e..cc3bffe 100755
--- a/kokoro/linux/aarch64/test_csharp_aarch64.sh
+++ b/kokoro/linux/aarch64/test_csharp_aarch64.sh
@@ -15,8 +15,8 @@
 # First, build protobuf C# tests under x86_64 docker image
 # Tests are built "dotnet publish" because we want all the dependencies to the copied to the destination directory
 # (we want to avoid references to ~/.nuget that won't be available in the subsequent docker run)
-CSHARP_BUILD_COMMAND="dotnet publish -c Release -f net50 csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj"
-docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -e "DOTNET_CLI_TELEMETRY_OPTOUT=true" -e "DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work mcr.microsoft.com/dotnet/sdk:5.0.202-buster-slim bash -c "$CSHARP_BUILD_COMMAND"
+CSHARP_BUILD_COMMAND="dotnet publish -c Release -f net60 csharp/src/Google.Protobuf.Test/Google.Protobuf.Test.csproj"
+docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -e "DOTNET_CLI_TELEMETRY_OPTOUT=true" -e "DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim bash -c "$CSHARP_BUILD_COMMAND"
 
 # Use an actual aarch64 docker image to run protobuf C# tests with an emulator. "dotnet vstest" allows
 # running tests from a pre-built project.
@@ -25,5 +25,5 @@
 #   running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user
 #   otherwise the UID would be homeless under the docker container and pip install wouldn't work. For simplicity,
 #   we just run map the user's home to a throwaway temporary directory
-CSHARP_TEST_COMMAND="dotnet vstest csharp/src/Google.Protobuf.Test/bin/Release/net50/publish/Google.Protobuf.Test.dll"
-docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -e "DOTNET_CLI_TELEMETRY_OPTOUT=true" -e "DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work mcr.microsoft.com/dotnet/sdk:5.0.202-buster-slim-arm64v8 bash -c "$CSHARP_TEST_COMMAND"
+CSHARP_TEST_COMMAND="dotnet vstest csharp/src/Google.Protobuf.Test/bin/Release/net60/publish/Google.Protobuf.Test.dll"
+docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -e "DOTNET_CLI_TELEMETRY_OPTOUT=true" -e "DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim-arm64v8 bash -c "$CSHARP_TEST_COMMAND"
diff --git a/kokoro/linux/bazel/build.sh b/kokoro/linux/bazel/build.sh
index 5ec92ce..d0d4b3e 100755
--- a/kokoro/linux/bazel/build.sh
+++ b/kokoro/linux/bazel/build.sh
@@ -35,5 +35,13 @@
   @com_google_protobuf//:cc_proto_blacklist_test
 trap - EXIT
 
-cd examples
+pushd examples
 bazel build //...
+popd
+
+# Verify that we can build successfully from generated tar files.
+./autogen.sh && ./configure && make -j$(nproc) dist
+DIST=`ls *.tar.gz`
+tar -xf $DIST
+cd ${DIST//.tar.gz}
+bazel build //:protobuf //:protobuf_java
diff --git a/kokoro/linux/benchmark/run.sh b/kokoro/linux/benchmark/run.sh
index 502f436..acd8737 100755
--- a/kokoro/linux/benchmark/run.sh
+++ b/kokoro/linux/benchmark/run.sh
@@ -23,8 +23,10 @@
 ./configure CXXFLAGS="-fPIC -O2"
 make -j8
 pushd python
-python setup.py build --cpp_implementation
-pip install . --user
+virtualenv -p python3 env
+source env/bin/activate
+python3 setup.py build --cpp_implementation
+pip3 install --install-option="--cpp_implementation" .
 popd
 
 # build and run Python benchmark
@@ -91,7 +93,7 @@
 # print the postprocessed results to the build job log
 # TODO(jtattermusch): re-enable uploading results to bigquery (it is currently broken)
 make python_add_init
-env LD_LIBRARY_PATH="${repo_root}/src/.libs" python -m util.result_parser \
+env LD_LIBRARY_PATH="${repo_root}/src/.libs" python3 -m util.result_parser \
 	-cpp="../tmp/cpp_result.json" -java="../tmp/java_result.json" -python="../tmp/python_result.json"
 popd
 
diff --git a/kokoro/linux/dockerfile/test/csharp/Dockerfile b/kokoro/linux/dockerfile/test/csharp/Dockerfile
index 37edbfd..c07fcbc 100644
--- a/kokoro/linux/dockerfile/test/csharp/Dockerfile
+++ b/kokoro/linux/dockerfile/test/csharp/Dockerfile
@@ -32,8 +32,8 @@
 # Install dotnet SDK via install script
 RUN wget -q https://dot.net/v1/dotnet-install.sh && \
     chmod u+x dotnet-install.sh && \
-    ./dotnet-install.sh --version 2.1.802 && \
-    ./dotnet-install.sh --version 5.0.102 && \
+    ./dotnet-install.sh --version 3.1.415 && \
+    ./dotnet-install.sh --version 6.0.100 && \
     ln -s /root/.dotnet/dotnet /usr/local/bin
 
 RUN wget -q www.nuget.org/NuGet.exe -O /usr/local/bin/nuget.exe
diff --git a/kokoro/linux/dockerfile/test/python310/Dockerfile b/kokoro/linux/dockerfile/test/python310/Dockerfile
new file mode 100644
index 0000000..e16e93b
--- /dev/null
+++ b/kokoro/linux/dockerfile/test/python310/Dockerfile
@@ -0,0 +1,31 @@
+FROM python:3.10-buster
+
+# Install dependencies.  We start with the basic ones require to build protoc
+# and the C++ build
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  parallel \
+  time \
+  wget \
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+# Install Python libraries.
+RUN python -m pip install --no-cache-dir --upgrade \
+  pip \
+  setuptools \
+  tox \
+  wheel
diff --git a/kokoro/linux/dockerfile/test/ruby/Dockerfile b/kokoro/linux/dockerfile/test/ruby/Dockerfile
index 2affd14..8362870 100644
--- a/kokoro/linux/dockerfile/test/ruby/Dockerfile
+++ b/kokoro/linux/dockerfile/test/ruby/Dockerfile
@@ -29,10 +29,8 @@
 RUN gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys \
     409B6B1796C275462A1703113804BB82D39DC0E3 \
     7D2BAF1CF37B13E2069D6956105BD0E739499BDB
-RUN \curl -sSL https://get.rvm.io | bash -s master
+RUN \curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s master
 
-RUN /bin/bash -l -c "rvm install 2.3.8"
-RUN /bin/bash -l -c "rvm install 2.4.5"
 RUN /bin/bash -l -c "rvm install 2.5.1"
 RUN /bin/bash -l -c "rvm install 2.6.0"
 RUN /bin/bash -l -c "rvm install 2.7.0"
diff --git a/kokoro/linux/ruby24/build.sh b/kokoro/linux/python310/build.sh
similarity index 85%
rename from kokoro/linux/ruby24/build.sh
rename to kokoro/linux/python310/build.sh
index 68585aa..0d8a2c9 100755
--- a/kokoro/linux/ruby24/build.sh
+++ b/kokoro/linux/python310/build.sh
@@ -11,8 +11,8 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/ruby
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python310
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
-export TEST_SET="ruby24"
+export TEST_SET="python310"
 ./kokoro/linux/build_and_run_docker.sh
diff --git a/kokoro/linux/ruby24/continuous.cfg b/kokoro/linux/python310/continuous.cfg
similarity index 75%
rename from kokoro/linux/ruby24/continuous.cfg
rename to kokoro/linux/python310/continuous.cfg
index a1ccfc0..6ec74d8 100644
--- a/kokoro/linux/ruby24/continuous.cfg
+++ b/kokoro/linux/python310/continuous.cfg
@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby24/build.sh"
+build_file: "protobuf/kokoro/linux/python310/build.sh"
 timeout_mins: 120
 
 action {
diff --git a/kokoro/linux/ruby24/continuous.cfg b/kokoro/linux/python310/presubmit.cfg
similarity index 75%
copy from kokoro/linux/ruby24/continuous.cfg
copy to kokoro/linux/python310/presubmit.cfg
index a1ccfc0..6ec74d8 100644
--- a/kokoro/linux/ruby24/continuous.cfg
+++ b/kokoro/linux/python310/presubmit.cfg
@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby24/build.sh"
+build_file: "protobuf/kokoro/linux/python310/build.sh"
 timeout_mins: 120
 
 action {
diff --git a/kokoro/linux/ruby24/build.sh b/kokoro/linux/python310_cpp/build.sh
similarity index 84%
copy from kokoro/linux/ruby24/build.sh
copy to kokoro/linux/python310_cpp/build.sh
index 68585aa..2903a2d 100755
--- a/kokoro/linux/ruby24/build.sh
+++ b/kokoro/linux/python310_cpp/build.sh
@@ -11,8 +11,8 @@
 cd $(dirname $0)/../../..
 
 export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/ruby
+export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/python310
 export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
 export OUTPUT_DIR=testoutput
-export TEST_SET="ruby24"
+export TEST_SET="python310_cpp"
 ./kokoro/linux/build_and_run_docker.sh
diff --git a/kokoro/linux/ruby24/continuous.cfg b/kokoro/linux/python310_cpp/continuous.cfg
similarity index 74%
copy from kokoro/linux/ruby24/continuous.cfg
copy to kokoro/linux/python310_cpp/continuous.cfg
index a1ccfc0..7ec8441 100644
--- a/kokoro/linux/ruby24/continuous.cfg
+++ b/kokoro/linux/python310_cpp/continuous.cfg
@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby24/build.sh"
+build_file: "protobuf/kokoro/linux/python310_cpp/build.sh"
 timeout_mins: 120
 
 action {
diff --git a/kokoro/linux/ruby24/continuous.cfg b/kokoro/linux/python310_cpp/presubmit.cfg
similarity index 74%
copy from kokoro/linux/ruby24/continuous.cfg
copy to kokoro/linux/python310_cpp/presubmit.cfg
index a1ccfc0..7ec8441 100644
--- a/kokoro/linux/ruby24/continuous.cfg
+++ b/kokoro/linux/python310_cpp/presubmit.cfg
@@ -1,7 +1,7 @@
 # Config file for running tests in Kokoro
 
 # Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby24/build.sh"
+build_file: "protobuf/kokoro/linux/python310_cpp/build.sh"
 timeout_mins: 120
 
 action {
diff --git a/kokoro/linux/ruby23/build.sh b/kokoro/linux/ruby23/build.sh
deleted file mode 100755
index 503a320..0000000
--- a/kokoro/linux/ruby23/build.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# This is the top-level script we give to Kokoro as the entry point for
-# running the "pull request" project:
-#
-# This script selects a specific Dockerfile (for building a Docker image) and
-# a script to run inside that image.  Then we delegate to the general
-# build_and_run_docker.sh script.
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-export DOCKERHUB_ORGANIZATION=protobuftesting
-export DOCKERFILE_DIR=kokoro/linux/dockerfile/test/ruby
-export DOCKER_RUN_SCRIPT=kokoro/linux/pull_request_in_docker.sh
-export OUTPUT_DIR=testoutput
-export TEST_SET="ruby23"
-./kokoro/linux/build_and_run_docker.sh
diff --git a/kokoro/linux/ruby23/continuous.cfg b/kokoro/linux/ruby23/continuous.cfg
deleted file mode 100644
index f5c6498..0000000
--- a/kokoro/linux/ruby23/continuous.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby23/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}
diff --git a/kokoro/linux/ruby23/presubmit.cfg b/kokoro/linux/ruby23/presubmit.cfg
deleted file mode 100644
index f5c6498..0000000
--- a/kokoro/linux/ruby23/presubmit.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby23/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}
diff --git a/kokoro/linux/ruby24/presubmit.cfg b/kokoro/linux/ruby24/presubmit.cfg
deleted file mode 100644
index a1ccfc0..0000000
--- a/kokoro/linux/ruby24/presubmit.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/linux/ruby24/build.sh"
-timeout_mins: 120
-
-action {
-  define_artifacts {
-    regex: "**/sponge_log.xml"
-  }
-}
diff --git a/kokoro/macos/prepare_build_macos_rc b/kokoro/macos/prepare_build_macos_rc
index ef428fc..c0017b6 100755
--- a/kokoro/macos/prepare_build_macos_rc
+++ b/kokoro/macos/prepare_build_macos_rc
@@ -33,5 +33,8 @@
   curl -sSL https://rvm.io/mpapis.asc | gpg --import -
   curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -
 
-  curl -sSL https://get.rvm.io | bash -s stable --ruby
+  # Old OpenSSL versions cannot handle the SSL certificate used by
+  # https://get.rvm.io, so as a workaround we download RVM directly from
+  # GitHub. See this issue for details: https://github.com/rvm/rvm/issues/5133
+  curl -sSL https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer | bash -s stable --ruby
 fi
diff --git a/kokoro/macos/ruby23/build.sh b/kokoro/macos/ruby23/build.sh
deleted file mode 100755
index 5a29a99..0000000
--- a/kokoro/macos/ruby23/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-KOKORO_INSTALL_RVM=yes
-source kokoro/macos/prepare_build_macos_rc
-
-./tests.sh ruby23
diff --git a/kokoro/macos/ruby23/continuous.cfg b/kokoro/macos/ruby23/continuous.cfg
deleted file mode 100644
index c9b1f61..0000000
--- a/kokoro/macos/ruby23/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/ruby23/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/ruby23/presubmit.cfg b/kokoro/macos/ruby23/presubmit.cfg
deleted file mode 100644
index c9b1f61..0000000
--- a/kokoro/macos/ruby23/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/ruby23/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/ruby24/build.sh b/kokoro/macos/ruby24/build.sh
deleted file mode 100755
index 10ac85f..0000000
--- a/kokoro/macos/ruby24/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-#
-# Build file to set up and run tests
-
-# Change to repo root
-cd $(dirname $0)/../../..
-
-# Prepare worker environment to run tests
-KOKORO_INSTALL_RVM=yes
-source kokoro/macos/prepare_build_macos_rc
-
-./tests.sh ruby24
diff --git a/kokoro/macos/ruby24/continuous.cfg b/kokoro/macos/ruby24/continuous.cfg
deleted file mode 100644
index fada028..0000000
--- a/kokoro/macos/ruby24/continuous.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/ruby24/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/macos/ruby24/presubmit.cfg b/kokoro/macos/ruby24/presubmit.cfg
deleted file mode 100644
index fada028..0000000
--- a/kokoro/macos/ruby24/presubmit.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# Config file for running tests in Kokoro
-
-# Location of the build script in repository
-build_file: "protobuf/kokoro/macos/ruby24/build.sh"
-timeout_mins: 1440
diff --git a/kokoro/release/python/linux/build_artifacts.sh b/kokoro/release/python/linux/build_artifacts.sh
index 2407a30..9a3fc58 100755
--- a/kokoro/release/python/linux/build_artifacts.sh
+++ b/kokoro/release/python/linux/build_artifacts.sh
@@ -26,6 +26,13 @@
 export ARTIFACT_DIR=$(pwd)/artifacts
 
 git clone https://github.com/matthew-brett/multibuild.git
+# Pin multibuild scripts at a known commit to avoid potentially unwanted future changes from
+# silently creeping in (see https://github.com/protocolbuffers/protobuf/issues/9180).
+# IMPORTANT: always pin multibuild at the same commit for:
+# - linux/build_artifacts.sh
+# - linux/build_artifacts.sh
+# - windows/build_artifacts.bat
+(cd multibuild; git checkout b89bb903e94308be79abefa4f436bf123ebb1313)
 cp kokoro/release/python/linux/config.sh config.sh
 
 build_artifact_version() {
@@ -47,9 +54,23 @@
   sudo rm -rf $REPO_DIR
 }
 
-build_crosscompiled_aarch64_artifact_version() {
+build_x86_64_manylinux1_artifact_version() {
+  # Explicitly request building manylinux1 wheels, which is no longer the default.
+  # https://github.com/protocolbuffers/protobuf/issues/9180
+  MB_ML_VER=1
+  build_artifact_version $@
+}
+
+build_x86_64_manylinux2010_artifact_version() {
+  # Explicitly request building manylinux2010 wheels
+  MB_ML_VER=2010
+  build_artifact_version $@
+}
+
+build_crosscompiled_aarch64_manylinux2014_artifact_version() {
   # crosscompilation is only supported with the dockcross manylinux2014 image
   DOCKER_IMAGE=dockcross/manylinux2014-aarch64:20210706-65bf2dd
+  MB_ML_VER=2014
   PLAT=aarch64
 
   # TODO(jtatermusch): currently when crosscompiling, "auditwheel repair" will be disabled
@@ -57,11 +78,13 @@
   build_artifact_version $@
 }
 
-build_artifact_version 3.6
-build_artifact_version 3.7
-build_artifact_version 3.8
-build_artifact_version 3.9
+build_x86_64_manylinux1_artifact_version 3.6
+build_x86_64_manylinux1_artifact_version 3.7
+build_x86_64_manylinux1_artifact_version 3.8
+build_x86_64_manylinux1_artifact_version 3.9
+build_x86_64_manylinux2010_artifact_version 3.10
 
-build_crosscompiled_aarch64_artifact_version 3.7
-build_crosscompiled_aarch64_artifact_version 3.8
-build_crosscompiled_aarch64_artifact_version 3.9
+build_crosscompiled_aarch64_manylinux2014_artifact_version 3.7
+build_crosscompiled_aarch64_manylinux2014_artifact_version 3.8
+build_crosscompiled_aarch64_manylinux2014_artifact_version 3.9
+build_crosscompiled_aarch64_manylinux2014_artifact_version 3.10
diff --git a/kokoro/release/python/macos/build_artifacts.sh b/kokoro/release/python/macos/build_artifacts.sh
index fbbd650..aeb4242 100755
--- a/kokoro/release/python/macos/build_artifacts.sh
+++ b/kokoro/release/python/macos/build_artifacts.sh
@@ -26,6 +26,13 @@
 export ARTIFACT_DIR=$(pwd)/artifacts
 
 git clone https://github.com/matthew-brett/multibuild.git
+# Pin multibuild scripts at a known commit to avoid potentially unwanted future changes from
+# silently creeping in (see https://github.com/protocolbuffers/protobuf/issues/9180).
+# IMPORTANT: always pin multibuild at the same commit for:
+# - linux/build_artifacts.sh
+# - linux/build_artifacts.sh
+# - windows/build_artifacts.bat
+(cd multibuild; git checkout b89bb903e94308be79abefa4f436bf123ebb1313)
 cp kokoro/release/python/macos/config.sh config.sh
 
 OLD_PATH=$PATH
@@ -55,3 +62,4 @@
 build_artifact_version 3.7
 build_artifact_version 3.8
 build_artifact_version 3.9
+build_artifact_version 3.10
diff --git a/kokoro/release/python/windows/build_artifacts.bat b/kokoro/release/python/windows/build_artifacts.bat
index 5c5df7c..a8f8f78 100644
--- a/kokoro/release/python/windows/build_artifacts.bat
+++ b/kokoro/release/python/windows/build_artifacts.bat
@@ -9,12 +9,20 @@
 set REPO_DIR=protobuf
 set BUILD_DLL=OFF
 set UNICODE=ON
-set PB_TEST_DEP="six==1.9"
 set OTHER_TEST_DEP="setuptools==38.5.1"
 set OLD_PATH=C:\Program Files (x86)\MSBuild\14.0\bin\;%PATH%
 
 REM Fetch multibuild
 git clone https://github.com/matthew-brett/multibuild.git
+REM Pin multibuild scripts at a known commit to avoid potentially unwanted future changes from
+REM silently creeping in (see https://github.com/protocolbuffers/protobuf/issues/9180).
+REM IMPORTANT: always pin multibuild at the same commit for:
+REM - linux/build_artifacts.sh
+REM - linux/build_artifacts.sh
+REM - windows/build_artifacts.bat
+cd multibuild
+git checkout b89bb903e94308be79abefa4f436bf123ebb1313
+cd ..
 
 REM Install zlib
 mkdir zlib
@@ -74,6 +82,16 @@
 SET PYTHON_ARCH=64
 CALL build_single_artifact.bat || goto :error
 
+SET PYTHON=C:\python310_32bit
+SET PYTHON_VERSION=3.10
+SET PYTHON_ARCH=32
+CALL build_single_artifact.bat || goto :error
+
+SET PYTHON=C:\python310
+SET PYTHON_VERSION=3.10
+SET PYTHON_ARCH=64
+CALL build_single_artifact.bat || goto :error
+
 goto :EOF
 
 :error
diff --git a/kokoro/release/python/windows/build_single_artifact.bat b/kokoro/release/python/windows/build_single_artifact.bat
index 920f9c8..8d3cd0c 100644
--- a/kokoro/release/python/windows/build_single_artifact.bat
+++ b/kokoro/release/python/windows/build_single_artifact.bat
@@ -24,6 +24,12 @@
 if %PYTHON%==C:\python39 set generator=Visual Studio 14 Win64
 if %PYTHON%==C:\python39 set vcplatform=x64
 
+if %PYTHON%==C:\python310_32bit set generator=Visual Studio 14
+if %PYTHON%==C:\python310_32bit set vcplatform=Win32
+
+if %PYTHON%==C:\python310 set generator=Visual Studio 14 Win64
+if %PYTHON%==C:\python310 set vcplatform=x64
+
 REM Prepend newly installed Python to the PATH of this build (this cannot be
 REM done from inside the powershell script as it would require to restart
 REM the parent CMD process).
diff --git a/kokoro/release/python/windows/install_python_interpreters.ps1 b/kokoro/release/python/windows/install_python_interpreters.ps1
index b63259a..3f8db95 100644
--- a/kokoro/release/python/windows/install_python_interpreters.ps1
+++ b/kokoro/release/python/windows/install_python_interpreters.ps1
@@ -95,3 +95,20 @@
     PythonInstallerHash = "b61a33dc28f13b561452f3089c87eb63"
 }
 Install-Python @Python39x64Config
+
+# Python 3.10
+$Python310x86Config = @{
+    PythonVersion = "3.10.0"
+    PythonInstaller = "python-3.10.0"
+    PythonInstallPath = "C:\python310_32bit"
+    PythonInstallerHash = "133aa48145032e341ad2a000cd3bff50"
+}
+Install-Python @Python310x86Config
+
+$Python310x64Config = @{
+    PythonVersion = "3.10.0"
+    PythonInstaller = "python-3.10.0-amd64"
+    PythonInstallPath = "C:\python310"
+    PythonInstallerHash = "c3917c08a7fe85db7203da6dcaa99a70"
+}
+Install-Python @Python310x64Config
diff --git a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
index 046b604..98270d1 100755
--- a/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
+++ b/kokoro/release/ruby/macos/ruby/ruby_build_environment.sh
@@ -60,19 +60,18 @@
 ruby --version | grep 'ruby 2.7.0'
 for v in 3.0.0 2.7.0 ; do
   ccache -c
-  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
+  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin MAKE="$MAKE"
+  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=aarch64-darwin MAKE="$MAKE"
 done
 set +x
 rvm use 2.5.0
 set -x
 ruby --version | grep 'ruby 2.5.0'
-for v in 2.6.0 2.5.1 2.4.0 2.3.0; do
+for v in 2.6.0 2.5.1; do
   ccache -c
-  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin11 MAKE="$MAKE"
+  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=x86_64-darwin MAKE="$MAKE"
+  rake -f "$CROSS_RUBY" cross-ruby VERSION="$v" HOST=aarch64-darwin MAKE="$MAKE"
 done
 set +x
 rvm use 2.7.0
 set -x
-
-sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > "$CROSS_RUBY"
-mv "$CROSS_RUBY" ~/.rake-compiler/config.yml
diff --git a/maven_install.json b/maven_install.json
index f934218..bce3e2b 100644
--- a/maven_install.json
+++ b/maven_install.json
@@ -1,9 +1,11 @@
 {
     "dependency_tree": {
-        "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 1033791982,
+        "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
+        "__INPUT_ARTIFACTS_HASH": 1634601905,
+        "__RESOLVED_ARTIFACTS_HASH": -143733866,
         "conflict_resolution": {
             "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1",
-            "junit:junit:4.12": "junit:junit:4.13.1"
+            "junit:junit:4.12": "junit:junit:4.13.2"
         },
         "dependencies": [
             {
@@ -43,16 +45,16 @@
                 "url": "https://repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar"
             },
             {
-                "coord": "com.google.code.gson:gson:2.8.6",
+                "coord": "com.google.code.gson:gson:2.8.9",
                 "dependencies": [],
                 "directDependencies": [],
-                "file": "v1/https/repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar",
+                "file": "v1/https/repo1.maven.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar",
                 "mirror_urls": [
-                    "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar",
-                    "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar"
+                    "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar",
+                    "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar"
                 ],
-                "sha256": "c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f",
-                "url": "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar"
+                "sha256": "d3999291855de495c94c743761b8ab5176cfeabe281a5ab0d8e8d45326fd703e",
+                "url": "https://repo1.maven.org/maven2/com/google/code/gson/gson/2.8.9/gson-2.8.9.jar"
             },
             {
                 "coord": "com.google.errorprone:error_prone_annotations:2.5.1",
@@ -79,6 +81,35 @@
                 "url": "https://repo1.maven.org/maven2/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar"
             },
             {
+                "coord": "com.google.guava:guava-testlib:30.1.1-jre",
+                "dependencies": [
+                    "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
+                    "com.google.j2objc:j2objc-annotations:1.3",
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "org.hamcrest:hamcrest-core:1.3",
+                    "com.google.guava:guava:30.1.1-jre",
+                    "com.google.guava:failureaccess:1.0.1",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
+                    "org.checkerframework:checker-qual:3.9.1"
+                ],
+                "directDependencies": [
+                    "com.google.j2objc:j2objc-annotations:1.3",
+                    "com.google.code.findbugs:jsr305:3.0.2",
+                    "com.google.guava:guava:30.1.1-jre",
+                    "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
+                    "org.checkerframework:checker-qual:3.9.1"
+                ],
+                "file": "v1/https/repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar",
+                "mirror_urls": [
+                    "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar",
+                    "https://repo.maven.apache.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar"
+                ],
+                "sha256": "8a7fc9adfa1e7441d1d30ca288c593ebc7c4a24c601d01169b781c398f24099b",
+                "url": "https://repo1.maven.org/maven2/com/google/guava/guava-testlib/30.1.1-jre/guava-testlib-30.1.1-jre.jar"
+            },
+            {
                 "coord": "com.google.guava:guava:30.1.1-jre",
                 "dependencies": [
                     "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava",
@@ -132,19 +163,18 @@
                 "coord": "com.google.truth:truth:1.1.2",
                 "dependencies": [
                     "org.ow2.asm:asm:9.0",
-                    "org.hamcrest:hamcrest-core:1.3",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "junit:junit:4.13.1",
                     "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "directDependencies": [
                     "org.ow2.asm:asm:9.0",
                     "com.google.auto.value:auto-value-annotations:1.7.4",
-                    "junit:junit:4.13.1",
                     "com.google.guava:guava:30.1.1-jre",
                     "com.google.errorprone:error_prone_annotations:2.5.1",
+                    "junit:junit:4.13.2",
                     "org.checkerframework:checker-qual:3.9.1"
                 ],
                 "file": "v1/https/repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar",
@@ -156,20 +186,20 @@
                 "url": "https://repo1.maven.org/maven2/com/google/truth/truth/1.1.2/truth-1.1.2.jar"
             },
             {
-                "coord": "junit:junit:4.13.1",
+                "coord": "junit:junit:4.13.2",
                 "dependencies": [
                     "org.hamcrest:hamcrest-core:1.3"
                 ],
                 "directDependencies": [
                     "org.hamcrest:hamcrest-core:1.3"
                 ],
-                "file": "v1/https/repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar",
+                "file": "v1/https/repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar",
                 "mirror_urls": [
-                    "https://repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar",
-                    "https://repo.maven.apache.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar"
+                    "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar",
+                    "https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
                 ],
-                "sha256": "c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122",
-                "url": "https://repo1.maven.org/maven2/junit/junit/4.13.1/junit-4.13.1.jar"
+                "sha256": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3",
+                "url": "https://repo1.maven.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar"
             },
             {
                 "coord": "org.checkerframework:checker-qual:3.9.1",
@@ -202,24 +232,6 @@
                 "url": "https://repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar"
             },
             {
-                "coord": "org.easymock:easymockclassextension:3.2",
-                "dependencies": [
-                    "org.easymock:easymock:3.2",
-                    "cglib:cglib-nodep:2.2.2",
-                    "org.objenesis:objenesis:1.3"
-                ],
-                "directDependencies": [
-                    "org.easymock:easymock:3.2"
-                ],
-                "file": "v1/https/repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar",
-                "mirror_urls": [
-                    "https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar",
-                    "https://repo.maven.apache.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar"
-                ],
-                "sha256": "e2aeb3ecec87d859b2f3072985d4b15873558bcf6410f422db0c0c5194c76c87",
-                "url": "https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar"
-            },
-            {
                 "coord": "org.hamcrest:hamcrest-core:1.3",
                 "dependencies": [],
                 "directDependencies": [],
diff --git a/php/ext/google/protobuf/names.c b/php/ext/google/protobuf/names.c
index 6108ff4..a991888 100644
--- a/php/ext/google/protobuf/names.c
+++ b/php/ext/google/protobuf/names.c
@@ -71,22 +71,22 @@
 /* def name -> classname ******************************************************/
 
 const char *const kReservedNames[] = {
-    "abstract",     "and",        "array",      "as",           "break",
-    "callable",     "case",       "catch",      "class",        "clone",
-    "const",        "continue",   "declare",    "default",      "die",
-    "do",           "echo",       "else",       "elseif",       "empty",
-    "enddeclare",   "endfor",     "endforeach", "endif",        "endswitch",
-    "endwhile",     "eval",       "exit",       "extends",      "final",
-    "finally",      "fn",         "for",        "foreach",      "function",
-    "if",           "implements", "include",    "include_once", "instanceof",
-    "global",       "goto",       "insteadof",  "interface",    "isset",
-    "list",         "match",      "namespace",  "new",          "or",
-    "print",        "private",    "protected",  "public",       "require",
-    "require_once", "return",     "static",     "switch",       "throw",
-    "trait",        "try",        "unset",      "use",          "var",
-    "while",        "xor",        "yield",      "int",          "float",
-    "bool",         "string",     "true",       "false",        "null",
-    "void",         "iterable",   NULL};
+    "abstract",   "and",          "array",      "as",           "break",
+    "callable",   "case",         "catch",      "class",        "clone",
+    "const",      "continue",     "declare",    "default",      "die",
+    "do",         "echo",         "else",       "elseif",       "empty",
+    "enddeclare", "endfor",       "endforeach", "endif",        "endswitch",
+    "endwhile",   "eval",         "exit",       "extends",      "final",
+    "finally",    "fn",           "for",        "foreach",      "function",
+    "if",         "implements",   "include",    "include_once", "instanceof",
+    "global",     "goto",         "insteadof",  "interface",    "isset",
+    "list",       "match",        "namespace",  "new",          "object",
+    "or",         "print",        "private",    "protected",    "public",
+    "require",    "require_once", "return",     "static",       "switch",
+    "throw",      "trait",        "try",        "unset",        "use",
+    "var",        "while",        "xor",        "yield",        "int",
+    "float",      "bool",         "string",     "true",         "false",
+    "null",       "void",         "iterable",   NULL};
 
 bool is_reserved_name(const char* name) {
   int i;
diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml
index f083785..5bdb928 100644
--- a/php/ext/google/protobuf/package.xml
+++ b/php/ext/google/protobuf/package.xml
@@ -10,19 +10,19 @@
   <email>protobuf-opensource@google.com</email>
   <active>yes</active>
  </lead>
- <date>2021-10-04</date>
- <time>13:03:51</time>
+ <date>2022-01-28</date>
+ <time>00:03:40</time>
  <version>
-  <release>3.18.1</release>
-  <api>3.18.1</api>
+  <release>3.19.4</release>
+  <api>3.19.4</api>
  </version>
  <stability>
   <release>stable</release>
   <api>stable</api>
  </stability>
- <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+ <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
  <notes>
- * No new changes in 3.18.1
+ * See github.com/protocolbuffers/protobuf/releases for release notes.
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -73,7 +73,7 @@
    </stability>
    <date>2016-09-23</date>
    <time>16:06:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 First alpha release
    </notes>
@@ -89,7 +89,7 @@
    </stability>
    <date>2017-01-13</date>
    <time>16:06:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 Second alpha release.
    </notes>
@@ -105,7 +105,7 @@
    </stability>
    <date>2017-04-28</date>
    <time>16:06:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -121,7 +121,7 @@
    </stability>
    <date>2017-05-08</date>
    <time>15:33:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -137,7 +137,7 @@
    </stability>
    <date>2017-06-21</date>
    <time>15:33:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -153,7 +153,7 @@
    </stability>
    <date>2017-08-16</date>
    <time>15:33:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -169,7 +169,7 @@
    </stability>
    <date>2017-09-14</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -185,7 +185,7 @@
    </stability>
    <date>2017-11-15</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -201,7 +201,7 @@
    </stability>
    <date>2017-12-06</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -217,7 +217,7 @@
    </stability>
    <date>2017-12-11</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 GA release.
    </notes>
@@ -233,7 +233,7 @@
    </stability>
    <date>2018-03-06</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 G  A release.
    </notes>
@@ -249,7 +249,7 @@
    </stability>
    <date>2018-06-06</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 G  A release.
    </notes>
@@ -265,7 +265,7 @@
    </stability>
    <date>2018-08-03</date>
    <time>11:02:07</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
 G  A release.
    </notes>
@@ -281,7 +281,7 @@
    </stability>
    <date>2019-02-1</date>
    <time>10:22:43</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -295,7 +295,7 @@
    </stability>
    <date>2019-02-22</date>
    <time>11:31:21</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -309,7 +309,7 @@
    </stability>
    <date>2019-02-28</date>
    <time>10:19:15</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -323,7 +323,7 @@
    </stability>
    <date>2019-03-25</date>
    <time>13:23:39</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -337,7 +337,7 @@
    </stability>
    <date>2019-04-23</date>
    <time>16:14:52</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -351,7 +351,7 @@
    </stability>
    <date>2019-05-21</date>
    <time>14:07:13</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -365,7 +365,7 @@
    </stability>
    <date>2019-06-17</date>
    <time>09:34:50</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -379,7 +379,7 @@
    </stability>
    <date>2019-07-10</date>
    <time>16:50:08</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -393,7 +393,7 @@
    </stability>
    <date>2019-08-02</date>
    <time>15:59:08</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -407,7 +407,7 @@
    </stability>
    <date>2019-09-04</date>
    <time>13:24:25</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -421,7 +421,7 @@
    </stability>
    <date>2019-09-05</date>
    <time>10:12:46</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -435,7 +435,7 @@
    </stability>
    <date>2019-09-12</date>
    <time>13:48:02</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -449,7 +449,7 @@
    </stability>
    <date>2019-11-15</date>
    <time>11:44:18</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -463,7 +463,7 @@
    </stability>
    <date>2019-11-21</date>
    <time>10:38:49</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -477,7 +477,7 @@
    </stability>
    <date>2019-11-25</date>
    <time>11:47:41</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -491,7 +491,7 @@
    </stability>
    <date>2019-12-02</date>
    <time>11:09:17</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -505,7 +505,7 @@
    </stability>
    <date>2019-12-10</date>
    <time>11:22:54</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -519,7 +519,7 @@
    </stability>
    <date>2020-01-28</date>
    <time>10:20:43</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -533,7 +533,7 @@
    </stability>
    <date>2020-02-12</date>
    <time>12:46:57</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -547,7 +547,7 @@
    </stability>
    <date>2020-04-30</date>
    <time>14:23:34</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -561,7 +561,7 @@
    </stability>
    <date>2020-05-12</date>
    <time>12:48:03</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -575,7 +575,7 @@
    </stability>
    <date>2020-05-15</date>
    <time>13:26:23</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -589,7 +589,7 @@
    </stability>
    <date>2020-05-20</date>
    <time>10:18:13</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -603,7 +603,7 @@
    </stability>
    <date>2020-05-26</date>
    <time>13:57:10</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -617,7 +617,7 @@
    </stability>
    <date>2020-06-01</date>
    <time>01:09:39</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -631,7 +631,7 @@
    </stability>
    <date>2020-08-05</date>
    <time>11:21:41</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -645,7 +645,7 @@
    </stability>
    <date>2020-08-05</date>
    <time>11:22:52</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -659,7 +659,7 @@
    </stability>
    <date>2020-08-12</date>
    <time>13:46:54</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -673,7 +673,7 @@
    </stability>
    <date>2020-08-14</date>
    <time>14:07:59</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -687,7 +687,7 @@
    </stability>
    <date>2020-10-08</date>
    <time>14:07:59</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>GA release.</notes>
   </release>
   <release>
@@ -701,7 +701,7 @@
    </stability>
    <date>2020-11-05</date>
    <time>13:39:47</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -716,7 +716,7 @@
    </stability>
    <date>2020-11-10</date>
    <time>16:28:41</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -731,7 +731,7 @@
    </stability>
    <date>2020-11-11</date>
    <time>10:35:18</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -746,7 +746,7 @@
    </stability>
    <date>2020-11-12</date>
    <time>14:06:40</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -761,7 +761,7 @@
    </stability>
    <date>2021-02-05</date>
    <time>14:15:36</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -776,7 +776,7 @@
    </stability>
    <date>2021-02-17</date>
    <time>09:10:33</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -791,7 +791,7 @@
    </stability>
    <date>2021-02-18</date>
    <time>10:33:10</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -806,7 +806,7 @@
    </stability>
    <date>2021-02-19</date>
    <time>10:50:04</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -821,7 +821,7 @@
    </stability>
    <date>2021-02-23</date>
    <time>11:35:09</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -836,7 +836,7 @@
    </stability>
    <date>2021-02-24</date>
    <time>16:49:52</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -851,7 +851,7 @@
    </stability>
    <date>2021-03-02</date>
    <time>15:25:02</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -866,7 +866,7 @@
    </stability>
    <date>2021-03-04</date>
    <time>10:45:30</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -881,7 +881,7 @@
    </stability>
    <date>2021-03-10</date>
    <time>10:11:34</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -896,7 +896,7 @@
    </stability>
    <date>2021-04-02</date>
    <time>10:01:42</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -911,7 +911,7 @@
    </stability>
    <date>2021-04-02</date>
    <time>16:11:33</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -926,7 +926,7 @@
    </stability>
    <date>2021-05-03</date>
    <time>16:40:57</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -941,7 +941,7 @@
    </stability>
    <date>2021-05-05</date>
    <time>16:34:02</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -956,7 +956,7 @@
    </stability>
    <date>2021-05-06</date>
    <time>11:08:58</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -971,7 +971,7 @@
    </stability>
    <date>2021-05-07</date>
    <time>15:58:19</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -986,7 +986,7 @@
    </stability>
    <date>2021-05-11</date>
    <time>13:29:14</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1001,7 +1001,7 @@
    </stability>
    <date>2021-05-19</date>
    <time>16:06:12</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
  * Fixed PHP memory leaks and arginfo errors. (#8614)
  * Fixed JSON parser to allow multiple values from the same oneof as long as
@@ -1019,7 +1019,7 @@
    </stability>
    <date>2021-05-25</date>
    <time>19:32:12</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1034,7 +1034,7 @@
    </stability>
    <date>2021-06-04</date>
    <time>21:17:28</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1049,7 +1049,7 @@
    </stability>
    <date>2021-08-18</date>
    <time>15:23:47</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1064,7 +1064,7 @@
    </stability>
    <date>2021-08-27</date>
    <time>14:37:43</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1079,7 +1079,7 @@
    </stability>
    <date>2021-09-13</date>
    <time>11:30:58</time>
-   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
    <notes>
    </notes>
   </release>
@@ -1094,6 +1094,111 @@
    </stability>
    <date>2021-10-04</date>
    <time>13:03:51</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.0RC1</release>
+    <api>3.19.0</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>beta</api>
+   </stability>
+   <date>2021-10-15</date>
+   <time>13:38:38</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.0RC2</release>
+    <api>3.19.0</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>beta</api>
+   </stability>
+   <date>2021-10-18</date>
+   <time>15:36:35</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.0</release>
+    <api>3.19.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2021-10-19</date>
+   <time>11:06:24</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.1</release>
+    <api>3.19.1</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2021-10-28</date>
+   <time>20:01:12</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.2</release>
+    <api>3.19.2</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2022-01-05</date>
+   <time>17:01:38</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.3</release>
+    <api>3.19.3</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2022-01-11</date>
+   <time>00:58:50</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</license>
+   <notes>
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.19.4</release>
+    <api>3.19.4</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2022-01-28</date>
+   <time>00:03:40</time>
    <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
    <notes>
    </notes>
diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c
index a668fe0..925faa6 100644
--- a/php/ext/google/protobuf/php-upb.c
+++ b/php/ext/google/protobuf/php-upb.c
@@ -5968,7 +5968,7 @@
   }
 
   /* Account for space used by hasbits. */
-  l->size = div_round_up(hasbit, 8);
+  l->size = div_round_up(hasbit + 1, 8);
 
   /* Allocate non-oneof fields. */
   for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
index 8b5c8aa..41ae271 100644
--- a/php/ext/google/protobuf/protobuf.h
+++ b/php/ext/google/protobuf/protobuf.h
@@ -91,7 +91,7 @@
   ZEND_ARG_INFO(0, value)
 ZEND_END_ARG_INFO()
 
-#define PHP_PROTOBUF_VERSION "3.18.1"
+#define PHP_PROTOBUF_VERSION "3.19.4"
 
 // ptr -> PHP object cache. This is a weak map that caches lazily-created
 // wrapper objects around upb types:
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/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php
index 837f052..a6101dc 100644
--- a/php/tests/GeneratedClassTest.php
+++ b/php/tests/GeneratedClassTest.php
@@ -9,6 +9,7 @@
 use Bar\TestLegacyMessage;
 use Bar\TestLegacyMessage_NestedEnum;
 use Bar\TestLegacyMessage_NestedMessage;
+use Foo\Test32Fields;
 use Foo\TestEnum;
 use Foo\TestIncludeNamespaceMessage;
 use Foo\TestIncludePrefixMessage;
@@ -1849,4 +1850,13 @@
 
         $this->assertTrue(true);
     }
+
+    public function testIssue9440()
+    {
+        $m = new Test32Fields();
+        $m->setId(8);
+        $this->assertEquals(8, $m->getId());
+        $m->setVersion('1');
+        $this->assertEquals(8, $m->getId());
+    }
 }
diff --git a/php/tests/proto/test.proto b/php/tests/proto/test.proto
index 609b8cf..421292a 100644
--- a/php/tests/proto/test.proto
+++ b/php/tests/proto/test.proto
@@ -306,3 +306,38 @@
     int32 int32_field = 4;
   }
 }
+
+message Test32Fields {
+  optional uint32 id = 1;
+  optional uint32 random_name_a0 = 2;
+  optional uint32 random_name_a1 = 3;
+  optional uint32 random_name_a2 = 4;
+  optional uint32 random_name_a3 = 5;
+  optional uint32 random_name_a4 = 6;
+  optional uint32 random_name_a5 = 7;
+  optional uint32 random_name_a6 = 8;
+  optional uint32 random_name_a7 = 9;
+  optional uint32 random_name_a8 = 10;
+  optional uint32 random_name_a9 = 11;
+  optional uint32 random_name_b0 = 12;
+  optional uint32 random_name_b1 = 13;
+  optional uint32 random_name_b2 = 14;
+  optional uint32 random_name_b3 = 15;
+  optional uint32 random_name_b4 = 16;
+  optional uint32 random_name_b5 = 17;
+  optional uint32 random_name_b6 = 18;
+  optional uint32 random_name_b7 = 19;
+  optional uint32 random_name_b8 = 20;
+  optional uint32 random_name_b9 = 21;
+  optional uint32 random_name_c0 = 22;
+  optional uint32 random_name_c1 = 23;
+  optional uint32 random_name_c2 = 24;
+  optional uint32 random_name_c3 = 25;
+  optional uint32 random_name_c4 = 26;
+  optional uint32 random_name_c5 = 27;
+  optional uint32 random_name_c6 = 28;
+  optional uint32 random_name_c7 = 29;
+  optional uint32 random_name_c8 = 30;
+  optional uint32 random_name_c9 = 31;
+  optional string version = 32;
+}
diff --git a/protobuf-lite.pc.in b/protobuf-lite.pc.in
index 68a2bb4..f92e4ad 100644
--- a/protobuf-lite.pc.in
+++ b/protobuf-lite.pc.in
@@ -6,6 +6,6 @@
 Name: Protocol Buffers
 Description: Google's Data Interchange Format
 Version: @VERSION@
-Libs: -L${libdir} -lprotobuf-lite @PTHREAD_LIBS@
-Cflags: -I${includedir} @PTHREAD_CFLAGS@
+Libs: -L${libdir} -lprotobuf-lite
+Cflags: -I${includedir}
 Conflicts: protobuf
diff --git a/protobuf.bzl b/protobuf.bzl
index 9716128..826b610 100644
--- a/protobuf.bzl
+++ b/protobuf.bzl
@@ -80,7 +80,14 @@
     source_dir = _SourceDir(ctx)
     gen_dir = _GenDir(ctx).rstrip("/")
     if source_dir:
-        import_flags = depset(direct=["-I" + source_dir, "-I" + gen_dir])
+        has_sources = any([src.is_source for src in srcs])
+        has_generated = any([not src.is_source for src in srcs])
+        import_flags = []
+        if has_sources:
+            import_flags += ["-I" + source_dir]
+        if has_generated:
+            import_flags += ["-I" + gen_dir]
+        import_flags = depset(direct=import_flags)
     else:
         import_flags = depset(direct=["-I."])
 
@@ -259,9 +266,9 @@
         deps = [],
         cc_libs = [],
         include = None,
-        protoc = "@com_google_protobuf//:protoc",
+        protoc = Label("//:protoc"),
         use_grpc_plugin = False,
-        default_runtime = "@com_google_protobuf//:protobuf",
+        default_runtime = Label("//:protobuf"),
         **kargs):
     """Bazel rule to create a C++ protobuf library from proto source files
 
@@ -379,7 +386,7 @@
         "_protoc": attr.label(
             executable = True,
             cfg = "exec",
-            default = "@com_google_protobuf//:protoc",
+            default = "//:protoc",
         ),
     },
 )
@@ -422,8 +429,8 @@
         py_libs = [],
         py_extra_srcs = [],
         include = None,
-        default_runtime = "@com_google_protobuf//:protobuf_python",
-        protoc = "@com_google_protobuf//:protoc",
+        default_runtime = Label("//:protobuf_python"),
+        protoc = Label("//:protoc"),
         use_grpc_plugin = False,
         **kargs):
     """Bazel rule to create a Python protobuf library from proto source files
diff --git a/protobuf.pc.in b/protobuf.pc.in
index 055a9d0..e9bef5d 100644
--- a/protobuf.pc.in
+++ b/protobuf.pc.in
@@ -6,8 +6,8 @@
 Name: Protocol Buffers
 Description: Google's Data Interchange Format
 Version: @VERSION@
-Libs: -L${libdir} -lprotobuf @PTHREAD_LIBS@
+Libs: -L${libdir} -lprotobuf
 Libs.private: @LIBS@
 
-Cflags: -I${includedir} @PTHREAD_CFLAGS@
+Cflags: -I${includedir}
 Conflicts: protobuf-lite
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index ec9d8e9..7e2caa3 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -2,6 +2,18 @@
 
 load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 
+PROTOBUF_MAVEN_ARTIFACTS = [
+    "com.google.code.findbugs:jsr305:3.0.2",
+    "com.google.code.gson:gson:2.8.9",
+    "com.google.errorprone:error_prone_annotations:2.3.2",
+    "com.google.j2objc:j2objc-annotations:1.3",
+    "com.google.guava:guava:30.1.1-jre",
+    "com.google.guava:guava-testlib:30.1.1-jre",
+    "com.google.truth:truth:1.1.2",
+    "junit:junit:4.12",
+    "org.easymock:easymock:3.2",
+]
+
 def protobuf_deps():
     """Loads common dependencies needed to compile the protobuf library."""
 
@@ -18,20 +30,12 @@
     if not native.existing_rule("zlib"):
         http_archive(
             name = "zlib",
-            build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
+            build_file = Label("//:third_party/zlib.BUILD"),
             sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff",
             strip_prefix = "zlib-1.2.11",
             urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"],
         )
 
-    if not native.existing_rule("six"):
-        http_archive(
-            name = "six",
-            build_file = "@com_google_protobuf//:third_party/six.BUILD",
-            sha256 = "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73",
-            urls = ["https://pypi.python.org/packages/source/s/six/six-1.12.0.tar.gz"],
-        )
-
     if not native.existing_rule("rules_cc"):
         http_archive(
             name = "rules_cc",
@@ -59,15 +63,31 @@
     if not native.existing_rule("rules_python"):
         http_archive(
             name = "rules_python",
-            sha256 = "e5470e92a18aa51830db99a4d9c492cc613761d5bdb7131c04bd92b9834380f6",
-            strip_prefix = "rules_python-4b84ad270387a7c439ebdccfd530e2339601ef27",
-            urls = ["https://github.com/bazelbuild/rules_python/archive/4b84ad270387a7c439ebdccfd530e2339601ef27.tar.gz"],
+            sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0",
+            urls = ["https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz"],
         )
 
     if not native.existing_rule("rules_jvm_external"):
-       http_archive(
+        http_archive(
             name = "rules_jvm_external",
             sha256 = "f36441aa876c4f6427bfb2d1f2d723b48e9d930b62662bf723ddfb8fc80f0140",
             strip_prefix = "rules_jvm_external-4.1",
             urls = ["https://github.com/bazelbuild/rules_jvm_external/archive/4.1.zip"],
         )
+
+    if not native.existing_rule("rules_pkg"):
+        http_archive(
+            name = "rules_pkg",
+            urls = [
+                "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz",
+                "https://github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz",
+            ],
+            sha256 = "a89e203d3cf264e564fcb96b6e06dd70bc0557356eb48400ce4b5d97c2c3720d",
+        )
+
+    if not native.existing_rule("io_bazel_rules_kotlin"):
+        http_archive(
+            name = "io_bazel_rules_kotlin",
+            urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v1.5.0-beta-4/rules_kotlin_release.tgz"],
+            sha256 = "6cbd4e5768bdfae1598662e40272729ec9ece8b7bded8f0d2c81c8ff96dc139d",
+        )
diff --git a/protobuf_version.bzl b/protobuf_version.bzl
index 7f6d714..9ae1340 100644
--- a/protobuf_version.bzl
+++ b/protobuf_version.bzl
@@ -1 +1 @@
-PROTOBUF_VERSION = '3.18.1'
+PROTOBUF_VERSION = '3.19.4'
diff --git a/protoc-artifacts/build-zip.sh b/protoc-artifacts/build-zip.sh
index 7d1923e..1d97725 100755
--- a/protoc-artifacts/build-zip.sh
+++ b/protoc-artifacts/build-zip.sh
@@ -16,6 +16,7 @@
 included. Each invocation will create 8 zip packages:
   dist/<TARGET>-<VERSION_NUMBER>-win32.zip
   dist/<TARGET>-<VERSION_NUMBER>-win64.zip
+  dist/<TARGET>-<VERSION_NUMBER>-osx-aarch_64.zip
   dist/<TARGET>-<VERSION_NUMBER>-osx-x86_64.zip
   dist/<TARGET>-<VERSION_NUMBER>-linux-x86_32.zip
   dist/<TARGET>-<VERSION_NUMBER>-linux-x86_64.zip
@@ -33,6 +34,7 @@
 declare -a FILE_NAMES=( \
   win32.zip windows-x86_32.exe \
   win64.zip windows-x86_64.exe \
+  osx-aarch_64.zip osx-aarch_64.exe \
   osx-x86_64.zip osx-x86_64.exe \
   linux-x86_32.zip linux-x86_32.exe \
   linux-x86_64.zip linux-x86_64.exe \
diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml
index c3aa377..1d0d18e 100644
--- a/protoc-artifacts/pom.xml
+++ b/protoc-artifacts/pom.xml
@@ -8,7 +8,7 @@
   </parent>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protoc</artifactId>
-  <version>3.18.1</version>
+  <version>3.19.4</version>
   <packaging>pom</packaging>
   <name>Protobuf Compiler</name>
   <description>
@@ -19,7 +19,7 @@
   <url>https://developers.google.com/protocol-buffers/</url>
   <licenses>
     <license>
-      <name>3-Clause BSD License</name>
+      <name>BSD-3-Clause</name>
       <url>https://opensource.org/licenses/BSD-3-Clause</url>
       <distribution>repo</distribution>
     </license>
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 61c242f..9615a58 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 2229671..6b6ba65 100755
--- a/python/google/protobuf/internal/_parameterized.py
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -357,7 +357,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)
@@ -389,9 +389,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 6532a81..241942e 100644
--- a/python/google/protobuf/internal/api_implementation.cc
+++ b/python/google/protobuf/internal/api_implementation.cc
@@ -81,24 +81,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 88d7136..d026a74 100644
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -51,6 +51,28 @@
 name: 'TestEmptyMessage'
 """
 
+TEST_FILE_DESCRIPTOR_DEBUG = """syntax = "proto2";
+
+package protobuf_unittest;
+
+message NestedMessage {
+  enum ForeignEnum {
+    FOREIGN_FOO = 4;
+    FOREIGN_BAR = 5;
+    FOREIGN_BAZ = 6;
+  }
+  optional int32 bb = 1;
+}
+
+message ResponseMessage {
+}
+
+service Service {
+  rpc CallMethod(.protobuf_unittest.NestedMessage) returns (.protobuf_unittest.ResponseMessage);
+}
+
+"""
+
 
 warnings.simplefilter('error', DeprecationWarning)
 
@@ -121,6 +143,13 @@
   def testContainingServiceFixups(self):
     self.assertEqual(self.my_service, self.my_method.containing_service)
 
+  @unittest.skipIf(
+      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)
+
   def testGetOptions(self):
     self.assertEqual(self.my_enum.GetOptions(),
                      descriptor_pb2.EnumOptions())
@@ -523,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 af3713f..3545563 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.assertRaisesRegexp(
         json_format.ParseError,
-        'Failed to parse repeatedInt32Value field: '
-        'null is not allowed to be used as an element in a repeated field.',
-        json_format.Parse,
-        '{"repeatedInt32Value":[1, null]}',
-        parsed_message)
-    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.assertRaisesRegexp(
         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.assertRaisesRegexp(
         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.assertRaisesRegexp(
         json_format.ParseError,
@@ -1039,17 +1043,16 @@
     self.assertRaisesRegexp(
         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.assertRaisesRegexp(
-        json_format.ParseError,
-        'Failed to parse value field: '
+        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.assertRaisesRegexp(
@@ -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.assertRaisesRegexp(
-        json_format.ParseError,
-        'Message type "proto3.TestOneof"'
-        ' should not have multiple "oneof_value" oneof fields.',
+        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.assertRaisesRegexp(
         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.assertRaisesRegexp(
         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.assertRaisesRegexp(
-        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.assertRaisesRegexp(
-        TypeError,
-        'Can not find message descriptor by type_url: '
-        'type.googleapis.com/MessageNotExist.',
-        json_format.Parse, text, message)
+    self.assertRaisesRegex(
+        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 6ed1f20..e8d86a2 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 d2632f9..37aec7e 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -36,6 +36,8 @@
 import datetime
 import unittest
 
+import dateutil.tz
+
 from google.protobuf import any_pb2
 from google.protobuf import duration_pb2
 from google.protobuf import field_mask_pb2
@@ -48,9 +50,11 @@
 from google.protobuf.internal import well_known_types
 from google.protobuf import descriptor
 from google.protobuf import text_format
+from google3.pyglib import datelib
+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,43 +237,68 @@
     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):
+  # Two hours after the Unix Epoch, around the world.
+  @_parameterized.named_parameters(
+      ('London', [1970, 1, 1, 2], dateutil.tz.UTC),
+      ('Tokyo', [1970, 1, 1, 11], dateutil.tz.gettz('Japan')),
+      ('LA', [1969, 12, 31, 18], dateutil.tz.gettz('US/Pacific')),
+  )
+  def testTimezoneAwareDatetimeConversion(self, date_parts, tzinfo):
+    original_datetime = datelib.CreateDatetime(*date_parts, tzinfo=tzinfo)
 
-      def utcoffset(self, _):
-        return datetime.timedelta(hours=1)
+    message = timestamp_pb2.Timestamp()
+    message.FromDatetime(original_datetime)
+    self.assertEqual(7200, message.seconds)
+    self.assertEqual(0, message.nanos)
 
-      def dst(self, _):
-        return datetime.timedelta(0)
+    # ToDatetime() with no parameters produces a naive UTC datetime, i.e. it not
+    # only loses the original timezone information (e.g. US/Pacific) as it's
+    # "normalised" to UTC, but also drops the information that the datetime
+    # represents a UTC one.
+    naive_datetime = message.ToDatetime()
+    self.assertEqual(datetime.datetime(1970, 1, 1, 2), naive_datetime)
+    self.assertIsNone(naive_datetime.tzinfo)
+    self.assertNotEqual(original_datetime, naive_datetime)  # not even for UTC!
 
-      def tzname(self, _):
-        return 'UTC+1'
-
-    message1 = timestamp_pb2.Timestamp()
-    dt = datetime.datetime(1970, 1, 1, 1, tzinfo=TZ())
-    message1.FromDatetime(dt)
-    message2 = timestamp_pb2.Timestamp()
-    dt = datetime.datetime(1970, 1, 1, 0)
-    message2.FromDatetime(dt)
-    self.assertEqual(message1, message2)
+    # In contrast, ToDatetime(tzinfo=) produces an aware datetime in the given
+    # timezone.
+    aware_datetime = message.ToDatetime(tzinfo=tzinfo)
+    self.assertEqual(original_datetime, aware_datetime)
+    self.assertEqual(
+        datelib.CreateDatetime(1970, 1, 1, 2, tzinfo=dateutil.tz.UTC),
+        aware_datetime)
+    self.assertEqual(tzinfo, aware_datetime.tzinfo)
 
   def testTimedeltaConversion(self):
     message = duration_pb2.Duration()
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index b3e8593..bf2a17d 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -226,7 +226,7 @@
               else:
                 recorded_key = 'false'
             else:
-              recorded_key = key
+              recorded_key = str(key)
             js_map[recorded_key] = self._FieldToJsonObject(
                 v_field, value[key])
           js[name] = js_map
@@ -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 9708b84..cbf6887 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -49,12 +49,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 {
@@ -94,17 +95,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;
@@ -235,23 +236,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());
 
@@ -263,7 +264,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;
     }
   }
 
@@ -287,7 +288,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 =
@@ -323,7 +324,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;
@@ -344,9 +345,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
@@ -360,8 +361,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;
 
@@ -372,10 +373,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;
@@ -409,7 +410,7 @@
 }
 
 static PyGetSetDef Getters[] = {
-  {NULL}
+    {nullptr},
 };
 
 PyTypeObject PyBaseDescriptor_Type = {
@@ -419,29 +420,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
 };
 
@@ -450,7 +451,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;
 }
@@ -612,19 +613,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());
 }
@@ -635,94 +635,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);
@@ -850,7 +854,7 @@
     default:
       PyErr_Format(PyExc_NotImplementedError, "default value for %s",
                    _GetDescriptor(self)->full_name().c_str());
-      return NULL;
+      return nullptr;
   }
   return result;
 }
@@ -941,6 +945,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));
 }
@@ -956,89 +968,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);
@@ -1124,76 +1138,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);
@@ -1251,63 +1266,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 {
@@ -1339,7 +1355,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;
   }
@@ -1349,8 +1365,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;
@@ -1393,6 +1409,10 @@
   return CheckCalledFromGeneratedFile("has_options");
 }
 
+static PyObject* GetDebugString(PyFileDescriptor* self) {
+  return PyString_FromCppString(_GetDescriptor(self)->DebugString());
+}
+
 static PyObject* GetOptions(PyFileDescriptor *self) {
   return GetOrBuildOptions(_GetDescriptor(self));
 }
@@ -1417,31 +1437,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[] = {
-  { "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
@@ -1453,45 +1478,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(
@@ -1499,8 +1524,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 =
@@ -1517,7 +1542,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);
@@ -1565,6 +1590,7 @@
     Py_RETURN_FALSE;
   }
 }
+
 static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
                          void *closure) {
   return CheckCalledFromGeneratedFile("has_options");
@@ -1585,64 +1611,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 {
@@ -1681,14 +1708,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);
@@ -1704,69 +1731,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);
@@ -1808,6 +1835,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));
 }
@@ -1817,62 +1852,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.
@@ -1881,7 +1920,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 b084f5b..adb1690 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -57,12 +57,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 {
@@ -157,59 +158,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;
@@ -221,25 +219,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;
   }
 }
 
@@ -257,13 +252,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);
 }
@@ -285,7 +280,7 @@
 };
 
 static int Contains(PyContainer* self, PyObject* key) {
-  const void* item = NULL;
+  const void* item = nullptr;
   if (!_GetItemByKey(self, key, &item)) {
     return -1;
   }
@@ -344,11 +339,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);
@@ -388,15 +383,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;
       }
@@ -426,7 +421,7 @@
     result = DescriptorMapping_Equal(self, other);
   }
   if (result < 0) {
-    return NULL;
+    return nullptr;
   }
   if (result ^ (opid == Py_NE)) {
     Py_RETURN_TRUE;
@@ -436,28 +431,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;
   }
@@ -467,13 +462,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);
   }
@@ -483,13 +478,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);
   }
@@ -499,22 +494,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());
@@ -539,56 +534,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.
@@ -599,7 +593,7 @@
   }
   if (index < 0 || index >= Length(self)) {
     PyErr_SetString(PyExc_IndexError, "index out of range");
-    return NULL;
+    return nullptr;
   }
   return _NewObj_ByIndex(self, index);
 }
@@ -609,15 +603,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);
 }
@@ -632,7 +625,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;
@@ -668,7 +661,7 @@
   if (position < 0) {
     // Not found
     PyErr_SetNone(PyExc_ValueError);
-    return NULL;
+    return nullptr;
   } else {
     return PyLong_FromLong(position);
   }
@@ -701,7 +694,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) {
@@ -710,77 +703,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;
@@ -791,8 +783,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;
@@ -802,14 +794,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;
@@ -820,8 +812,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;
@@ -839,8 +831,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;
@@ -851,80 +843,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;
@@ -992,17 +983,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
@@ -1053,17 +1036,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
@@ -1105,17 +1088,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
@@ -1154,7 +1137,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);
@@ -1180,17 +1163,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
@@ -1228,17 +1202,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
@@ -1280,17 +1254,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
@@ -1351,17 +1317,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
@@ -1409,17 +1367,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
@@ -1467,17 +1416,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
@@ -1529,17 +1470,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
@@ -1577,17 +1510,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
@@ -1625,17 +1550,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
@@ -1673,17 +1590,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
@@ -1709,17 +1618,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
@@ -1745,17 +1645,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 d2d9f8e..d1bd7a3 100644
--- a/python/google/protobuf/pyext/descriptor_database.h
+++ b/python/google/protobuf/pyext/descriptor_database.h
@@ -42,17 +42,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.
@@ -60,14 +61,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 5ec6269..5b0ceeb 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -43,12 +43,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 {
@@ -98,13 +99,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;
 
@@ -112,9 +113,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);
@@ -130,8 +131,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;
@@ -142,7 +143,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;
@@ -151,10 +152,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;
@@ -168,7 +169,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;
@@ -177,13 +178,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);
   }
@@ -229,24 +230,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");
@@ -263,14 +264,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);
@@ -280,12 +281,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");
   }
 
@@ -301,12 +302,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");
   }
@@ -323,12 +324,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");
   }
 
@@ -344,12 +345,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");
   }
 
@@ -365,13 +366,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");
@@ -385,13 +386,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");
@@ -405,13 +406,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");
@@ -425,18 +426,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);
@@ -444,10 +445,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;
   }
 
 
@@ -456,8 +457,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;
@@ -465,13 +466,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.
   }
@@ -491,7 +492,7 @@
   const FileDescriptor* file_descriptor =
       PyFileDescriptor_AsDescriptor(descriptor);
   if (!file_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (file_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindFileByName(
@@ -499,7 +500,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;
 }
@@ -508,7 +509,7 @@
   const Descriptor* message_descriptor =
       PyMessageDescriptor_AsDescriptor(descriptor);
   if (!message_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (message_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindMessageTypeByName(
@@ -516,7 +517,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;
 }
@@ -525,7 +526,7 @@
   const EnumDescriptor* enum_descriptor =
       PyEnumDescriptor_AsDescriptor(descriptor);
   if (!enum_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (enum_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindEnumTypeByName(
@@ -533,7 +534,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;
 }
@@ -542,7 +543,7 @@
   const FieldDescriptor* extension_descriptor =
       PyFieldDescriptor_AsDescriptor(descriptor);
   if (!extension_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (extension_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindExtensionByName(
@@ -550,7 +551,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;
 }
@@ -559,7 +560,7 @@
   const ServiceDescriptor* service_descriptor =
       PyServiceDescriptor_AsDescriptor(descriptor);
   if (!service_descriptor) {
-    return NULL;
+    return nullptr;
   }
   if (service_descriptor !=
       reinterpret_cast<PyDescriptorPool*>(self)->pool->FindServiceByName(
@@ -567,7 +568,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;
 }
@@ -578,12 +579,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(
@@ -593,22 +594,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);
   }
@@ -618,11 +619,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;
   }
 
 
@@ -632,56 +633,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
@@ -693,44 +694,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)
@@ -743,7 +744,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;
   }
@@ -774,7 +775,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 cb48faa..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(),
@@ -1074,23 +1076,24 @@
     if (descriptor->is_map()) {
       ScopedPyObjectPtr map(GetFieldValue(self, descriptor));
       const FieldDescriptor* value_descriptor =
-          descriptor->message_type()->FindFieldByName("value");
+          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() &&
@@ -2582,12 +2586,12 @@
   ContainerBase* py_container = nullptr;
   if (field_descriptor->is_map()) {
     const Descriptor* entry_type = field_descriptor->message_type();
-    const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
+    const FieldDescriptor* value_type = entry_type->map_value();
     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 30dfab8..64f9fed 100644
--- a/python/google/protobuf/pyext/message_factory.cc
+++ b/python/google/protobuf/pyext/message_factory.cc
@@ -38,12 +38,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 {
@@ -54,8 +55,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();
@@ -72,25 +73,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;
     }
   }
 
@@ -161,8 +162,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(
@@ -170,24 +171,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);
     }
@@ -199,17 +200,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());
@@ -223,14 +224,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);
@@ -238,8 +240,8 @@
 }
 
 static PyGetSetDef Getters[] = {
-    {"pool", (getter)GetPool, NULL, "DescriptorPool"},
-    {NULL}
+    {"pool", (getter)GetPool, nullptr, "DescriptorPool"},
+    {nullptr},
 };
 
 }  // namespace message_factory
@@ -251,37 +253,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 971d2ba..1f953fc 100644
--- a/python/google/protobuf/pyext/message_module.cc
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -93,28 +93,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
@@ -126,7 +126,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 6f7fc29..e6ea7e3 100644
--- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h
+++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h
@@ -47,7 +47,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.
@@ -69,7 +69,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 7f4fb23..00ac67a 100644
--- a/python/google/protobuf/pyext/unknown_fields.cc
+++ b/python/google/protobuf/pyext/unknown_fields.cc
@@ -49,7 +49,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.");
@@ -64,7 +64,7 @@
        it != self->sub_unknown_fields.end(); it++) {
     Clear(*it);
   }
-  self->fields = NULL;
+  self->fields = nullptr;
   self->sub_unknown_fields.clear();
 }
 
@@ -74,11 +74,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) {
@@ -88,7 +88,7 @@
     PyErr_Format(PyExc_IndexError,
                  "index (%zd) out of range",
                  index);
-    return NULL;
+    return nullptr;
   }
 
   return unknown_fields::NewPyUnknownFieldRef(self, index);
@@ -97,8 +97,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;
@@ -116,8 +116,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);
@@ -142,53 +142,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 {
@@ -196,8 +196,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;
@@ -212,26 +212,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;
   }
   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());
 }
@@ -239,8 +239,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
@@ -268,19 +268,19 @@
 
 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_FromLong(field->varint());
+      data = PyLong_FromUnsignedLongLong(field->varint());
       break;
     case UnknownField::TYPE_FIXED32:
-      data = PyLong_FromLong(field->fixed32());
+      data = PyLong_FromUnsignedLong(field->fixed32());
       break;
     case UnknownField::TYPE_FIXED64:
-      data = PyLong_FromLong(field->fixed64());
+      data = PyLong_FromUnsignedLongLong(field->fixed64());
       break;
     case UnknownField::TYPE_LENGTH_DELIMITED:
       data = PyBytes_FromStringAndSize(field->length_delimited().data(),
@@ -301,54 +301,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/python/protobuf_distutils/protobuf_distutils/generate_py_protobufs.py b/python/protobuf_distutils/protobuf_distutils/generate_py_protobufs.py
index 515ded2..88b8d45 100644
--- a/python/protobuf_distutils/protobuf_distutils/generate_py_protobufs.py
+++ b/python/protobuf_distutils/protobuf_distutils/generate_py_protobufs.py
@@ -120,7 +120,7 @@
         if self.proto_files is None:
             files = glob.glob(os.path.join(self.source_dir, '*.proto'))
             if self.recurse:
-                files.extend(glob.glob(os.path.join(self.source_dir, '**', '*.proto')))
+                files.extend(glob.glob(os.path.join(self.source_dir, '**', '*.proto'), recursive=True))
             self.proto_files = [f.partition(self.proto_root_path + os.path.sep)[-1] for f in files]
             if not self.proto_files:
                 raise DistutilsOptionError('no .proto files were found under ' + self.source_dir)
diff --git a/python/protobuf_distutils/setup.py b/python/protobuf_distutils/setup.py
index 1092930..9a19032 100644
--- a/python/protobuf_distutils/setup.py
+++ b/python/protobuf_distutils/setup.py
@@ -46,7 +46,7 @@
     packages=find_packages(),
     maintainer='protobuf@googlegroups.com',
     maintainer_email='protobuf@googlegroups.com',
-    license='3-Clause BSD License',
+    license='BSD-3-Clause',
     classifiers=[
         "Framework :: Setuptools Plugin",
         "Operating System :: OS Independent",
diff --git a/python/tox.ini b/python/tox.ini
index 88dd842..7142b86 100644
--- a/python/tox.ini
+++ b/python/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 envlist =
-    py{35,36,37,38,39}-{cpp,python}
+    py{35,36,37,38,39,310}-{cpp,python}
 
 [testenv]
 usedevelop=true
@@ -14,7 +14,7 @@
 commands =
     python setup.py -q build_py
     python: python setup.py -q build
-    py{35,36,37,38,39}-cpp: python setup.py -q build --cpp_implementation --warnings_as_errors --compile_static_extension
+    py{35,36,37,38,39,310}-cpp: python setup.py -q build --cpp_implementation --warnings_as_errors --compile_static_extension
     python: python setup.py -q test -q
     cpp: python setup.py -q test -q --cpp_implementation
     python: python setup.py -q test_conformance
diff --git a/ruby/Gemfile b/ruby/Gemfile
index 76b23ad..fa75df1 100644
--- a/ruby/Gemfile
+++ b/ruby/Gemfile
@@ -1,5 +1,3 @@
 source 'https://rubygems.org'
 
 gemspec
-
-gem "irb", "~> 1.1", "< 1.2.0" if RUBY_VERSION < "2.5"
diff --git a/ruby/Rakefile b/ruby/Rakefile
index 8aae2ee..762dc2c 100644
--- a/ruby/Rakefile
+++ b/ruby/Rakefile
@@ -80,6 +80,14 @@
   end
 
 else
+  unless ENV['IN_DOCKER'] == 'true'
+    # We need utf8_range in-tree.
+    FileUtils.mkdir_p("ext/google/protobuf_c/third_party/utf8_range")
+    FileUtils.cp("../third_party/utf8_range/utf8_range.h", "ext/google/protobuf_c/third_party/utf8_range")
+    FileUtils.cp("../third_party/utf8_range/utf8_range.c", "ext/google/protobuf_c/third_party/utf8_range")
+    FileUtils.cp("../third_party/utf8_range/LICENSE", "ext/google/protobuf_c/third_party/utf8_range")
+  end
+
   Rake::ExtensionTask.new("protobuf_c", spec) do |ext|
     unless RUBY_PLATFORM =~ /darwin/
       # TODO: also set "no_native to true" for mac if possible. As is,
@@ -93,7 +101,7 @@
     ext.cross_platform = [
       'x86-mingw32', 'x64-mingw32',
       'x86_64-linux', 'x86-linux',
-      'universal-darwin'
+      'x86_64-darwin', 'arm64-darwin',
     ]
   end
 
@@ -117,7 +125,7 @@
     ['x86-mingw32', 'x64-mingw32', 'x86_64-linux', 'x86-linux'].each do |plat|
       RakeCompilerDock.sh <<-"EOT", platform: plat
         bundle && \
-        IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.0:2.4.0:2.3.0
+        IN_DOCKER=true rake native:#{plat} pkg/#{spec.full_name}-#{plat}.gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.0
       EOT
     end
   end
@@ -125,7 +133,7 @@
   if RUBY_PLATFORM =~ /darwin/
     task 'gem:native' do
       system "rake genproto"
-      system "rake cross native gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.1:2.4.0:2.3.0"
+      system "rake cross native gem RUBY_CC_VERSION=3.0.0:2.7.0:2.6.0:2.5.1"
     end
   else
     task 'gem:native' => [:genproto, 'gem:windows', 'gem:java']
diff --git a/ruby/ext/google/protobuf_c/convert.c b/ruby/ext/google/protobuf_c/convert.c
index 8bcf6ee..8b98aee 100644
--- a/ruby/ext/google/protobuf_c/convert.c
+++ b/ruby/ext/google/protobuf_c/convert.c
@@ -31,7 +31,7 @@
 // -----------------------------------------------------------------------------
 // Ruby <-> upb data conversion functions.
 //
-// This file Also contains a few other assorted algorithms on upb_msgval.
+// This file Also contains a few other assorted algorithms on upb_MessageValue.
 //
 // None of the algorithms in this file require any access to the internal
 // representation of Ruby or upb objects.
@@ -42,10 +42,10 @@
 #include "message.h"
 #include "protobuf.h"
 
-static upb_strview Convert_StringData(VALUE str, upb_arena *arena) {
-  upb_strview ret;
+static upb_StringView Convert_StringData(VALUE str, upb_Arena* arena) {
+  upb_StringView ret;
   if (arena) {
-    char *ptr = upb_arena_malloc(arena, RSTRING_LEN(str));
+    char* ptr = upb_Arena_Malloc(arena, RSTRING_LEN(str));
     memcpy(ptr, RSTRING_PTR(str), RSTRING_LEN(str));
     ret.data = ptr;
   } else {
@@ -57,13 +57,11 @@
 }
 
 static bool is_ruby_num(VALUE value) {
-  return (TYPE(value) == T_FLOAT ||
-          TYPE(value) == T_FIXNUM ||
+  return (TYPE(value) == T_FLOAT || TYPE(value) == T_FIXNUM ||
           TYPE(value) == T_BIGNUM);
 }
 
-static void Convert_CheckInt(const char* name, upb_fieldtype_t type,
-                             VALUE val) {
+static void Convert_CheckInt(const char* name, upb_CType type, VALUE val) {
   if (!is_ruby_num(val)) {
     rb_raise(cTypeError,
              "Expected number type for integral field '%s' (given %s).", name,
@@ -82,7 +80,7 @@
                name, rb_class2name(CLASS_OF(val)));
     }
   }
-  if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) {
+  if (type == kUpb_CType_UInt32 || type == kUpb_CType_UInt64) {
     if (NUM2DBL(val) < 0) {
       rb_raise(
           rb_eRangeError,
@@ -93,26 +91,31 @@
 }
 
 static int32_t Convert_ToEnum(VALUE value, const char* name,
-                              const upb_enumdef* e) {
+                              const upb_EnumDef* e) {
   int32_t val;
 
   switch (TYPE(value)) {
     case T_FLOAT:
     case T_FIXNUM:
     case T_BIGNUM:
-      Convert_CheckInt(name, UPB_TYPE_INT32, value);
+      Convert_CheckInt(name, kUpb_CType_Int32, value);
       val = NUM2INT(value);
       break;
-    case T_STRING:
-      if (!upb_enumdef_ntoi(e, RSTRING_PTR(value), RSTRING_LEN(value), &val)) {
-        goto unknownval;
-      }
+    case T_STRING: {
+      const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNameWithSize(
+          e, RSTRING_PTR(value), RSTRING_LEN(value));
+      if (!ev) goto unknownval;
+      val = upb_EnumValueDef_Number(ev);
       break;
-    case T_SYMBOL:
-      if (!upb_enumdef_ntoiz(e, rb_id2name(SYM2ID(value)), &val)) {
+    }
+    case T_SYMBOL: {
+      const upb_EnumValueDef* ev =
+          upb_EnumDef_FindValueByName(e, rb_id2name(SYM2ID(value)));
+      if (!ev)
         goto unknownval;
-      }
+      val = upb_EnumValueDef_Number(ev);
       break;
+    }
     default:
       rb_raise(cTypeError,
                "Expected number or symbol type for enum field '%s'.", name);
@@ -124,47 +127,52 @@
   rb_raise(rb_eRangeError, "Unknown symbol value for enum field '%s'.", name);
 }
 
-upb_msgval Convert_RubyToUpb(VALUE value, const char* name, TypeInfo type_info,
-                             upb_arena* arena) {
-  upb_msgval ret;
+upb_MessageValue Convert_RubyToUpb(VALUE value, const char* name,
+                                   TypeInfo type_info, upb_Arena* arena) {
+  upb_MessageValue ret;
 
   switch (type_info.type) {
-    case UPB_TYPE_FLOAT:
+    case kUpb_CType_Float:
       if (!is_ruby_num(value)) {
-        rb_raise(cTypeError, "Expected number type for float field '%s' (given %s).",
-                 name, rb_class2name(CLASS_OF(value)));
+        rb_raise(cTypeError,
+                 "Expected number type for float field '%s' (given %s).", name,
+                 rb_class2name(CLASS_OF(value)));
       }
       ret.float_val = NUM2DBL(value);
       break;
-    case UPB_TYPE_DOUBLE:
+    case kUpb_CType_Double:
       if (!is_ruby_num(value)) {
-        rb_raise(cTypeError, "Expected number type for double field '%s' (given %s).",
-                 name, rb_class2name(CLASS_OF(value)));
+        rb_raise(cTypeError,
+                 "Expected number type for double field '%s' (given %s).", name,
+                 rb_class2name(CLASS_OF(value)));
       }
       ret.double_val = NUM2DBL(value);
       break;
-    case UPB_TYPE_BOOL: {
+    case kUpb_CType_Bool: {
       if (value == Qtrue) {
         ret.bool_val = 1;
       } else if (value == Qfalse) {
         ret.bool_val = 0;
       } else {
-        rb_raise(cTypeError, "Invalid argument for boolean field '%s' (given %s).",
-                 name, rb_class2name(CLASS_OF(value)));
+        rb_raise(cTypeError,
+                 "Invalid argument for boolean field '%s' (given %s).", name,
+                 rb_class2name(CLASS_OF(value)));
       }
       break;
     }
-    case UPB_TYPE_STRING: {
+    case kUpb_CType_String: {
       VALUE utf8 = rb_enc_from_encoding(rb_utf8_encoding());
       if (CLASS_OF(value) == rb_cSymbol) {
         value = rb_funcall(value, rb_intern("to_s"), 0);
       } else if (CLASS_OF(value) != rb_cString) {
-        rb_raise(cTypeError, "Invalid argument for string field '%s' (given %s).",
-                 name, rb_class2name(CLASS_OF(value)));
+        rb_raise(cTypeError,
+                 "Invalid argument for string field '%s' (given %s).", name,
+                 rb_class2name(CLASS_OF(value)));
       }
 
       if (rb_obj_encoding(value) != utf8) {
-        // Note: this will not duplicate underlying string data unless necessary.
+        // Note: this will not duplicate underlying string data unless
+        // necessary.
         value = rb_str_encode(value, utf8, 0, Qnil);
 
         if (rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) {
@@ -175,15 +183,17 @@
       ret.str_val = Convert_StringData(value, arena);
       break;
     }
-    case UPB_TYPE_BYTES: {
+    case kUpb_CType_Bytes: {
       VALUE bytes = rb_enc_from_encoding(rb_ascii8bit_encoding());
       if (CLASS_OF(value) != rb_cString) {
-        rb_raise(cTypeError, "Invalid argument for bytes field '%s' (given %s).",
-                 name, rb_class2name(CLASS_OF(value)));
+        rb_raise(cTypeError,
+                 "Invalid argument for bytes field '%s' (given %s).", name,
+                 rb_class2name(CLASS_OF(value)));
       }
 
       if (rb_obj_encoding(value) != bytes) {
-        // Note: this will not duplicate underlying string data unless necessary.
+        // Note: this will not duplicate underlying string data unless
+        // necessary.
         // TODO(haberman): is this really necessary to get raw bytes?
         value = rb_str_encode(value, bytes, 0, Qnil);
       }
@@ -191,33 +201,33 @@
       ret.str_val = Convert_StringData(value, arena);
       break;
     }
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       ret.msg_val =
           Message_GetUpbMessage(value, type_info.def.msgdef, name, arena);
       break;
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Enum:
       ret.int32_val = Convert_ToEnum(value, name, type_info.def.enumdef);
       break;
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_Int32:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_UInt64:
       Convert_CheckInt(name, type_info.type, value);
       switch (type_info.type) {
-      case UPB_TYPE_INT32:
-        ret.int32_val = NUM2INT(value);
-        break;
-      case UPB_TYPE_INT64:
-        ret.int64_val = NUM2LL(value);
-        break;
-      case UPB_TYPE_UINT32:
-        ret.uint32_val = NUM2UINT(value);
-        break;
-      case UPB_TYPE_UINT64:
-        ret.uint64_val = NUM2ULL(value);
-        break;
-      default:
-        break;
+        case kUpb_CType_Int32:
+          ret.int32_val = NUM2INT(value);
+          break;
+        case kUpb_CType_Int64:
+          ret.int64_val = NUM2LL(value);
+          break;
+        case kUpb_CType_UInt32:
+          ret.uint32_val = NUM2UINT(value);
+          break;
+        case kUpb_CType_UInt64:
+          ret.uint64_val = NUM2ULL(value);
+          break;
+        default:
+          break;
       }
       break;
     default:
@@ -227,45 +237,46 @@
   return ret;
 }
 
-VALUE Convert_UpbToRuby(upb_msgval upb_val, TypeInfo type_info, VALUE arena) {
+VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info,
+                        VALUE arena) {
   switch (type_info.type) {
-    case UPB_TYPE_FLOAT:
+    case kUpb_CType_Float:
       return DBL2NUM(upb_val.float_val);
-    case UPB_TYPE_DOUBLE:
+    case kUpb_CType_Double:
       return DBL2NUM(upb_val.double_val);
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       return upb_val.bool_val ? Qtrue : Qfalse;
-    case UPB_TYPE_INT32:
+    case kUpb_CType_Int32:
       return INT2NUM(upb_val.int32_val);
-    case UPB_TYPE_INT64:
+    case kUpb_CType_Int64:
       return LL2NUM(upb_val.int64_val);
-    case UPB_TYPE_UINT32:
+    case kUpb_CType_UInt32:
       return UINT2NUM(upb_val.uint32_val);
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_UInt64:
       return ULL2NUM(upb_val.int64_val);
-    case UPB_TYPE_ENUM: {
-      const char* name =
-          upb_enumdef_iton(type_info.def.enumdef, upb_val.int32_val);
-      if (name) {
-        return ID2SYM(rb_intern(name));
+    case kUpb_CType_Enum: {
+      const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(
+          type_info.def.enumdef, upb_val.int32_val);
+      if (ev) {
+        return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
       } else {
         return INT2NUM(upb_val.int32_val);
       }
     }
-    case UPB_TYPE_STRING: {
+    case kUpb_CType_String: {
       VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size);
       rb_enc_associate(str_rb, rb_utf8_encoding());
       rb_obj_freeze(str_rb);
       return str_rb;
     }
-    case UPB_TYPE_BYTES: {
+    case kUpb_CType_Bytes: {
       VALUE str_rb = rb_str_new(upb_val.str_val.data, upb_val.str_val.size);
       rb_enc_associate(str_rb, rb_ascii8bit_encoding());
       rb_obj_freeze(str_rb);
       return str_rb;
     }
-    case UPB_TYPE_MESSAGE:
-      return Message_GetRubyWrapper((upb_msg*)upb_val.msg_val,
+    case kUpb_CType_Message:
+      return Message_GetRubyWrapper((upb_Message*)upb_val.msg_val,
                                     type_info.def.msgdef, arena);
     default:
       rb_raise(rb_eRuntimeError, "Convert_UpbToRuby(): Unexpected type %d",
@@ -273,24 +284,24 @@
   }
 }
 
-upb_msgval Msgval_DeepCopy(upb_msgval msgval, TypeInfo type_info,
-                           upb_arena* arena) {
-  upb_msgval new_msgval;
+upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info,
+                                 upb_Arena* arena) {
+  upb_MessageValue new_msgval;
 
   switch (type_info.type) {
     default:
       memcpy(&new_msgval, &msgval, sizeof(msgval));
       break;
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES: {
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes: {
       size_t n = msgval.str_val.size;
-      char *mem = upb_arena_malloc(arena, n);
+      char* mem = upb_Arena_Malloc(arena, n);
       new_msgval.str_val.data = mem;
       new_msgval.str_val.size = n;
       memcpy(mem, msgval.str_val.data, n);
       break;
     }
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       new_msgval.msg_val =
           Message_deep_copy(msgval.msg_val, type_info.def.msgdef, arena);
       break;
@@ -299,48 +310,50 @@
   return new_msgval;
 }
 
-bool Msgval_IsEqual(upb_msgval val1, upb_msgval val2, TypeInfo type_info) {
+bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2,
+                    TypeInfo type_info) {
   switch (type_info.type) {
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       return memcmp(&val1, &val2, 1) == 0;
-    case UPB_TYPE_FLOAT:
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Float:
+    case kUpb_CType_Int32:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_Enum:
       return memcmp(&val1, &val2, 4) == 0;
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_Double:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt64:
       return memcmp(&val1, &val2, 8) == 0;
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       return val1.str_val.size == val2.str_val.size &&
-             memcmp(val1.str_val.data, val2.str_val.data,
-                    val1.str_val.size) == 0;
-    case UPB_TYPE_MESSAGE:
+             memcmp(val1.str_val.data, val2.str_val.data, val1.str_val.size) ==
+                 0;
+    case kUpb_CType_Message:
       return Message_Equal(val1.msg_val, val2.msg_val, type_info.def.msgdef);
     default:
       rb_raise(rb_eRuntimeError, "Internal error, unexpected type");
   }
 }
 
-uint64_t Msgval_GetHash(upb_msgval val, TypeInfo type_info, uint64_t seed) {
+uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info,
+                        uint64_t seed) {
   switch (type_info.type) {
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       return Wyhash(&val, 1, seed, kWyhashSalt);
-    case UPB_TYPE_FLOAT:
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Float:
+    case kUpb_CType_Int32:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_Enum:
       return Wyhash(&val, 4, seed, kWyhashSalt);
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_Double:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt64:
       return Wyhash(&val, 8, seed, kWyhashSalt);
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       return Wyhash(val.str_val.data, val.str_val.size, seed, kWyhashSalt);
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       return Message_Hash(val.msg_val, type_info.def.msgdef, seed);
     default:
       rb_raise(rb_eRuntimeError, "Internal error, unexpected type");
diff --git a/ruby/ext/google/protobuf_c/convert.h b/ruby/ext/google/protobuf_c/convert.h
index cda18a0..e48c979 100644
--- a/ruby/ext/google/protobuf_c/convert.h
+++ b/ruby/ext/google/protobuf_c/convert.h
@@ -36,7 +36,7 @@
 #include "protobuf.h"
 #include "ruby-upb.h"
 
-// Converts |ruby_val| to a upb_msgval according to |type_info|.
+// Converts |ruby_val| to a upb_MessageValue according to |type_info|.
 //
 // The |arena| parameter indicates the lifetime of the container where this
 // value will be assigned. It is used as follows:
@@ -47,8 +47,8 @@
 // - If type is message and the Ruby value is a message instance, we will fuse
 //   the message's arena into |arena|, to ensure that this message outlives the
 //   container.
-upb_msgval Convert_RubyToUpb(VALUE ruby_val, const char *name,
-                             TypeInfo type_info, upb_arena *arena);
+upb_MessageValue Convert_RubyToUpb(VALUE ruby_val, const char *name,
+                                   TypeInfo type_info, upb_Arena *arena);
 
 // Converts |upb_val| to a Ruby VALUE according to |type_info|. This may involve
 // creating a Ruby wrapper object.
@@ -56,17 +56,20 @@
 // The |arena| parameter indicates the arena that owns the lifetime of
 // |upb_val|. Any Ruby wrapper object that is created will reference |arena|
 // and ensure it outlives the wrapper.
-VALUE Convert_UpbToRuby(upb_msgval upb_val, TypeInfo type_info, VALUE arena);
+VALUE Convert_UpbToRuby(upb_MessageValue upb_val, TypeInfo type_info,
+                        VALUE arena);
 
 // Creates a deep copy of |msgval| in |arena|.
-upb_msgval Msgval_DeepCopy(upb_msgval msgval, TypeInfo type_info,
-                           upb_arena *arena);
+upb_MessageValue Msgval_DeepCopy(upb_MessageValue msgval, TypeInfo type_info,
+                                 upb_Arena *arena);
 
 // Returns true if |val1| and |val2| are equal. Their type is given by
 // |type_info|.
-bool Msgval_IsEqual(upb_msgval val1, upb_msgval val2, TypeInfo type_info);
+bool Msgval_IsEqual(upb_MessageValue val1, upb_MessageValue val2,
+                    TypeInfo type_info);
 
-// Returns a hash value for the given upb_msgval.
-uint64_t Msgval_GetHash(upb_msgval val, TypeInfo type_info, uint64_t seed);
+// Returns a hash value for the given upb_MessageValue.
+uint64_t Msgval_GetHash(upb_MessageValue val, TypeInfo type_info,
+                        uint64_t seed);
 
 #endif  // RUBY_PROTOBUF_CONVERT_H_
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index fd32cce..aaa8b4d 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -41,11 +41,11 @@
 // instances.
 // -----------------------------------------------------------------------------
 
-static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def);
-static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def);
-static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def);
-static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def);
-static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def);
+static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def);
+static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def);
+static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def);
+static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def);
+static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def);
 
 // A distinct object that is not accessible from Ruby.  We use this as a
 // constructor argument to enforce that certain objects cannot be created from
@@ -74,7 +74,7 @@
 
 typedef struct {
   VALUE def_to_descriptor;  // Hash table of def* -> Ruby descriptor.
-  upb_symtab* symtab;
+  upb_DefPool* symtab;
 } DescriptorPool;
 
 VALUE cDescriptorPool = Qnil;
@@ -90,14 +90,14 @@
 
 static void DescriptorPool_free(void* _self) {
   DescriptorPool* self = _self;
-  upb_symtab_free(self->symtab);
+  upb_DefPool_Free(self->symtab);
   xfree(self);
 }
 
 static const rb_data_type_t DescriptorPool_type = {
-  "Google::Protobuf::DescriptorPool",
-  {DescriptorPool_mark, DescriptorPool_free, NULL},
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::DescriptorPool",
+    {DescriptorPool_mark, DescriptorPool_free, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static DescriptorPool* ruby_to_DescriptorPool(VALUE val) {
@@ -107,8 +107,8 @@
 }
 
 // Exposed to other modules in defs.h.
-const upb_symtab *DescriptorPool_GetSymtab(VALUE desc_pool_rb) {
-  DescriptorPool *pool = ruby_to_DescriptorPool(desc_pool_rb);
+const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb) {
+  DescriptorPool* pool = ruby_to_DescriptorPool(desc_pool_rb);
   return pool->symtab;
 }
 
@@ -126,7 +126,7 @@
   ret = TypedData_Wrap_Struct(klass, &DescriptorPool_type, self);
 
   self->def_to_descriptor = rb_hash_new();
-  self->symtab = upb_symtab_new();
+  self->symtab = upb_DefPool_New();
   ObjectCache_Add(self->symtab, ret);
 
   return ret;
@@ -143,7 +143,7 @@
   DescriptorPool* self = ruby_to_DescriptorPool(_self);
   Check_Type(serialized_file_proto, T_STRING);
   VALUE arena_rb = Arena_new();
-  upb_arena *arena = Arena_get(arena_rb);
+  upb_Arena* arena = Arena_get(arena_rb);
   google_protobuf_FileDescriptorProto* file_proto =
       google_protobuf_FileDescriptorProto_parse(
           RSTRING_PTR(serialized_file_proto),
@@ -151,13 +151,13 @@
   if (!file_proto) {
     rb_raise(rb_eArgError, "Unable to parse FileDescriptorProto");
   }
-  upb_status status;
-  upb_status_clear(&status);
-  const upb_filedef* filedef =
-      upb_symtab_addfile(self->symtab, file_proto, &status);
+  upb_Status status;
+  upb_Status_Clear(&status);
+  const upb_FileDef* filedef =
+      upb_DefPool_AddFile(self->symtab, file_proto, &status);
   if (!filedef) {
     rb_raise(cTypeError, "Unable to build file to DescriptorPool: %s",
-             upb_status_errmsg(&status));
+             upb_Status_ErrorMessage(&status));
   }
   return get_filedef_obj(_self, filedef);
 }
@@ -172,15 +172,15 @@
 static VALUE DescriptorPool_lookup(VALUE _self, VALUE name) {
   DescriptorPool* self = ruby_to_DescriptorPool(_self);
   const char* name_str = get_str(name);
-  const upb_msgdef* msgdef;
-  const upb_enumdef* enumdef;
+  const upb_MessageDef* msgdef;
+  const upb_EnumDef* enumdef;
 
-  msgdef = upb_symtab_lookupmsg(self->symtab, name_str);
+  msgdef = upb_DefPool_FindMessageByName(self->symtab, name_str);
   if (msgdef) {
     return get_msgdef_obj(_self, msgdef);
   }
 
-  enumdef = upb_symtab_lookupenum(self->symtab, name_str);
+  enumdef = upb_DefPool_FindEnumByName(self->symtab, name_str);
   if (enumdef) {
     return get_enumdef_obj(_self, enumdef);
   }
@@ -202,8 +202,7 @@
 }
 
 static void DescriptorPool_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "DescriptorPool", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "DescriptorPool", rb_cObject);
   rb_define_alloc_func(klass, DescriptorPool_alloc);
   rb_define_method(klass, "add_serialized_file",
                    DescriptorPool_add_serialized_file, 1);
@@ -222,7 +221,7 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_msgdef* msgdef;
+  const upb_MessageDef* msgdef;
   VALUE klass;
   VALUE descriptor_pool;
 } Descriptor;
@@ -236,9 +235,9 @@
 }
 
 static const rb_data_type_t Descriptor_type = {
-  "Google::Protobuf::Descriptor",
-  {Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::Descriptor",
+    {Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static Descriptor* ruby_to_Descriptor(VALUE val) {
@@ -281,7 +280,7 @@
   }
 
   self->descriptor_pool = descriptor_pool;
-  self->msgdef = (const upb_msgdef*)NUM2ULL(ptr);
+  self->msgdef = (const upb_MessageDef*)NUM2ULL(ptr);
 
   return Qnil;
 }
@@ -294,7 +293,8 @@
  */
 static VALUE Descriptor_file_descriptor(VALUE _self) {
   Descriptor* self = ruby_to_Descriptor(_self);
-  return get_filedef_obj(self->descriptor_pool, upb_msgdef_file(self->msgdef));
+  return get_filedef_obj(self->descriptor_pool,
+                         upb_MessageDef_File(self->msgdef));
 }
 
 /*
@@ -306,7 +306,7 @@
  */
 static VALUE Descriptor_name(VALUE _self) {
   Descriptor* self = ruby_to_Descriptor(_self);
-  return rb_str_maybe_null(upb_msgdef_fullname(self->msgdef));
+  return rb_str_maybe_null(upb_MessageDef_FullName(self->msgdef));
 }
 
 /*
@@ -318,11 +318,9 @@
 static VALUE Descriptor_each(VALUE _self) {
   Descriptor* self = ruby_to_Descriptor(_self);
 
-  upb_msg_field_iter it;
-  for (upb_msg_field_begin(&it, self->msgdef);
-       !upb_msg_field_done(&it);
-       upb_msg_field_next(&it)) {
-    const upb_fielddef* field = upb_msg_iter_field(&it);
+  int n = upb_MessageDef_FieldCount(self->msgdef);
+  for (int i = 0; i < n; i++) {
+    const upb_FieldDef* field = upb_MessageDef_Field(self->msgdef, i);
     VALUE obj = get_fielddef_obj(self->descriptor_pool, field);
     rb_yield(obj);
   }
@@ -339,7 +337,7 @@
 static VALUE Descriptor_lookup(VALUE _self, VALUE name) {
   Descriptor* self = ruby_to_Descriptor(_self);
   const char* s = get_str(name);
-  const upb_fielddef* field = upb_msgdef_ntofz(self->msgdef, s);
+  const upb_FieldDef* field = upb_MessageDef_FindFieldByName(self->msgdef, s);
   if (field == NULL) {
     return Qnil;
   }
@@ -356,11 +354,9 @@
 static VALUE Descriptor_each_oneof(VALUE _self) {
   Descriptor* self = ruby_to_Descriptor(_self);
 
-  upb_msg_oneof_iter it;
-  for (upb_msg_oneof_begin(&it, self->msgdef);
-       !upb_msg_oneof_done(&it);
-       upb_msg_oneof_next(&it)) {
-    const upb_oneofdef* oneof = upb_msg_iter_oneof(&it);
+  int n = upb_MessageDef_OneofCount(self->msgdef);
+  for (int i = 0; i < n; i++) {
+    const upb_OneofDef* oneof = upb_MessageDef_Oneof(self->msgdef, i);
     VALUE obj = get_oneofdef_obj(self->descriptor_pool, oneof);
     rb_yield(obj);
   }
@@ -377,7 +373,7 @@
 static VALUE Descriptor_lookup_oneof(VALUE _self, VALUE name) {
   Descriptor* self = ruby_to_Descriptor(_self);
   const char* s = get_str(name);
-  const upb_oneofdef* oneof = upb_msgdef_ntooz(self->msgdef, s);
+  const upb_OneofDef* oneof = upb_MessageDef_FindOneofByName(self->msgdef, s);
   if (oneof == NULL) {
     return Qnil;
   }
@@ -399,8 +395,7 @@
 }
 
 static void Descriptor_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "Descriptor", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "Descriptor", rb_cObject);
   rb_define_alloc_func(klass, Descriptor_alloc);
   rb_define_method(klass, "initialize", Descriptor_initialize, 3);
   rb_define_method(klass, "each", Descriptor_each, 0);
@@ -420,8 +415,8 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_filedef* filedef;
-  VALUE descriptor_pool;  // Owns the upb_filedef.
+  const upb_FileDef* filedef;
+  VALUE descriptor_pool;  // Owns the upb_FileDef.
 } FileDescriptor;
 
 static VALUE cFileDescriptor = Qnil;
@@ -432,9 +427,9 @@
 }
 
 static const rb_data_type_t FileDescriptor_type = {
-  "Google::Protobuf::FileDescriptor",
-  {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::FileDescriptor",
+    {FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static FileDescriptor* ruby_to_FileDescriptor(VALUE val) {
@@ -459,7 +454,7 @@
  * to a builder.
  */
 static VALUE FileDescriptor_initialize(VALUE _self, VALUE cookie,
-                                VALUE descriptor_pool, VALUE ptr) {
+                                       VALUE descriptor_pool, VALUE ptr) {
   FileDescriptor* self = ruby_to_FileDescriptor(_self);
 
   if (cookie != c_only_cookie) {
@@ -468,7 +463,7 @@
   }
 
   self->descriptor_pool = descriptor_pool;
-  self->filedef = (const upb_filedef*)NUM2ULL(ptr);
+  self->filedef = (const upb_FileDef*)NUM2ULL(ptr);
 
   return Qnil;
 }
@@ -481,7 +476,7 @@
  */
 static VALUE FileDescriptor_name(VALUE _self) {
   FileDescriptor* self = ruby_to_FileDescriptor(_self);
-  const char* name = upb_filedef_name(self->filedef);
+  const char* name = upb_FileDef_Name(self->filedef);
   return name == NULL ? Qnil : rb_str_new2(name);
 }
 
@@ -497,16 +492,18 @@
 static VALUE FileDescriptor_syntax(VALUE _self) {
   FileDescriptor* self = ruby_to_FileDescriptor(_self);
 
-  switch (upb_filedef_syntax(self->filedef)) {
-    case UPB_SYNTAX_PROTO3: return ID2SYM(rb_intern("proto3"));
-    case UPB_SYNTAX_PROTO2: return ID2SYM(rb_intern("proto2"));
-    default: return Qnil;
+  switch (upb_FileDef_Syntax(self->filedef)) {
+    case kUpb_Syntax_Proto3:
+      return ID2SYM(rb_intern("proto3"));
+    case kUpb_Syntax_Proto2:
+      return ID2SYM(rb_intern("proto2"));
+    default:
+      return Qnil;
   }
 }
 
 static void FileDescriptor_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "FileDescriptor", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "FileDescriptor", rb_cObject);
   rb_define_alloc_func(klass, FileDescriptor_alloc);
   rb_define_method(klass, "initialize", FileDescriptor_initialize, 3);
   rb_define_method(klass, "name", FileDescriptor_name, 0);
@@ -520,8 +517,8 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_fielddef* fielddef;
-  VALUE descriptor_pool;  // Owns the upb_fielddef.
+  const upb_FieldDef* fielddef;
+  VALUE descriptor_pool;  // Owns the upb_FieldDef.
 } FieldDescriptor;
 
 static VALUE cFieldDescriptor = Qnil;
@@ -532,9 +529,9 @@
 }
 
 static const rb_data_type_t FieldDescriptor_type = {
-  "Google::Protobuf::FieldDescriptor",
-  {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::FieldDescriptor",
+    {FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) {
@@ -573,7 +570,7 @@
   }
 
   self->descriptor_pool = descriptor_pool;
-  self->fielddef = (const upb_fielddef*)NUM2ULL(ptr);
+  self->fielddef = (const upb_FieldDef*)NUM2ULL(ptr);
 
   return Qnil;
 }
@@ -586,31 +583,31 @@
  */
 static VALUE FieldDescriptor_name(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  return rb_str_maybe_null(upb_fielddef_name(self->fielddef));
+  return rb_str_maybe_null(upb_FieldDef_Name(self->fielddef));
 }
 
 // Non-static, exposed to other .c files.
-upb_fieldtype_t ruby_to_fieldtype(VALUE type) {
+upb_CType ruby_to_fieldtype(VALUE type) {
   if (TYPE(type) != T_SYMBOL) {
     rb_raise(rb_eArgError, "Expected symbol for field type.");
   }
 
-#define CONVERT(upb, ruby)                                           \
-  if (SYM2ID(type) == rb_intern( # ruby )) {                         \
-    return UPB_TYPE_ ## upb;                                         \
+#define CONVERT(upb, ruby)                \
+  if (SYM2ID(type) == rb_intern(#ruby)) { \
+    return kUpb_CType_##upb;                \
   }
 
-  CONVERT(FLOAT, float);
-  CONVERT(DOUBLE, double);
-  CONVERT(BOOL, bool);
-  CONVERT(STRING, string);
-  CONVERT(BYTES, bytes);
-  CONVERT(MESSAGE, message);
-  CONVERT(ENUM, enum);
-  CONVERT(INT32, int32);
-  CONVERT(INT64, int64);
-  CONVERT(UINT32, uint32);
-  CONVERT(UINT64, uint64);
+  CONVERT(Float, float);
+  CONVERT(Double, double);
+  CONVERT(Bool, bool);
+  CONVERT(String, string);
+  CONVERT(Bytes, bytes);
+  CONVERT(Message, message);
+  CONVERT(Enum, enum);
+  CONVERT(Int32, int32);
+  CONVERT(Int64, int64);
+  CONVERT(UInt32, uint32);
+  CONVERT(UInt64, uint64);
 
 #undef CONVERT
 
@@ -618,28 +615,29 @@
   return 0;
 }
 
-static VALUE descriptortype_to_ruby(upb_descriptortype_t type) {
+static VALUE descriptortype_to_ruby(upb_FieldType type) {
   switch (type) {
-#define CONVERT(upb, ruby)                                           \
-    case UPB_DESCRIPTOR_TYPE_ ## upb : return ID2SYM(rb_intern( # ruby ));
-    CONVERT(FLOAT, float);
-    CONVERT(DOUBLE, double);
-    CONVERT(BOOL, bool);
-    CONVERT(STRING, string);
-    CONVERT(BYTES, bytes);
-    CONVERT(MESSAGE, message);
-    CONVERT(GROUP, group);
-    CONVERT(ENUM, enum);
-    CONVERT(INT32, int32);
-    CONVERT(INT64, int64);
-    CONVERT(UINT32, uint32);
-    CONVERT(UINT64, uint64);
-    CONVERT(SINT32, sint32);
-    CONVERT(SINT64, sint64);
-    CONVERT(FIXED32, fixed32);
-    CONVERT(FIXED64, fixed64);
-    CONVERT(SFIXED32, sfixed32);
-    CONVERT(SFIXED64, sfixed64);
+#define CONVERT(upb, ruby)        \
+  case kUpb_FieldType_##upb: \
+    return ID2SYM(rb_intern(#ruby));
+    CONVERT(Float, float);
+    CONVERT(Double, double);
+    CONVERT(Bool, bool);
+    CONVERT(String, string);
+    CONVERT(Bytes, bytes);
+    CONVERT(Message, message);
+    CONVERT(Group, group);
+    CONVERT(Enum, enum);
+    CONVERT(Int32, int32);
+    CONVERT(Int64, int64);
+    CONVERT(UInt32, uint32);
+    CONVERT(UInt64, uint64);
+    CONVERT(SInt32, sint32);
+    CONVERT(SInt64, sint64);
+    CONVERT(Fixed32, fixed32);
+    CONVERT(Fixed64, fixed64);
+    CONVERT(SFixed32, sfixed32);
+    CONVERT(SFixed64, sfixed64);
 #undef CONVERT
   }
   return Qnil;
@@ -657,7 +655,7 @@
  */
 static VALUE FieldDescriptor__type(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  return descriptortype_to_ruby(upb_fielddef_descriptortype(self->fielddef));
+  return descriptortype_to_ruby(upb_FieldDef_Type(self->fielddef));
 }
 
 /*
@@ -668,17 +666,16 @@
  */
 static VALUE FieldDescriptor_default(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_fielddef *f = self->fielddef;
-  upb_msgval default_val = {0};
-  if (upb_fielddef_issubmsg(f)) {
+  const upb_FieldDef* f = self->fielddef;
+  upb_MessageValue default_val = {0};
+  if (upb_FieldDef_IsSubMessage(f)) {
     return Qnil;
-  } else if (!upb_fielddef_isseq(f)) {
-    default_val = upb_fielddef_default(f);
+  } else if (!upb_FieldDef_IsRepeated(f)) {
+    default_val = upb_FieldDef_Default(f);
   }
   return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
 }
 
-
 /*
  * call-seq:
  *     FieldDescriptor.json_name => json_name
@@ -687,8 +684,8 @@
  */
 static VALUE FieldDescriptor_json_name(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_fielddef *f = self->fielddef;
-  const char *json_name = upb_fielddef_jsonname(f);
+  const upb_FieldDef* f = self->fielddef;
+  const char* json_name = upb_FieldDef_JsonName(f);
   return rb_str_new2(json_name);
 }
 
@@ -703,13 +700,14 @@
  */
 static VALUE FieldDescriptor_label(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  switch (upb_fielddef_label(self->fielddef)) {
-#define CONVERT(upb, ruby)                                           \
-    case UPB_LABEL_ ## upb : return ID2SYM(rb_intern( # ruby ));
+  switch (upb_FieldDef_Label(self->fielddef)) {
+#define CONVERT(upb, ruby) \
+  case kUpb_Label_##upb:    \
+    return ID2SYM(rb_intern(#ruby));
 
-    CONVERT(OPTIONAL, optional);
-    CONVERT(REQUIRED, required);
-    CONVERT(REPEATED, repeated);
+    CONVERT(Optional, optional);
+    CONVERT(Required, required);
+    CONVERT(Repeated, repeated);
 
 #undef CONVERT
   }
@@ -725,7 +723,7 @@
  */
 static VALUE FieldDescriptor_number(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  return INT2NUM(upb_fielddef_number(self->fielddef));
+  return INT2NUM(upb_FieldDef_Number(self->fielddef));
 }
 
 /*
@@ -739,13 +737,13 @@
  */
 static VALUE FieldDescriptor_submsg_name(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  switch (upb_fielddef_type(self->fielddef)) {
-    case UPB_TYPE_ENUM:
+  switch (upb_FieldDef_CType(self->fielddef)) {
+    case kUpb_CType_Enum:
       return rb_str_new2(
-          upb_enumdef_fullname(upb_fielddef_enumsubdef(self->fielddef)));
-    case UPB_TYPE_MESSAGE:
+          upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(self->fielddef)));
+    case kUpb_CType_Message:
       return rb_str_new2(
-          upb_msgdef_fullname(upb_fielddef_msgsubdef(self->fielddef)));
+          upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(self->fielddef)));
     default:
       return Qnil;
   }
@@ -762,13 +760,13 @@
  */
 static VALUE FieldDescriptor_subtype(VALUE _self) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  switch (upb_fielddef_type(self->fielddef)) {
-    case UPB_TYPE_ENUM:
+  switch (upb_FieldDef_CType(self->fielddef)) {
+    case kUpb_CType_Enum:
       return get_enumdef_obj(self->descriptor_pool,
-                             upb_fielddef_enumsubdef(self->fielddef));
-    case UPB_TYPE_MESSAGE:
+                             upb_FieldDef_EnumSubDef(self->fielddef));
+    case kUpb_CType_Message:
       return get_msgdef_obj(self->descriptor_pool,
-                            upb_fielddef_msgsubdef(self->fielddef));
+                            upb_FieldDef_MessageSubDef(self->fielddef));
     default:
       return Qnil;
   }
@@ -783,11 +781,11 @@
  */
 static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_msgdef *m;
+  const upb_MessageDef* m;
 
   Message_Get(msg_rb, &m);
 
-  if (m != upb_fielddef_containingtype(self->fielddef)) {
+  if (m != upb_FieldDef_ContainingType(self->fielddef)) {
     rb_raise(cTypeError, "get method called on wrong message type");
   }
 
@@ -803,16 +801,16 @@
  */
 static VALUE FieldDescriptor_has(VALUE _self, VALUE msg_rb) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_msgdef *m;
-  const upb_msgdef *msg = Message_Get(msg_rb, &m);
+  const upb_MessageDef* m;
+  const upb_MessageDef* msg = Message_Get(msg_rb, &m);
 
-  if (m != upb_fielddef_containingtype(self->fielddef)) {
+  if (m != upb_FieldDef_ContainingType(self->fielddef)) {
     rb_raise(cTypeError, "has method called on wrong message type");
-  } else if (!upb_fielddef_haspresence(self->fielddef)) {
+  } else if (!upb_FieldDef_HasPresence(self->fielddef)) {
     rb_raise(rb_eArgError, "does not track presence");
   }
 
-  return upb_msg_has(msg, self->fielddef) ? Qtrue : Qfalse;
+  return upb_Message_Has(msg, self->fielddef) ? Qtrue : Qfalse;
 }
 
 /*
@@ -823,14 +821,14 @@
  */
 static VALUE FieldDescriptor_clear(VALUE _self, VALUE msg_rb) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_msgdef *m;
-  upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
+  const upb_MessageDef* m;
+  upb_MessageDef* msg = Message_GetMutable(msg_rb, &m);
 
-  if (m != upb_fielddef_containingtype(self->fielddef)) {
+  if (m != upb_FieldDef_ContainingType(self->fielddef)) {
     rb_raise(cTypeError, "has method called on wrong message type");
   }
 
-  upb_msg_clearfield(msg, self->fielddef);
+  upb_Message_ClearField(msg, self->fielddef);
   return Qnil;
 }
 
@@ -844,24 +842,23 @@
  */
 static VALUE FieldDescriptor_set(VALUE _self, VALUE msg_rb, VALUE value) {
   FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
-  const upb_msgdef *m;
-  upb_msgdef *msg = Message_GetMutable(msg_rb, &m);
-  upb_arena *arena = Arena_get(Message_GetArena(msg_rb));
-  upb_msgval msgval;
+  const upb_MessageDef* m;
+  upb_MessageDef* msg = Message_GetMutable(msg_rb, &m);
+  upb_Arena* arena = Arena_get(Message_GetArena(msg_rb));
+  upb_MessageValue msgval;
 
-  if (m != upb_fielddef_containingtype(self->fielddef)) {
+  if (m != upb_FieldDef_ContainingType(self->fielddef)) {
     rb_raise(cTypeError, "set method called on wrong message type");
   }
 
-  msgval = Convert_RubyToUpb(value, upb_fielddef_name(self->fielddef),
+  msgval = Convert_RubyToUpb(value, upb_FieldDef_Name(self->fielddef),
                              TypeInfo_get(self->fielddef), arena);
-  upb_msg_set(msg, self->fielddef, msgval, arena);
+  upb_Message_Set(msg, self->fielddef, msgval, arena);
   return Qnil;
 }
 
 static void FieldDescriptor_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "FieldDescriptor", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "FieldDescriptor", rb_cObject);
   rb_define_alloc_func(klass, FieldDescriptor_alloc);
   rb_define_method(klass, "initialize", FieldDescriptor_initialize, 3);
   rb_define_method(klass, "name", FieldDescriptor_name, 0);
@@ -885,8 +882,8 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_oneofdef* oneofdef;
-  VALUE descriptor_pool;  // Owns the upb_oneofdef.
+  const upb_OneofDef* oneofdef;
+  VALUE descriptor_pool;  // Owns the upb_OneofDef.
 } OneofDescriptor;
 
 static VALUE cOneofDescriptor = Qnil;
@@ -930,7 +927,7 @@
  * Creates a descriptor wrapper object.  May only be called from C.
  */
 static VALUE OneofDescriptor_initialize(VALUE _self, VALUE cookie,
-                                 VALUE descriptor_pool, VALUE ptr) {
+                                        VALUE descriptor_pool, VALUE ptr) {
   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
 
   if (cookie != c_only_cookie) {
@@ -939,7 +936,7 @@
   }
 
   self->descriptor_pool = descriptor_pool;
-  self->oneofdef = (const upb_oneofdef*)NUM2ULL(ptr);
+  self->oneofdef = (const upb_OneofDef*)NUM2ULL(ptr);
 
   return Qnil;
 }
@@ -952,7 +949,7 @@
  */
 static VALUE OneofDescriptor_name(VALUE _self) {
   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
-  return rb_str_maybe_null(upb_oneofdef_name(self->oneofdef));
+  return rb_str_maybe_null(upb_OneofDef_Name(self->oneofdef));
 }
 
 /*
@@ -963,11 +960,10 @@
  */
 static VALUE OneofDescriptor_each(VALUE _self) {
   OneofDescriptor* self = ruby_to_OneofDescriptor(_self);
-  upb_oneof_iter it;
-  for (upb_oneof_begin(&it, self->oneofdef);
-       !upb_oneof_done(&it);
-       upb_oneof_next(&it)) {
-    const upb_fielddef* f = upb_oneof_iter_field(&it);
+
+  int n = upb_OneofDef_FieldCount(self->oneofdef);
+  for (int i = 0; i < n; i++) {
+    const upb_FieldDef* f = upb_OneofDef_Field(self->oneofdef, i);
     VALUE obj = get_fielddef_obj(self->descriptor_pool, f);
     rb_yield(obj);
   }
@@ -975,8 +971,7 @@
 }
 
 static void OneofDescriptor_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "OneofDescriptor", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "OneofDescriptor", rb_cObject);
   rb_define_alloc_func(klass, OneofDescriptor_alloc);
   rb_define_method(klass, "initialize", OneofDescriptor_initialize, 3);
   rb_define_method(klass, "name", OneofDescriptor_name, 0);
@@ -991,9 +986,9 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_enumdef* enumdef;
-  VALUE module;  // begins as nil
-  VALUE descriptor_pool;  // Owns the upb_enumdef.
+  const upb_EnumDef* enumdef;
+  VALUE module;           // begins as nil
+  VALUE descriptor_pool;  // Owns the upb_EnumDef.
 } EnumDescriptor;
 
 static VALUE cEnumDescriptor = Qnil;
@@ -1005,9 +1000,9 @@
 }
 
 static const rb_data_type_t EnumDescriptor_type = {
-  "Google::Protobuf::EnumDescriptor",
-  {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::EnumDescriptor",
+    {EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) {
@@ -1026,8 +1021,8 @@
 }
 
 // Exposed to other modules in defs.h.
-const upb_enumdef *EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) {
-  EnumDescriptor *desc = ruby_to_EnumDescriptor(enum_desc_rb);
+const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb) {
+  EnumDescriptor* desc = ruby_to_EnumDescriptor(enum_desc_rb);
   return desc->enumdef;
 }
 
@@ -1047,7 +1042,7 @@
   }
 
   self->descriptor_pool = descriptor_pool;
-  self->enumdef = (const upb_enumdef*)NUM2ULL(ptr);
+  self->enumdef = (const upb_EnumDef*)NUM2ULL(ptr);
 
   return Qnil;
 }
@@ -1061,7 +1056,7 @@
 static VALUE EnumDescriptor_file_descriptor(VALUE _self) {
   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
   return get_filedef_obj(self->descriptor_pool,
-                         upb_enumdef_file(self->enumdef));
+                         upb_EnumDef_File(self->enumdef));
 }
 
 /*
@@ -1072,7 +1067,7 @@
  */
 static VALUE EnumDescriptor_name(VALUE _self) {
   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
-  return rb_str_maybe_null(upb_enumdef_fullname(self->enumdef));
+  return rb_str_maybe_null(upb_EnumDef_FullName(self->enumdef));
 }
 
 /*
@@ -1084,10 +1079,11 @@
  */
 static VALUE EnumDescriptor_lookup_name(VALUE _self, VALUE name) {
   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
-  const char* name_str= rb_id2name(SYM2ID(name));
-  int32_t val = 0;
-  if (upb_enumdef_ntoiz(self->enumdef, name_str, &val)) {
-    return INT2NUM(val);
+  const char* name_str = rb_id2name(SYM2ID(name));
+  const upb_EnumValueDef *ev =
+      upb_EnumDef_FindValueByName(self->enumdef, name_str);
+  if (ev) {
+    return INT2NUM(upb_EnumValueDef_Number(ev));
   } else {
     return Qnil;
   }
@@ -1103,9 +1099,9 @@
 static VALUE EnumDescriptor_lookup_value(VALUE _self, VALUE number) {
   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
   int32_t val = NUM2INT(number);
-  const char* name = upb_enumdef_iton(self->enumdef, val);
-  if (name != NULL) {
-    return ID2SYM(rb_intern(name));
+  const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(self->enumdef, val);
+  if (ev) {
+    return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
   } else {
     return Qnil;
   }
@@ -1121,12 +1117,11 @@
 static VALUE EnumDescriptor_each(VALUE _self) {
   EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
 
-  upb_enum_iter it;
-  for (upb_enum_begin(&it, self->enumdef);
-       !upb_enum_done(&it);
-       upb_enum_next(&it)) {
-    VALUE key = ID2SYM(rb_intern(upb_enum_iter_name(&it)));
-    VALUE number = INT2NUM(upb_enum_iter_number(&it));
+  int n = upb_EnumDef_ValueCount(self->enumdef);
+  for (int i = 0; i < n; i++) {
+    const upb_EnumValueDef* ev = upb_EnumDef_Value(self->enumdef, i);
+    VALUE key = ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
+    VALUE number = INT2NUM(upb_EnumValueDef_Number(ev));
     rb_yield_values(2, key, number);
   }
 
@@ -1148,8 +1143,7 @@
 }
 
 static void EnumDescriptor_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "EnumDescriptor", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "EnumDescriptor", rb_cObject);
   rb_define_alloc_func(klass, EnumDescriptor_alloc);
   rb_define_method(klass, "initialize", EnumDescriptor_initialize, 3);
   rb_define_method(klass, "name", EnumDescriptor_name, 0);
@@ -1176,7 +1170,7 @@
 
   if (def == Qnil) {
     // Lazily create wrapper object.
-    VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
+    VALUE args[3] = {c_only_cookie, _descriptor_pool, key};
     def = rb_class_new_instance(3, args, klass);
     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
   }
@@ -1184,23 +1178,23 @@
   return def;
 }
 
-static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_msgdef* def) {
+static VALUE get_msgdef_obj(VALUE descriptor_pool, const upb_MessageDef* def) {
   return get_def_obj(descriptor_pool, def, cDescriptor);
 }
 
-static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_enumdef* def) {
+static VALUE get_enumdef_obj(VALUE descriptor_pool, const upb_EnumDef* def) {
   return get_def_obj(descriptor_pool, def, cEnumDescriptor);
 }
 
-static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_fielddef* def) {
+static VALUE get_fielddef_obj(VALUE descriptor_pool, const upb_FieldDef* def) {
   return get_def_obj(descriptor_pool, def, cFieldDescriptor);
 }
 
-static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_filedef* def) {
+static VALUE get_filedef_obj(VALUE descriptor_pool, const upb_FileDef* def) {
   return get_def_obj(descriptor_pool, def, cFileDescriptor);
 }
 
-static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_oneofdef* def) {
+static VALUE get_oneofdef_obj(VALUE descriptor_pool, const upb_OneofDef* def) {
   return get_def_obj(descriptor_pool, def, cOneofDescriptor);
 }
 
@@ -1210,8 +1204,8 @@
 
 // Functions exposed to other modules in defs.h.
 
-VALUE Descriptor_DefToClass(const upb_msgdef *m) {
-  const upb_symtab *symtab = upb_filedef_symtab(upb_msgdef_file(m));
+VALUE Descriptor_DefToClass(const upb_MessageDef* m) {
+  const upb_DefPool* symtab = upb_FileDef_Pool(upb_MessageDef_File(m));
   VALUE pool = ObjectCache_Get(symtab);
   PBRUBY_ASSERT(pool != Qnil);
   VALUE desc_rb = get_msgdef_obj(pool, m);
@@ -1219,15 +1213,16 @@
   return desc->klass;
 }
 
-const upb_msgdef *Descriptor_GetMsgDef(VALUE desc_rb) {
+const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb) {
   const Descriptor* desc = ruby_to_Descriptor(desc_rb);
   return desc->msgdef;
 }
 
-VALUE TypeInfo_InitArg(int argc, VALUE *argv, int skip_arg) {
+VALUE TypeInfo_InitArg(int argc, VALUE* argv, int skip_arg) {
   if (argc > skip_arg) {
     if (argc > 1 + skip_arg) {
-      rb_raise(rb_eArgError, "Expected a maximum of %d arguments.", skip_arg + 1);
+      rb_raise(rb_eArgError, "Expected a maximum of %d arguments.",
+               skip_arg + 1);
     }
     return argv[skip_arg];
   } else {
@@ -1239,7 +1234,7 @@
                             VALUE* type_class, VALUE* init_arg) {
   TypeInfo ret = {ruby_to_fieldtype(argv[skip_arg])};
 
-  if (ret.type == UPB_TYPE_MESSAGE || ret.type == UPB_TYPE_ENUM) {
+  if (ret.type == kUpb_CType_Message || ret.type == kUpb_CType_Enum) {
     *init_arg = TypeInfo_InitArg(argc, argv, skip_arg + 2);
 
     if (argc < 2 + skip_arg) {
@@ -1257,11 +1252,11 @@
                "class or enum as returned by the DescriptorPool.");
     }
 
-    if (ret.type == UPB_TYPE_MESSAGE) {
+    if (ret.type == kUpb_CType_Message) {
       ret.def.msgdef = ruby_to_Descriptor(desc)->msgdef;
       Message_CheckClass(klass);
     } else {
-      PBRUBY_ASSERT(ret.type == UPB_TYPE_ENUM);
+      PBRUBY_ASSERT(ret.type == kUpb_CType_Enum);
       ret.def.enumdef = ruby_to_EnumDescriptor(desc)->enumdef;
     }
   } else {
diff --git a/ruby/ext/google/protobuf_c/defs.h b/ruby/ext/google/protobuf_c/defs.h
index 97a94bb..f559cb0 100644
--- a/ruby/ext/google/protobuf_c/defs.h
+++ b/ruby/ext/google/protobuf_c/defs.h
@@ -40,9 +40,9 @@
 // TypeInfo
 // -----------------------------------------------------------------------------
 
-// This bundles a upb_fieldtype_t and msgdef/enumdef when appropriate. This is
+// This bundles a upb_CType and msgdef/enumdef when appropriate. This is
 // convenient for functions that need type information but cannot necessarily
-// assume a upb_fielddef will be available.
+// assume a upb_FieldDef will be available.
 //
 // For example, Google::Protobuf::Map and Google::Protobuf::RepeatedField can
 // be constructed with type information alone:
@@ -51,21 +51,21 @@
 //   Google::Protobuf::RepeatedField.new(:message, FooMessage)
 
 typedef struct {
-  upb_fieldtype_t type;
+  upb_CType type;
   union {
-    const upb_msgdef* msgdef;      // When type == UPB_TYPE_MESSAGE
-    const upb_enumdef* enumdef;    // When type == UPB_TYPE_ENUM
+    const upb_MessageDef* msgdef;  // When type == kUpb_CType_Message
+    const upb_EnumDef* enumdef;    // When type == kUpb_CType_Enum
   } def;
 } TypeInfo;
 
-static inline TypeInfo TypeInfo_get(const upb_fielddef *f) {
-  TypeInfo ret = {upb_fielddef_type(f), {NULL}};
+static inline TypeInfo TypeInfo_get(const upb_FieldDef* f) {
+  TypeInfo ret = {upb_FieldDef_CType(f), {NULL}};
   switch (ret.type) {
-    case UPB_TYPE_MESSAGE:
-      ret.def.msgdef = upb_fielddef_msgsubdef(f);
+    case kUpb_CType_Message:
+      ret.def.msgdef = upb_FieldDef_MessageSubDef(f);
       break;
-    case UPB_TYPE_ENUM:
-      ret.def.enumdef = upb_fielddef_enumsubdef(f);
+    case kUpb_CType_Enum:
+      ret.def.enumdef = upb_FieldDef_EnumSubDef(f);
       break;
     default:
       break;
@@ -76,9 +76,9 @@
 TypeInfo TypeInfo_FromClass(int argc, VALUE* argv, int skip_arg,
                             VALUE* type_class, VALUE* init_arg);
 
-static inline TypeInfo TypeInfo_from_type(upb_fieldtype_t type) {
+static inline TypeInfo TypeInfo_from_type(upb_CType type) {
   TypeInfo ret = {type};
-  assert(type != UPB_TYPE_MESSAGE && type != UPB_TYPE_ENUM);
+  assert(type != kUpb_CType_Message && type != kUpb_CType_Enum);
   return ret;
 }
 
@@ -86,17 +86,17 @@
 // Other utilities
 // -----------------------------------------------------------------------------
 
-VALUE Descriptor_DefToClass(const upb_msgdef *m);
+VALUE Descriptor_DefToClass(const upb_MessageDef* m);
 
 // Returns the underlying msgdef, enumdef, or symtab (respectively) for the
 // given Descriptor, EnumDescriptor, or DescriptorPool Ruby object.
-const upb_enumdef *EnumDescriptor_GetEnumDef(VALUE enum_desc_rb);
-const upb_symtab *DescriptorPool_GetSymtab(VALUE desc_pool_rb);
-const upb_msgdef *Descriptor_GetMsgDef(VALUE desc_rb);
+const upb_EnumDef* EnumDescriptor_GetEnumDef(VALUE enum_desc_rb);
+const upb_DefPool* DescriptorPool_GetSymtab(VALUE desc_pool_rb);
+const upb_MessageDef* Descriptor_GetMsgDef(VALUE desc_rb);
 
 // Returns a upb field type for the given Ruby symbol
-// (eg. :float => UPB_TYPE_FLOAT).
-upb_fieldtype_t ruby_to_fieldtype(VALUE type);
+// (eg. :float => kUpb_CType_Float).
+upb_CType ruby_to_fieldtype(VALUE type);
 
 // The singleton generated pool (a DescriptorPool object).
 extern VALUE generated_pool;
diff --git a/ruby/ext/google/protobuf_c/extconf.rb b/ruby/ext/google/protobuf_c/extconf.rb
index ec17787..d8f081a 100755
--- a/ruby/ext/google/protobuf_c/extconf.rb
+++ b/ruby/ext/google/protobuf_c/extconf.rb
@@ -2,6 +2,10 @@
 
 require 'mkmf'
 
+ext_name = "google/protobuf_c"
+
+dir_config(ext_name)
+
 if RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /linux/
   $CFLAGS += " -std=gnu99 -O3 -DNDEBUG -fvisibility=hidden -Wall -Wsign-compare -Wno-declaration-after-statement"
 else
@@ -14,7 +18,11 @@
   $LDFLAGS += " -Wl,-wrap,memcpy"
 end
 
-$objs = ["protobuf.o", "convert.o", "defs.o", "message.o",
-         "repeated_field.o", "map.o", "ruby-upb.o", "wrap_memcpy.o"]
+$VPATH << "$(srcdir)/third_party/utf8_range"
+$INCFLAGS << "$(srcdir)/third_party/utf8_range"
 
-create_makefile("google/protobuf_c")
+$srcs = ["protobuf.c", "convert.c", "defs.c", "message.c",
+         "repeated_field.c", "map.c", "ruby-upb.c", "wrap_memcpy.c",
+         "utf8_range.c"]
+
+create_makefile(ext_name)
diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c
index d5b47e4..5d30319 100644
--- a/ruby/ext/google/protobuf_c/map.c
+++ b/ruby/ext/google/protobuf_c/map.c
@@ -34,7 +34,7 @@
 #include "protobuf.h"
 
 // -----------------------------------------------------------------------------
-// Basic map operations on top of upb_map.
+// Basic map operations on top of upb_Map.
 //
 // Note that we roll our own `Map` container here because, as for
 // `RepeatedField`, we want a strongly-typed container. This is so that any user
@@ -48,8 +48,8 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_map *map;  // Can convert to mutable when non-frozen.
-  upb_fieldtype_t key_type;
+  const upb_Map* map;  // Can convert to mutable when non-frozen.
+  upb_CType key_type;
   TypeInfo value_type_info;
   VALUE value_type_class;
   VALUE arena;
@@ -62,9 +62,9 @@
 }
 
 const rb_data_type_t Map_type = {
-  "Google::Protobuf::Map",
-  { Map_mark, RUBY_DEFAULT_FREE, NULL },
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::Map",
+    {Map_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 VALUE cMap;
@@ -84,8 +84,8 @@
   return TypedData_Wrap_Struct(klass, &Map_type, self);
 }
 
-VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
-                         TypeInfo value_type, VALUE arena) {
+VALUE Map_GetRubyWrapper(upb_Map* map, upb_CType key_type, TypeInfo value_type,
+                         VALUE arena) {
   PBRUBY_ASSERT(map);
 
   VALUE val = ObjectCache_Get(map);
@@ -99,8 +99,8 @@
     self->arena = arena;
     self->key_type = key_type;
     self->value_type_info = value_type;
-    if (self->value_type_info.type == UPB_TYPE_MESSAGE) {
-      const upb_msgdef *val_m = self->value_type_info.def.msgdef;
+    if (self->value_type_info.type == kUpb_CType_Message) {
+      const upb_MessageDef* val_m = self->value_type_info.def.msgdef;
       self->value_type_class = Descriptor_DefToClass(val_m);
     }
   }
@@ -108,9 +108,9 @@
   return val;
 }
 
-static VALUE Map_new_this_type(Map *from) {
+static VALUE Map_new_this_type(Map* from) {
   VALUE arena_rb = Arena_new();
-  upb_map* map = upb_map_new(Arena_get(arena_rb), from->key_type,
+  upb_Map* map = upb_Map_New(Arena_get(arena_rb), from->key_type,
                              from->value_type_info.type);
   VALUE ret =
       Map_GetRubyWrapper(map, from->key_type, from->value_type_info, arena_rb);
@@ -125,22 +125,22 @@
   return ret;
 }
 
-static upb_map *Map_GetMutable(VALUE _self) {
+static upb_Map* Map_GetMutable(VALUE _self) {
   rb_check_frozen(_self);
-  return (upb_map*)ruby_to_Map(_self)->map;
+  return (upb_Map*)ruby_to_Map(_self)->map;
 }
 
-VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
+VALUE Map_CreateHash(const upb_Map* map, upb_CType key_type,
                      TypeInfo val_info) {
   VALUE hash = rb_hash_new();
-  size_t iter = UPB_MAP_BEGIN;
+  size_t iter = kUpb_Map_Begin;
   TypeInfo key_info = TypeInfo_from_type(key_type);
 
   if (!map) return hash;
 
-  while (upb_mapiter_next(map, &iter)) {
-    upb_msgval key = upb_mapiter_key(map, iter);
-    upb_msgval val = upb_mapiter_value(map, iter);
+  while (upb_MapIterator_Next(map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(map, iter);
     VALUE key_val = Convert_UpbToRuby(key, key_info, Qnil);
     VALUE val_val = Scalar_CreateHash(val, val_info);
     rb_hash_aset(hash, key_val, val_val);
@@ -152,25 +152,26 @@
 VALUE Map_deep_copy(VALUE obj) {
   Map* self = ruby_to_Map(obj);
   VALUE new_arena_rb = Arena_new();
-  upb_arena *arena = Arena_get(new_arena_rb);
-  upb_map* new_map =
-      upb_map_new(arena, self->key_type, self->value_type_info.type);
-  size_t iter = UPB_MAP_BEGIN;
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
-    upb_msgval val = upb_mapiter_value(self->map, iter);
-    upb_msgval val_copy = Msgval_DeepCopy(val, self->value_type_info, arena);
-    upb_map_set(new_map, key, val_copy, arena);
+  upb_Arena* arena = Arena_get(new_arena_rb);
+  upb_Map* new_map =
+      upb_Map_New(arena, self->key_type, self->value_type_info.type);
+  size_t iter = kUpb_Map_Begin;
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
+    upb_MessageValue val_copy =
+        Msgval_DeepCopy(val, self->value_type_info, arena);
+    upb_Map_Set(new_map, key, val_copy, arena);
   }
 
   return Map_GetRubyWrapper(new_map, self->key_type, self->value_type_info,
                             new_arena_rb);
 }
 
-const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
-                             upb_arena* arena) {
-  const upb_fielddef* key_field = map_field_key(field);
-  const upb_fielddef* value_field = map_field_value(field);
+const upb_Map* Map_GetUpbMap(VALUE val, const upb_FieldDef* field,
+                             upb_Arena* arena) {
+  const upb_FieldDef* key_field = map_field_key(field);
+  const upb_FieldDef* value_field = map_field_value(field);
   TypeInfo value_type_info = TypeInfo_get(value_field);
   Map* self;
 
@@ -180,7 +181,7 @@
   }
 
   self = ruby_to_Map(val);
-  if (self->key_type != upb_fielddef_type(key_field)) {
+  if (self->key_type != upb_FieldDef_CType(key_field)) {
     rb_raise(cTypeError, "Map key type does not match field's key type");
   }
   if (self->value_type_info.type != value_type_info.type) {
@@ -194,16 +195,16 @@
   return self->map;
 }
 
-void Map_Inspect(StringBuilder* b, const upb_map* map, upb_fieldtype_t key_type,
+void Map_Inspect(StringBuilder* b, const upb_Map* map, upb_CType key_type,
                  TypeInfo val_type) {
   bool first = true;
   TypeInfo key_type_info = {key_type};
   StringBuilder_Printf(b, "{");
   if (map) {
-    size_t iter = UPB_MAP_BEGIN;
-    while (upb_mapiter_next(map, &iter)) {
-      upb_msgval key = upb_mapiter_key(map, iter);
-      upb_msgval val = upb_mapiter_value(map, iter);
+    size_t iter = kUpb_Map_Begin;
+    while (upb_MapIterator_Next(map, &iter)) {
+      upb_MessageValue key = upb_MapIterator_Key(map, iter);
+      upb_MessageValue val = upb_MapIterator_Value(map, iter);
       if (first) {
         first = false;
       } else {
@@ -219,10 +220,12 @@
 
 static int merge_into_self_callback(VALUE key, VALUE val, VALUE _self) {
   Map* self = ruby_to_Map(_self);
-  upb_arena *arena = Arena_get(self->arena);
-  upb_msgval key_val = Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
-  upb_msgval val_val = Convert_RubyToUpb(val, "", self->value_type_info, arena);
-  upb_map_set(Map_GetMutable(_self), key_val, val_val, arena);
+  upb_Arena* arena = Arena_get(self->arena);
+  upb_MessageValue key_val =
+      Convert_RubyToUpb(key, "", Map_keyinfo(self), arena);
+  upb_MessageValue val_val =
+      Convert_RubyToUpb(val, "", self->value_type_info, arena);
+  upb_Map_Set(Map_GetMutable(_self), key_val, val_val, arena);
   return ST_CONTINUE;
 }
 
@@ -234,9 +237,9 @@
              RTYPEDDATA_TYPE(hashmap) == &Map_type) {
     Map* self = ruby_to_Map(_self);
     Map* other = ruby_to_Map(hashmap);
-    upb_arena *arena = Arena_get(self->arena);
-    upb_msg *self_msg = Map_GetMutable(_self);
-    size_t iter = UPB_MAP_BEGIN;
+    upb_Arena* arena = Arena_get(self->arena);
+    upb_Message* self_msg = Map_GetMutable(_self);
+    size_t iter = kUpb_Map_Begin;
 
     Arena_fuse(other->arena, arena);
 
@@ -246,10 +249,10 @@
       rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types");
     }
 
-    while (upb_mapiter_next(other->map, &iter)) {
-      upb_msgval key = upb_mapiter_key(other->map, iter);
-      upb_msgval val = upb_mapiter_value(other->map, iter);
-      upb_map_set(self_msg, key, val, arena);
+    while (upb_MapIterator_Next(other->map, &iter)) {
+      upb_MessageValue key = upb_MapIterator_Key(other->map, iter);
+      upb_MessageValue val = upb_MapIterator_Value(other->map, iter);
+      upb_Map_Set(self_msg, key, val, arena);
     }
   } else {
     rb_raise(rb_eArgError, "Unknown type merging into Map");
@@ -305,20 +308,20 @@
 
   // Check that the key type is an allowed type.
   switch (self->key_type) {
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_UINT64:
-    case UPB_TYPE_BOOL:
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_Int32:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_UInt64:
+    case kUpb_CType_Bool:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       // These are OK.
       break;
     default:
       rb_raise(rb_eArgError, "Invalid key type for map.");
   }
 
-  self->map = upb_map_new(Arena_get(self->arena), self->key_type,
+  self->map = upb_Map_New(Arena_get(self->arena), self->key_type,
                           self->value_type_info.type);
   ObjectCache_Add(self->map, _self);
 
@@ -339,11 +342,11 @@
  */
 static VALUE Map_each(VALUE _self) {
   Map* self = ruby_to_Map(_self);
-  size_t iter = UPB_MAP_BEGIN;
+  size_t iter = kUpb_Map_Begin;
 
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
-    upb_msgval val = upb_mapiter_value(self->map, iter);
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
     VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
     VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
     rb_yield_values(2, key_val, val_val);
@@ -360,11 +363,11 @@
  */
 static VALUE Map_keys(VALUE _self) {
   Map* self = ruby_to_Map(_self);
-  size_t iter = UPB_MAP_BEGIN;
+  size_t iter = kUpb_Map_Begin;
   VALUE ret = rb_ary_new();
 
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
     VALUE key_val = Convert_UpbToRuby(key, Map_keyinfo(self), self->arena);
     rb_ary_push(ret, key_val);
   }
@@ -380,11 +383,11 @@
  */
 static VALUE Map_values(VALUE _self) {
   Map* self = ruby_to_Map(_self);
-  size_t iter = UPB_MAP_BEGIN;
+  size_t iter = kUpb_Map_Begin;
   VALUE ret = rb_ary_new();
 
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval val = upb_mapiter_value(self->map, iter);
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
     VALUE val_val = Convert_UpbToRuby(val, self->value_type_info, self->arena);
     rb_ary_push(ret, val_val);
   }
@@ -401,10 +404,11 @@
  */
 static VALUE Map_index(VALUE _self, VALUE key) {
   Map* self = ruby_to_Map(_self);
-  upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
-  upb_msgval val;
+  upb_MessageValue key_upb =
+      Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+  upb_MessageValue val;
 
-  if (upb_map_get(self->map, key_upb, &val)) {
+  if (upb_Map_Get(self->map, key_upb, &val)) {
     return Convert_UpbToRuby(val, self->value_type_info, self->arena);
   } else {
     return Qnil;
@@ -421,11 +425,13 @@
  */
 static VALUE Map_index_set(VALUE _self, VALUE key, VALUE val) {
   Map* self = ruby_to_Map(_self);
-  upb_arena *arena = Arena_get(self->arena);
-  upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
-  upb_msgval val_upb = Convert_RubyToUpb(val, "", self->value_type_info, arena);
+  upb_Arena* arena = Arena_get(self->arena);
+  upb_MessageValue key_upb =
+      Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+  upb_MessageValue val_upb =
+      Convert_RubyToUpb(val, "", self->value_type_info, arena);
 
-  upb_map_set(Map_GetMutable(_self), key_upb, val_upb, arena);
+  upb_Map_Set(Map_GetMutable(_self), key_upb, val_upb, arena);
 
   return val;
 }
@@ -439,9 +445,10 @@
  */
 static VALUE Map_has_key(VALUE _self, VALUE key) {
   Map* self = ruby_to_Map(_self);
-  upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+  upb_MessageValue key_upb =
+      Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
 
-  if (upb_map_get(self->map, key_upb, NULL)) {
+  if (upb_Map_Get(self->map, key_upb, NULL)) {
     return Qtrue;
   } else {
     return Qfalse;
@@ -457,21 +464,22 @@
  */
 static VALUE Map_delete(VALUE _self, VALUE key) {
   Map* self = ruby_to_Map(_self);
-  upb_msgval key_upb = Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
-  upb_msgval val_upb;
+  upb_MessageValue key_upb =
+      Convert_RubyToUpb(key, "", Map_keyinfo(self), NULL);
+  upb_MessageValue val_upb;
   VALUE ret;
 
   rb_check_frozen(_self);
 
-  // TODO(haberman): make upb_map_delete() also capable of returning the deleted
+  // TODO(haberman): make upb_Map_Delete() also capable of returning the deleted
   // value.
-  if (upb_map_get(self->map, key_upb, &val_upb)) {
+  if (upb_Map_Get(self->map, key_upb, &val_upb)) {
     ret = Convert_UpbToRuby(val_upb, self->value_type_info, self->arena);
   } else {
     ret = Qnil;
   }
 
-  upb_map_delete(Map_GetMutable(_self), key_upb);
+  upb_Map_Delete(Map_GetMutable(_self), key_upb);
 
   return ret;
 }
@@ -483,7 +491,7 @@
  * Removes all entries from the map.
  */
 static VALUE Map_clear(VALUE _self) {
-  upb_map_clear(Map_GetMutable(_self));
+  upb_Map_Clear(Map_GetMutable(_self));
   return Qnil;
 }
 
@@ -495,7 +503,7 @@
  */
 static VALUE Map_length(VALUE _self) {
   Map* self = ruby_to_Map(_self);
-  return ULL2NUM(upb_map_size(self->map));
+  return ULL2NUM(upb_Map_Size(self->map));
 }
 
 /*
@@ -509,16 +517,16 @@
   Map* self = ruby_to_Map(_self);
   VALUE new_map_rb = Map_new_this_type(self);
   Map* new_self = ruby_to_Map(new_map_rb);
-  size_t iter = UPB_MAP_BEGIN;
-  upb_arena *arena = Arena_get(new_self->arena);
-  upb_map *new_map = Map_GetMutable(new_map_rb);
+  size_t iter = kUpb_Map_Begin;
+  upb_Arena* arena = Arena_get(new_self->arena);
+  upb_Map* new_map = Map_GetMutable(new_map_rb);
 
   Arena_fuse(self->arena, arena);
 
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
-    upb_msgval val = upb_mapiter_value(self->map, iter);
-    upb_map_set(new_map, key, val, arena);
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
+    upb_Map_Set(new_map, key, val, arena);
   }
 
   return new_map_rb;
@@ -559,18 +567,18 @@
       self->value_type_class != other->value_type_class) {
     return Qfalse;
   }
-  if (upb_map_size(self->map) != upb_map_size(other->map)) {
+  if (upb_Map_Size(self->map) != upb_Map_Size(other->map)) {
     return Qfalse;
   }
 
   // For each member of self, check that an equal member exists at the same key
   // in other.
-  size_t iter = UPB_MAP_BEGIN;
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
-    upb_msgval val = upb_mapiter_value(self->map, iter);
-    upb_msgval other_val;
-    if (!upb_map_get(other->map, key, &other_val)) {
+  size_t iter = kUpb_Map_Begin;
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
+    upb_MessageValue other_val;
+    if (!upb_Map_Get(other->map, key, &other_val)) {
       // Not present in other map.
       return Qfalse;
     }
@@ -609,11 +617,11 @@
   Map* self = ruby_to_Map(_self);
   uint64_t hash = 0;
 
-  size_t iter = UPB_MAP_BEGIN;
+  size_t iter = kUpb_Map_Begin;
   TypeInfo key_info = {self->key_type};
-  while (upb_mapiter_next(self->map, &iter)) {
-    upb_msgval key = upb_mapiter_key(self->map, iter);
-    upb_msgval val = upb_mapiter_value(self->map, iter);
+  while (upb_MapIterator_Next(self->map, &iter)) {
+    upb_MessageValue key = upb_MapIterator_Key(self->map, iter);
+    upb_MessageValue val = upb_MapIterator_Value(self->map, iter);
     hash = Msgval_GetHash(key, key_info, hash);
     hash = Msgval_GetHash(val, self->value_type_info, hash);
   }
@@ -680,7 +688,10 @@
   rb_define_method(klass, "delete", Map_delete, 1);
   rb_define_method(klass, "clear", Map_clear, 0);
   rb_define_method(klass, "length", Map_length, 0);
+  rb_define_method(klass, "size", Map_length, 0);
   rb_define_method(klass, "dup", Map_dup, 0);
+  // Also define #clone so that we don't inherit Object#clone.
+  rb_define_method(klass, "clone", Map_dup, 0);
   rb_define_method(klass, "==", Map_eq, 1);
   rb_define_method(klass, "freeze", Map_freeze, 0);
   rb_define_method(klass, "hash", Map_hash, 0);
diff --git a/ruby/ext/google/protobuf_c/map.h b/ruby/ext/google/protobuf_c/map.h
index 411362c..7b4a151 100644
--- a/ruby/ext/google/protobuf_c/map.h
+++ b/ruby/ext/google/protobuf_c/map.h
@@ -38,22 +38,21 @@
 
 // Returns a Ruby wrapper object for the given map, which will be created if
 // one does not exist already.
-VALUE Map_GetRubyWrapper(upb_map *map, upb_fieldtype_t key_type,
-                         TypeInfo value_type, VALUE arena);
+VALUE Map_GetRubyWrapper(upb_Map *map, upb_CType key_type, TypeInfo value_type,
+                         VALUE arena);
 
-// Gets the underlying upb_map for this Ruby map object, which must have
+// Gets the underlying upb_Map for this Ruby map object, which must have
 // key/value type that match |field|. If this is not a map or the type doesn't
 // match, raises an exception.
-const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field,
-                             upb_arena *arena);
+const upb_Map *Map_GetUpbMap(VALUE val, const upb_FieldDef *field,
+                             upb_Arena *arena);
 
 // Implements #inspect for this map by appending its contents to |b|.
-void Map_Inspect(StringBuilder *b, const upb_map *map, upb_fieldtype_t key_type,
+void Map_Inspect(StringBuilder *b, const upb_Map *map, upb_CType key_type,
                  TypeInfo val_type);
 
 // Returns a new Hash object containing the contents of this Map.
-VALUE Map_CreateHash(const upb_map* map, upb_fieldtype_t key_type,
-                     TypeInfo val_info);
+VALUE Map_CreateHash(const upb_Map *map, upb_CType key_type, TypeInfo val_info);
 
 // Returns a deep copy of this Map object.
 VALUE Map_deep_copy(VALUE obj);
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index 59602cf..7feee75 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -40,7 +40,7 @@
 static ID descriptor_instancevar_interned;
 
 static VALUE initialize_rb_class_with_no_args(VALUE klass) {
-    return rb_funcall(klass, rb_intern("new"), 0);
+  return rb_funcall(klass, rb_intern("new"), 0);
 }
 
 VALUE MessageOrEnum_GetDescriptor(VALUE klass) {
@@ -53,19 +53,20 @@
 
 typedef struct {
   VALUE arena;
-  const upb_msg* msg;        // Can get as mutable when non-frozen.
-  const upb_msgdef* msgdef;  // kept alive by self.class.descriptor reference.
+  const upb_Message* msg;  // Can get as mutable when non-frozen.
+  const upb_MessageDef*
+      msgdef;  // kept alive by self.class.descriptor reference.
 } Message;
 
 static void Message_mark(void* _self) {
-  Message* self = (Message *)_self;
+  Message* self = (Message*)_self;
   rb_gc_mark(self->arena);
 }
 
 static rb_data_type_t Message_type = {
-  "Message",
-  { Message_mark, RUBY_DEFAULT_FREE, NULL },
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Message",
+    {Message_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static Message* ruby_to_Message(VALUE msg_rb) {
@@ -89,18 +90,18 @@
   return ret;
 }
 
-const upb_msg *Message_Get(VALUE msg_rb, const upb_msgdef **m) {
+const upb_Message* Message_Get(VALUE msg_rb, const upb_MessageDef** m) {
   Message* msg = ruby_to_Message(msg_rb);
   if (m) *m = msg->msgdef;
   return msg->msg;
 }
 
-upb_msg *Message_GetMutable(VALUE msg_rb, const upb_msgdef **m) {
+upb_Message* Message_GetMutable(VALUE msg_rb, const upb_MessageDef** m) {
   rb_check_frozen(msg_rb);
-  return (upb_msg*)Message_Get(msg_rb, m);
+  return (upb_Message*)Message_Get(msg_rb, m);
 }
 
-void Message_InitPtr(VALUE self_, upb_msg *msg, VALUE arena) {
+void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
   Message* self = ruby_to_Message(self_);
   self->msg = msg;
   self->arena = arena;
@@ -119,7 +120,8 @@
   }
 }
 
-VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena) {
+VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
+                             VALUE arena) {
   if (msg == NULL) return Qnil;
 
   VALUE val = ObjectCache_Get(msg);
@@ -133,17 +135,17 @@
   return val;
 }
 
-void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
-                          const upb_msgdef* m) {
+void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
+                          const upb_MessageDef* m) {
   bool first = true;
-  int n = upb_msgdef_fieldcount(m);
+  int n = upb_MessageDef_FieldCount(m);
   VALUE klass = Descriptor_DefToClass(m);
   StringBuilder_Printf(b, "<%s: ", rb_class2name(klass));
 
   for (int i = 0; i < n; i++) {
-    const upb_fielddef* field = upb_msgdef_field(m, i);
+    const upb_FieldDef* field = upb_MessageDef_Field(m, i);
 
-    if (upb_fielddef_haspresence(field) && !upb_msg_has(msg, field)) {
+    if (upb_FieldDef_HasPresence(field) && !upb_Message_Has(msg, field)) {
       continue;
     }
 
@@ -153,17 +155,19 @@
       first = false;
     }
 
-    upb_msgval msgval = upb_msg_get(msg, field);
+    upb_MessageValue msgval = upb_Message_Get(msg, field);
 
-    StringBuilder_Printf(b, "%s: ", upb_fielddef_name(field));
+    StringBuilder_Printf(b, "%s: ", upb_FieldDef_Name(field));
 
-    if (upb_fielddef_ismap(field)) {
-      const upb_msgdef* entry_m = upb_fielddef_msgsubdef(field);
-      const upb_fielddef* key_f = upb_msgdef_itof(entry_m, 1);
-      const upb_fielddef* val_f = upb_msgdef_itof(entry_m, 2);
+    if (upb_FieldDef_IsMap(field)) {
+      const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
+      const upb_FieldDef* key_f =
+          upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1);
+      const upb_FieldDef* val_f =
+          upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2);
       TypeInfo val_info = TypeInfo_get(val_f);
-      Map_Inspect(b, msgval.map_val, upb_fielddef_type(key_f), val_info);
-    } else if (upb_fielddef_isseq(field)) {
+      Map_Inspect(b, msgval.map_val, upb_FieldDef_CType(key_f), val_info);
+    } else if (upb_FieldDef_IsRepeated(field)) {
       RepeatedField_Inspect(b, msgval.array_val, TypeInfo_get(field));
     } else {
       StringBuilder_PrintMsgval(b, msgval, TypeInfo_get(field));
@@ -187,14 +191,31 @@
 };
 
 // Check if the field is a well known wrapper type
-static bool IsWrapper(const upb_fielddef* f) {
-  return upb_fielddef_issubmsg(f) &&
-         upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f));
+static bool IsWrapper(const upb_MessageDef* m) {
+  if (!m) return false;
+  switch (upb_MessageDef_WellKnownType(m)) {
+    case kUpb_WellKnown_DoubleValue:
+    case kUpb_WellKnown_FloatValue:
+    case kUpb_WellKnown_Int64Value:
+    case kUpb_WellKnown_UInt64Value:
+    case kUpb_WellKnown_Int32Value:
+    case kUpb_WellKnown_UInt32Value:
+    case kUpb_WellKnown_StringValue:
+    case kUpb_WellKnown_BytesValue:
+    case kUpb_WellKnown_BoolValue:
+      return true;
+    default:
+      return false;
+  }
 }
 
-static bool Match(const upb_msgdef* m, const char* name, const upb_fielddef** f,
-                  const upb_oneofdef** o, const char* prefix,
-                  const char* suffix) {
+static bool IsFieldWrapper(const upb_FieldDef* f) {
+  return IsWrapper(upb_FieldDef_MessageSubDef(f));
+}
+
+static bool Match(const upb_MessageDef* m, const char* name,
+                  const upb_FieldDef** f, const upb_OneofDef** o,
+                  const char* prefix, const char* suffix) {
   size_t sp = strlen(prefix);
   size_t ss = strlen(suffix);
   size_t sn = strlen(name);
@@ -206,12 +227,12 @@
     return false;
   }
 
-  return upb_msgdef_lookupname(m, name + sp, sn - sp - ss, f, o);
+  return upb_MessageDef_FindByNameWithSize(m, name + sp, sn - sp - ss, f, o);
 }
 
 static int extract_method_call(VALUE method_name, Message* self,
-                               const upb_fielddef** f, const upb_oneofdef** o) {
-  const upb_msgdef* m = self->msgdef;
+                               const upb_FieldDef** f, const upb_OneofDef** o) {
+  const upb_MessageDef* m = self->msgdef;
   const char* name;
 
   Check_Type(method_name, T_SYMBOL);
@@ -221,156 +242,159 @@
   if (Match(m, name, f, o, "", "=")) return METHOD_SETTER;
   if (Match(m, name, f, o, "clear_", "")) return METHOD_CLEAR;
   if (Match(m, name, f, o, "has_", "?") &&
-      (*o || (*f && upb_fielddef_haspresence(*f)))) {
+      (*o || (*f && upb_FieldDef_HasPresence(*f)))) {
     // Disallow oneof hazzers for proto3.
     // TODO(haberman): remove this test when we are enabling oneof hazzers for
     // proto3.
-    if (*f && !upb_fielddef_issubmsg(*f) &&
-        upb_fielddef_realcontainingoneof(*f) &&
-        upb_msgdef_syntax(upb_fielddef_containingtype(*f)) !=
-            UPB_SYNTAX_PROTO2) {
+    if (*f && !upb_FieldDef_IsSubMessage(*f) &&
+        upb_FieldDef_RealContainingOneof(*f) &&
+        upb_MessageDef_Syntax(upb_FieldDef_ContainingType(*f)) !=
+            kUpb_Syntax_Proto2) {
       return METHOD_UNKNOWN;
     }
     return METHOD_PRESENCE;
   }
-  if (Match(m, name, f, o, "", "_as_value") && *f && !upb_fielddef_isseq(*f) &&
-      IsWrapper(*f)) {
+  if (Match(m, name, f, o, "", "_as_value") && *f &&
+      !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
     return METHOD_WRAPPER_GETTER;
   }
-  if (Match(m, name, f, o, "", "_as_value=") && *f && !upb_fielddef_isseq(*f) &&
-      IsWrapper(*f)) {
+  if (Match(m, name, f, o, "", "_as_value=") && *f &&
+      !upb_FieldDef_IsRepeated(*f) && IsFieldWrapper(*f)) {
     return METHOD_WRAPPER_SETTER;
   }
   if (Match(m, name, f, o, "", "_const") && *f &&
-      upb_fielddef_type(*f) == UPB_TYPE_ENUM) {
+      upb_FieldDef_CType(*f) == kUpb_CType_Enum) {
     return METHOD_ENUM_GETTER;
   }
 
   return METHOD_UNKNOWN;
 }
 
-static VALUE Message_oneof_accessor(VALUE _self, const upb_oneofdef* o,
+static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o,
                                     int accessor_type) {
   Message* self = ruby_to_Message(_self);
-  const upb_fielddef* oneof_field = upb_msg_whichoneof(self->msg, o);
+  const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o);
 
   switch (accessor_type) {
     case METHOD_PRESENCE:
       return oneof_field == NULL ? Qfalse : Qtrue;
     case METHOD_CLEAR:
       if (oneof_field != NULL) {
-        upb_msg_clearfield(Message_GetMutable(_self, NULL), oneof_field);
+        upb_Message_ClearField(Message_GetMutable(_self, NULL), oneof_field);
       }
       return Qnil;
     case METHOD_GETTER:
       return oneof_field == NULL
                  ? Qnil
-                 : ID2SYM(rb_intern(upb_fielddef_name(oneof_field)));
+                 : ID2SYM(rb_intern(upb_FieldDef_Name(oneof_field)));
     case METHOD_SETTER:
       rb_raise(rb_eRuntimeError, "Oneof accessors are read-only.");
   }
   rb_raise(rb_eRuntimeError, "Invalid access of oneof field.");
 }
 
-static void Message_setfield(upb_msg* msg, const upb_fielddef* f, VALUE val,
-                             upb_arena* arena) {
-  upb_msgval msgval;
-  if (upb_fielddef_ismap(f)) {
+static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
+                             upb_Arena* arena) {
+  upb_MessageValue msgval;
+  if (upb_FieldDef_IsMap(f)) {
     msgval.map_val = Map_GetUpbMap(val, f, arena);
-  } else if (upb_fielddef_isseq(f)) {
+  } else if (upb_FieldDef_IsRepeated(f)) {
     msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
   } else {
     if (val == Qnil &&
-        (upb_fielddef_issubmsg(f) || upb_fielddef_realcontainingoneof(f))) {
-      upb_msg_clearfield(msg, f);
+        (upb_FieldDef_IsSubMessage(f) || upb_FieldDef_RealContainingOneof(f))) {
+      upb_Message_ClearField(msg, f);
       return;
     }
     msgval =
-        Convert_RubyToUpb(val, upb_fielddef_name(f), TypeInfo_get(f), arena);
+        Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
   }
-  upb_msg_set(msg, f, msgval, arena);
+  upb_Message_Set(msg, f, msgval, arena);
 }
 
-VALUE Message_getfield(VALUE _self, const upb_fielddef* f) {
+VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
   Message* self = ruby_to_Message(_self);
-  // This is a special-case: upb_msg_mutable() for map & array are logically
+  // This is a special-case: upb_Message_Mutable() for map & array are logically
   // const (they will not change what is serialized) but physically
   // non-const, as they do allocate a repeated field or map. The logical
   // constness means it's ok to do even if the message is frozen.
-  upb_msg *msg = (upb_msg*)self->msg;
-  upb_arena *arena = Arena_get(self->arena);
-  if (upb_fielddef_ismap(f)) {
-    upb_map *map = upb_msg_mutable(msg, f, arena).map;
-    const upb_fielddef *key_f = map_field_key(f);
-    const upb_fielddef *val_f = map_field_value(f);
-    upb_fieldtype_t key_type = upb_fielddef_type(key_f);
+  upb_Message* msg = (upb_Message*)self->msg;
+  upb_Arena* arena = Arena_get(self->arena);
+  if (upb_FieldDef_IsMap(f)) {
+    upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
+    const upb_FieldDef* key_f = map_field_key(f);
+    const upb_FieldDef* val_f = map_field_value(f);
+    upb_CType key_type = upb_FieldDef_CType(key_f);
     TypeInfo value_type_info = TypeInfo_get(val_f);
     return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
-  } else if (upb_fielddef_isseq(f)) {
-    upb_array *arr = upb_msg_mutable(msg, f, arena).array;
+  } else if (upb_FieldDef_IsRepeated(f)) {
+    upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
     return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
-  } else if (upb_fielddef_issubmsg(f)) {
-    if (!upb_msg_has(self->msg, f)) return Qnil;
-    upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
-    const upb_msgdef *m = upb_fielddef_msgsubdef(f);
+  } else if (upb_FieldDef_IsSubMessage(f)) {
+    if (!upb_Message_Has(self->msg, f)) return Qnil;
+    upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
+    const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
     return Message_GetRubyWrapper(submsg, m, self->arena);
   } else {
-    upb_msgval msgval = upb_msg_get(self->msg, f);
+    upb_MessageValue msgval = upb_Message_Get(self->msg, f);
     return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
   }
 }
 
-static VALUE Message_field_accessor(VALUE _self, const upb_fielddef* f,
+static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
                                     int accessor_type, int argc, VALUE* argv) {
-  upb_arena *arena = Arena_get(Message_GetArena(_self));
+  upb_Arena* arena = Arena_get(Message_GetArena(_self));
 
   switch (accessor_type) {
     case METHOD_SETTER:
       Message_setfield(Message_GetMutable(_self, NULL), f, argv[1], arena);
       return Qnil;
     case METHOD_CLEAR:
-      upb_msg_clearfield(Message_GetMutable(_self, NULL), f);
+      upb_Message_ClearField(Message_GetMutable(_self, NULL), f);
       return Qnil;
     case METHOD_PRESENCE:
-      if (!upb_fielddef_haspresence(f)) {
+      if (!upb_FieldDef_HasPresence(f)) {
         rb_raise(rb_eRuntimeError, "Field does not have presence.");
       }
-      return upb_msg_has(Message_Get(_self, NULL), f);
+      return upb_Message_Has(Message_Get(_self, NULL), f);
     case METHOD_WRAPPER_GETTER: {
       Message* self = ruby_to_Message(_self);
-      if (upb_msg_has(self->msg, f)) {
-        PBRUBY_ASSERT(upb_fielddef_issubmsg(f) && !upb_fielddef_isseq(f));
-        upb_msgval wrapper = upb_msg_get(self->msg, f);
-        const upb_msgdef *wrapper_m = upb_fielddef_msgsubdef(f);
-        const upb_fielddef *value_f = upb_msgdef_itof(wrapper_m, 1);
-        upb_msgval value = upb_msg_get(wrapper.msg_val, value_f);
+      if (upb_Message_Has(self->msg, f)) {
+        PBRUBY_ASSERT(upb_FieldDef_IsSubMessage(f) &&
+                      !upb_FieldDef_IsRepeated(f));
+        upb_MessageValue wrapper = upb_Message_Get(self->msg, f);
+        const upb_MessageDef* wrapper_m = upb_FieldDef_MessageSubDef(f);
+        const upb_FieldDef* value_f =
+            upb_MessageDef_FindFieldByNumberWithSize(wrapper_m, 1);
+        upb_MessageValue value = upb_Message_Get(wrapper.msg_val, value_f);
         return Convert_UpbToRuby(value, TypeInfo_get(value_f), self->arena);
       } else {
         return Qnil;
       }
     }
     case METHOD_WRAPPER_SETTER: {
-      upb_msg *msg = Message_GetMutable(_self, NULL);
+      upb_Message* msg = Message_GetMutable(_self, NULL);
       if (argv[1] == Qnil) {
-        upb_msg_clearfield(msg, f);
+        upb_Message_ClearField(msg, f);
       } else {
-        const upb_fielddef *val_f = upb_msgdef_itof(upb_fielddef_msgsubdef(f), 1);
-        upb_msgval msgval = Convert_RubyToUpb(argv[1], upb_fielddef_name(f),
-                                              TypeInfo_get(val_f), arena);
-        upb_msg *wrapper = upb_msg_mutable(msg, f, arena).msg;
-        upb_msg_set(wrapper, val_f, msgval, arena);
+        const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumberWithSize(
+            upb_FieldDef_MessageSubDef(f), 1);
+        upb_MessageValue msgval = Convert_RubyToUpb(
+            argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
+        upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
+        upb_Message_Set(wrapper, val_f, msgval, arena);
       }
       return Qnil;
     }
     case METHOD_ENUM_GETTER: {
-      upb_msgval msgval = upb_msg_get(Message_Get(_self, NULL), f);
+      upb_MessageValue msgval = upb_Message_Get(Message_Get(_self, NULL), f);
 
-      if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
+      if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
         // Map repeated fields to a new type with ints
         VALUE arr = rb_ary_new();
-        size_t i, n = upb_array_size(msgval.array_val);
+        size_t i, n = upb_Array_Size(msgval.array_val);
         for (i = 0; i < n; i++) {
-          upb_msgval elem = upb_array_get(msgval.array_val, i);
+          upb_MessageValue elem = upb_Array_Get(msgval.array_val, i);
           rb_ary_push(arr, INT2NUM(elem.int32_val));
         }
         return arr;
@@ -415,8 +439,8 @@
  */
 static VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
   Message* self = ruby_to_Message(_self);
-  const upb_oneofdef* o;
-  const upb_fielddef* f;
+  const upb_OneofDef* o;
+  const upb_FieldDef* f;
   int accessor_type;
 
   if (argc < 1) {
@@ -453,8 +477,8 @@
 
 static VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
   Message* self = ruby_to_Message(_self);
-  const upb_oneofdef* o;
-  const upb_fielddef* f;
+  const upb_OneofDef* o;
+  const upb_FieldDef* f;
   int accessor_type;
 
   if (argc < 1) {
@@ -472,53 +496,56 @@
   }
 }
 
-void Message_InitFromValue(upb_msg* msg, const upb_msgdef* m, VALUE val,
-                           upb_arena* arena);
+void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
+                           upb_Arena* arena);
 
 typedef struct {
-  upb_map *map;
+  upb_Map* map;
   TypeInfo key_type;
   TypeInfo val_type;
-  upb_arena *arena;
+  upb_Arena* arena;
 } MapInit;
 
 static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
-  MapInit *map_init = (MapInit*)_self;
-  upb_msgval k, v;
+  MapInit* map_init = (MapInit*)_self;
+  upb_MessageValue k, v;
   k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
 
-  if (map_init->val_type.type == UPB_TYPE_MESSAGE && TYPE(val) == T_HASH) {
-    upb_msg *msg = upb_msg_new(map_init->val_type.def.msgdef, map_init->arena);
+  if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
+    upb_Message* msg =
+        upb_Message_New(map_init->val_type.def.msgdef, map_init->arena);
     Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
                           map_init->arena);
     v.msg_val = msg;
   } else {
     v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena);
   }
-  upb_map_set(map_init->map, k, v, map_init->arena);
+  upb_Map_Set(map_init->map, k, v, map_init->arena);
   return ST_CONTINUE;
 }
 
-static void Map_InitFromValue(upb_map* map, const upb_fielddef* f, VALUE val,
-                       upb_arena* arena) {
-  const upb_msgdef* entry_m = upb_fielddef_msgsubdef(f);
-  const upb_fielddef* key_f = upb_msgdef_itof(entry_m, 1);
-  const upb_fielddef* val_f = upb_msgdef_itof(entry_m, 2);
+static void Map_InitFromValue(upb_Map* map, const upb_FieldDef* f, VALUE val,
+                              upb_Arena* arena) {
+  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
+  const upb_FieldDef* key_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1);
+  const upb_FieldDef* val_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2);
   if (TYPE(val) != T_HASH) {
     rb_raise(rb_eArgError,
              "Expected Hash object as initializer value for map field '%s' "
              "(given %s).",
-             upb_fielddef_name(f), rb_class2name(CLASS_OF(val)));
+             upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
   }
   MapInit map_init = {map, TypeInfo_get(key_f), TypeInfo_get(val_f), arena};
   rb_hash_foreach(val, Map_initialize_kwarg, (VALUE)&map_init);
 }
 
-static upb_msgval MessageValue_FromValue(VALUE val, TypeInfo info,
-                                         upb_arena* arena) {
-  if (info.type == UPB_TYPE_MESSAGE) {
-    upb_msgval msgval;
-    upb_msg* msg = upb_msg_new(info.def.msgdef, arena);
+static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
+                                               upb_Arena* arena) {
+  if (info.type == kUpb_CType_Message) {
+    upb_MessageValue msgval;
+    upb_Message* msg = upb_Message_New(info.def.msgdef, arena);
     Message_InitFromValue(msg, info.def.msgdef, val, arena);
     msgval.msg_val = msg;
     return msgval;
@@ -527,61 +554,62 @@
   }
 }
 
-static void RepeatedField_InitFromValue(upb_array* arr, const upb_fielddef* f,
-                                        VALUE val, upb_arena* arena) {
+static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f,
+                                        VALUE val, upb_Arena* arena) {
   TypeInfo type_info = TypeInfo_get(f);
 
   if (TYPE(val) != T_ARRAY) {
     rb_raise(rb_eArgError,
-             "Expected array as initializer value for repeated field '%s' (given %s).",
-             upb_fielddef_name(f), rb_class2name(CLASS_OF(val)));
+             "Expected array as initializer value for repeated field '%s' "
+             "(given %s).",
+             upb_FieldDef_Name(f), rb_class2name(CLASS_OF(val)));
   }
 
   for (int i = 0; i < RARRAY_LEN(val); i++) {
     VALUE entry = rb_ary_entry(val, i);
-    upb_msgval msgval;
-    if (upb_fielddef_issubmsg(f) && TYPE(entry) == T_HASH) {
+    upb_MessageValue msgval;
+    if (upb_FieldDef_IsSubMessage(f) && TYPE(entry) == T_HASH) {
       msgval = MessageValue_FromValue(entry, type_info, arena);
     } else {
-      msgval = Convert_RubyToUpb(entry, upb_fielddef_name(f), type_info, arena);
+      msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena);
     }
-    upb_array_append(arr, msgval, arena);
+    upb_Array_Append(arr, msgval, arena);
   }
 }
 
-static void Message_InitFieldFromValue(upb_msg* msg, const upb_fielddef* f,
-                                       VALUE val, upb_arena* arena) {
+static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
+                                       VALUE val, upb_Arena* arena) {
   if (TYPE(val) == T_NIL) return;
 
-  if (upb_fielddef_ismap(f)) {
-    upb_map *map = upb_msg_mutable(msg, f, arena).map;
+  if (upb_FieldDef_IsMap(f)) {
+    upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
     Map_InitFromValue(map, f, val, arena);
-  } else if (upb_fielddef_label(f) == UPB_LABEL_REPEATED) {
-    upb_array *arr = upb_msg_mutable(msg, f, arena).array;
+  } else if (upb_FieldDef_Label(f) == kUpb_Label_Repeated) {
+    upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
     RepeatedField_InitFromValue(arr, f, val, arena);
-  } else if (upb_fielddef_issubmsg(f)) {
+  } else if (upb_FieldDef_IsSubMessage(f)) {
     if (TYPE(val) == T_HASH) {
-      upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
-      Message_InitFromValue(submsg, upb_fielddef_msgsubdef(f), val, arena);
+      upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
+      Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena);
     } else {
       Message_setfield(msg, f, val, arena);
     }
   } else {
-    upb_msgval msgval =
-        Convert_RubyToUpb(val, upb_fielddef_name(f), TypeInfo_get(f), arena);
-    upb_msg_set(msg, f, msgval, arena);
+    upb_MessageValue msgval =
+        Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
+    upb_Message_Set(msg, f, msgval, arena);
   }
 }
 
 typedef struct {
-  upb_msg *msg;
-  const upb_msgdef *msgdef;
-  upb_arena *arena;
+  upb_Message* msg;
+  const upb_MessageDef* msgdef;
+  upb_Arena* arena;
 } MsgInit;
 
 static int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
-  MsgInit *msg_init = (MsgInit*)_self;
-  const char *name;
+  MsgInit* msg_init = (MsgInit*)_self;
+  const char* name;
 
   if (TYPE(key) == T_STRING) {
     name = RSTRING_PTR(key);
@@ -589,10 +617,12 @@
     name = RSTRING_PTR(rb_id2str(SYM2ID(key)));
   } else {
     rb_raise(rb_eArgError,
-             "Expected string or symbols as hash keys when initializing proto from hash.");
+             "Expected string or symbols as hash keys when initializing proto "
+             "from hash.");
   }
 
-  const upb_fielddef* f = upb_msgdef_ntofz(msg_init->msgdef, name);
+  const upb_FieldDef* f =
+      upb_MessageDef_FindFieldByName(msg_init->msgdef, name);
 
   if (f == NULL) {
     rb_raise(rb_eArgError,
@@ -603,8 +633,8 @@
   return ST_CONTINUE;
 }
 
-void Message_InitFromValue(upb_msg* msg, const upb_msgdef* m, VALUE val,
-                           upb_arena* arena) {
+void Message_InitFromValue(upb_Message* msg, const upb_MessageDef* m, VALUE val,
+                           upb_Arena* arena) {
   MsgInit msg_init = {msg, m, arena};
   if (TYPE(val) == T_HASH) {
     rb_hash_foreach(val, Message_initialize_kwarg, (VALUE)&msg_init);
@@ -629,8 +659,8 @@
 static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
   Message* self = ruby_to_Message(_self);
   VALUE arena_rb = Arena_new();
-  upb_arena *arena = Arena_get(arena_rb);
-  upb_msg *msg = upb_msg_new(self->msgdef, arena);
+  upb_Arena* arena = Arena_get(arena_rb);
+  upb_Message* msg = upb_Message_New(self->msgdef, arena);
 
   Message_InitPtr(_self, msg, arena_rb);
 
@@ -640,7 +670,7 @@
   if (argc != 1) {
     rb_raise(rb_eArgError, "Expected 0 or 1 arguments.");
   }
-  Message_InitFromValue((upb_msg*)self->msg, self->msgdef, argv[0], arena);
+  Message_InitFromValue((upb_Message*)self->msg, self->msgdef, argv[0], arena);
   return Qnil;
 }
 
@@ -654,34 +684,35 @@
   Message* self = ruby_to_Message(_self);
   VALUE new_msg = rb_class_new_instance(0, NULL, CLASS_OF(_self));
   Message* new_msg_self = ruby_to_Message(new_msg);
-  size_t size = upb_msgdef_layout(self->msgdef)->size;
+  size_t size = upb_MessageDef_MiniTable(self->msgdef)->size;
 
   // TODO(copy unknown fields?)
   // TODO(use official upb msg copy function)
-  memcpy((upb_msg*)new_msg_self->msg, self->msg, size);
+  memcpy((upb_Message*)new_msg_self->msg, self->msg, size);
   Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
   return new_msg;
 }
 
 // Support function for Message_eq, and also used by other #eq functions.
-bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
+bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
+                   const upb_MessageDef* m) {
   if (m1 == m2) return true;
 
   size_t size1, size2;
-  int encode_opts = UPB_ENCODE_SKIPUNKNOWN | UPB_ENCODE_DETERMINISTIC;
-  upb_arena *arena_tmp = upb_arena_new();
-  const upb_msglayout *layout = upb_msgdef_layout(m);
+  int encode_opts = kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic;
+  upb_Arena* arena_tmp = upb_Arena_New();
+  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
 
   // Compare deterministically serialized payloads with no unknown fields.
-  char *data1 = upb_encode_ex(m1, layout, encode_opts, arena_tmp, &size1);
-  char *data2 = upb_encode_ex(m2, layout, encode_opts, arena_tmp, &size2);
+  char* data1 = upb_Encode(m1, layout, encode_opts, arena_tmp, &size1);
+  char* data2 = upb_Encode(m2, layout, encode_opts, arena_tmp, &size2);
 
   if (data1 && data2) {
     bool ret = (size1 == size2) && (memcmp(data1, data2, size1) == 0);
-    upb_arena_free(arena_tmp);
+    upb_Arena_Free(arena_tmp);
     return ret;
   } else {
-    upb_arena_free(arena_tmp);
+    upb_Arena_Free(arena_tmp);
     rb_raise(cParseError, "Error comparing messages");
   }
 }
@@ -705,22 +736,23 @@
   return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
 }
 
-uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
-  upb_arena *arena = upb_arena_new();
-  const char *data;
+uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
+                      uint64_t seed) {
+  upb_Arena* arena = upb_Arena_New();
+  const char* data;
   size_t size;
 
   // Hash a deterministically serialized payloads with no unknown fields.
-  data = upb_encode_ex(msg, upb_msgdef_layout(m),
-                       UPB_ENCODE_SKIPUNKNOWN | UPB_ENCODE_DETERMINISTIC, arena,
-                       &size);
+  data = upb_Encode(msg, upb_MessageDef_MiniTable(m),
+                    kUpb_Encode_SkipUnknown | kUpb_Encode_Deterministic, arena,
+                    &size);
 
   if (data) {
     uint64_t ret = Wyhash(data, size, seed, kWyhashSalt);
-    upb_arena_free(arena);
+    upb_Arena_Free(arena);
     return ret;
   } else {
-    upb_arena_free(arena);
+    upb_Arena_Free(arena);
     rb_raise(cParseError, "Error calculating hash");
   }
 }
@@ -759,13 +791,13 @@
 
 // Support functions for Message_to_h //////////////////////////////////////////
 
-static VALUE RepeatedField_CreateArray(const upb_array* arr,
+static VALUE RepeatedField_CreateArray(const upb_Array* arr,
                                        TypeInfo type_info) {
-  int size = arr ? upb_array_size(arr) : 0;
+  int size = arr ? upb_Array_Size(arr) : 0;
   VALUE ary = rb_ary_new2(size);
 
   for (int i = 0; i < size; i++) {
-    upb_msgval msgval = upb_array_get(arr, i);
+    upb_MessageValue msgval = upb_Array_Get(arr, i);
     VALUE val = Scalar_CreateHash(msgval, type_info);
     rb_ary_push(ary, val);
   }
@@ -773,54 +805,57 @@
   return ary;
 }
 
-static VALUE Message_CreateHash(const upb_msg *msg, const upb_msgdef *m) {
+static VALUE Message_CreateHash(const upb_Message* msg,
+                                const upb_MessageDef* m) {
   if (!msg) return Qnil;
 
   VALUE hash = rb_hash_new();
-  int n = upb_msgdef_fieldcount(m);
+  int n = upb_MessageDef_FieldCount(m);
   bool is_proto2;
 
   // We currently have a few behaviors that are specific to proto2.
   // This is unfortunate, we should key behaviors off field attributes (like
   // whether a field has presence), not proto2 vs. proto3. We should see if we
   // can change this without breaking users.
-  is_proto2 = upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2;
+  is_proto2 = upb_MessageDef_Syntax(m) == kUpb_Syntax_Proto2;
 
   for (int i = 0; i < n; i++) {
-    const upb_fielddef* field = upb_msgdef_field(m, i);
+    const upb_FieldDef* field = upb_MessageDef_Field(m, i);
     TypeInfo type_info = TypeInfo_get(field);
-    upb_msgval msgval;
+    upb_MessageValue msgval;
     VALUE msg_value;
     VALUE msg_key;
 
-    if (!is_proto2 && upb_fielddef_issubmsg(field) &&
-        !upb_fielddef_isseq(field) && !upb_msg_has(msg, field)) {
+    if (!is_proto2 && upb_FieldDef_IsSubMessage(field) &&
+        !upb_FieldDef_IsRepeated(field) && !upb_Message_Has(msg, field)) {
       // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
-      msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
+      msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
       rb_hash_aset(hash, msg_key, Qnil);
       continue;
     }
 
     // Do not include fields that are not present (oneof or optional fields).
-    if (is_proto2 && upb_fielddef_haspresence(field) &&
-        !upb_msg_has(msg, field)) {
+    if (is_proto2 && upb_FieldDef_HasPresence(field) &&
+        !upb_Message_Has(msg, field)) {
       continue;
     }
 
-    msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
-    msgval = upb_msg_get(msg, field);
+    msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
+    msgval = upb_Message_Get(msg, field);
 
     // Proto2 omits empty map/repeated filds also.
 
-    if (upb_fielddef_ismap(field)) {
-      const upb_msgdef *entry_m = upb_fielddef_msgsubdef(field);
-      const upb_fielddef *key_f = upb_msgdef_itof(entry_m, 1);
-      const upb_fielddef *val_f = upb_msgdef_itof(entry_m, 2);
-      upb_fieldtype_t key_type = upb_fielddef_type(key_f);
+    if (upb_FieldDef_IsMap(field)) {
+      const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
+      const upb_FieldDef* key_f =
+          upb_MessageDef_FindFieldByNumberWithSize(entry_m, 1);
+      const upb_FieldDef* val_f =
+          upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2);
+      upb_CType key_type = upb_FieldDef_CType(key_f);
       msg_value = Map_CreateHash(msgval.map_val, key_type, TypeInfo_get(val_f));
-    } else if (upb_fielddef_isseq(field)) {
+    } else if (upb_FieldDef_IsRepeated(field)) {
       if (is_proto2 &&
-          (!msgval.array_val || upb_array_size(msgval.array_val) == 0)) {
+          (!msgval.array_val || upb_Array_Size(msgval.array_val) == 0)) {
         continue;
       }
       msg_value = RepeatedField_CreateArray(msgval.array_val, type_info);
@@ -834,8 +869,8 @@
   return hash;
 }
 
-VALUE Scalar_CreateHash(upb_msgval msgval, TypeInfo type_info) {
-  if (type_info.type == UPB_TYPE_MESSAGE) {
+VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
+  if (type_info.type == kUpb_CType_Message) {
     return Message_CreateHash(msgval.msg_val, type_info.def.msgdef);
   } else {
     return Convert_UpbToRuby(msgval, type_info, Qnil);
@@ -878,10 +913,10 @@
  */
 static VALUE Message_index(VALUE _self, VALUE field_name) {
   Message* self = ruby_to_Message(_self);
-  const upb_fielddef* field;
+  const upb_FieldDef* field;
 
   Check_Type(field_name, T_STRING);
-  field = upb_msgdef_ntofz(self->msgdef, RSTRING_PTR(field_name));
+  field = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
 
   if (field == NULL) {
     return Qnil;
@@ -899,19 +934,19 @@
  */
 static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
   Message* self = ruby_to_Message(_self);
-  const upb_fielddef* f;
-  upb_msgval val;
-  upb_arena *arena = Arena_get(self->arena);
+  const upb_FieldDef* f;
+  upb_MessageValue val;
+  upb_Arena* arena = Arena_get(self->arena);
 
   Check_Type(field_name, T_STRING);
-  f = upb_msgdef_ntofz(self->msgdef, RSTRING_PTR(field_name));
+  f = upb_MessageDef_FindFieldByName(self->msgdef, RSTRING_PTR(field_name));
 
   if (f == NULL) {
     rb_raise(rb_eArgError, "Unknown field: %s", RSTRING_PTR(field_name));
   }
 
-  val = Convert_RubyToUpb(value, upb_fielddef_name(f), TypeInfo_get(f), arena);
-  upb_msg_set(Message_GetMutable(_self, NULL), f, val, arena);
+  val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
+  upb_Message_Set(Message_GetMutable(_self, NULL), f, val, arena);
 
   return Qnil;
 }
@@ -932,9 +967,11 @@
   VALUE msg_rb = initialize_rb_class_with_no_args(klass);
   Message* msg = ruby_to_Message(msg_rb);
 
-  if (!upb_decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_msg*)msg->msg,
-                 upb_msgdef_layout(msg->msgdef),
-                 Arena_get(msg->arena))) {
+  upb_DecodeStatus status = upb_Decode(
+      RSTRING_PTR(data), RSTRING_LEN(data), (upb_Message*)msg->msg,
+      upb_MessageDef_MiniTable(msg->msgdef), NULL, 0, Arena_get(msg->arena));
+
+  if (status != kUpb_DecodeStatus_Ok) {
     rb_raise(cParseError, "Error occurred during parsing");
   }
 
@@ -956,10 +993,10 @@
 static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
   VALUE data = argv[0];
   int options = 0;
-  upb_status status;
+  upb_Status status;
 
   // TODO(haberman): use this message's pool instead.
-  const upb_symtab *symtab = DescriptorPool_GetSymtab(generated_pool);
+  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
 
   if (argc < 1 || argc > 2) {
     rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
@@ -971,8 +1008,9 @@
       rb_raise(rb_eArgError, "Expected hash arguments.");
     }
 
-    if (RTEST(rb_hash_lookup2( hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) {
-      options |= UPB_JSONDEC_IGNOREUNKNOWN;
+    if (RTEST(rb_hash_lookup2(
+            hash_args, ID2SYM(rb_intern("ignore_unknown_fields")), Qfalse))) {
+      options |= upb_JsonDecode_IgnoreUnknown;
     }
   }
 
@@ -988,16 +1026,16 @@
   Message* msg = ruby_to_Message(msg_rb);
 
   // We don't allow users to decode a wrapper type directly.
-  if (upb_msgdef_iswrapper(msg->msgdef)) {
+  if (IsWrapper(msg->msgdef)) {
     rb_raise(rb_eRuntimeError, "Cannot parse a wrapper directly.");
   }
 
-  upb_status_clear(&status);
-  if (!upb_json_decode(RSTRING_PTR(data), RSTRING_LEN(data), (upb_msg*)msg->msg,
-                       msg->msgdef, symtab, options,
-                       Arena_get(msg->arena), &status)) {
+  upb_Status_Clear(&status);
+  if (!upb_JsonDecode(RSTRING_PTR(data), RSTRING_LEN(data),
+                      (upb_Message*)msg->msg, msg->msgdef, symtab, options,
+                      Arena_get(msg->arena), &status)) {
     rb_raise(cParseError, "Error occurred during parsing: %s",
-             upb_status_errmsg(&status));
+             upb_Status_ErrorMessage(&status));
   }
 
   return msg_rb;
@@ -1012,24 +1050,25 @@
  */
 static VALUE Message_encode(VALUE klass, VALUE msg_rb) {
   Message* msg = ruby_to_Message(msg_rb);
-  upb_arena *arena = upb_arena_new();
-  const char *data;
+  const char* data;
   size_t size;
 
   if (CLASS_OF(msg_rb) != klass) {
     rb_raise(rb_eArgError, "Message of wrong type.");
   }
 
-  data = upb_encode(msg->msg, upb_msgdef_layout(msg->msgdef), arena,
+  upb_Arena* arena = upb_Arena_New();
+
+  data = upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), 0, arena,
                     &size);
 
   if (data) {
     VALUE ret = rb_str_new(data, size);
     rb_enc_associate(ret, rb_ascii8bit_encoding());
-    upb_arena_free(arena);
+    upb_Arena_Free(arena);
     return ret;
   } else {
-    upb_arena_free(arena);
+    upb_Arena_Free(arena);
     rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)");
   }
 }
@@ -1040,18 +1079,19 @@
  *
  * Encodes the given message object into its serialized JSON representation.
  * @param options [Hash] options for the decoder
- *  preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase)
- *  emit_defaults: set true to emit 0/false values (default is to omit them)
+ *  preserve_proto_fieldnames: set true to use original fieldnames (default is
+ * to camelCase) emit_defaults: set true to emit 0/false values (default is to
+ * omit them)
  */
 static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
   Message* msg = ruby_to_Message(argv[0]);
   int options = 0;
   char buf[1024];
   size_t size;
-  upb_status status;
+  upb_Status status;
 
   // TODO(haberman): use this message's pool instead.
-  const upb_symtab *symtab = DescriptorPool_GetSymtab(generated_pool);
+  const upb_DefPool* symtab = DescriptorPool_GetSymtab(generated_pool);
 
   if (argc < 1 || argc > 2) {
     rb_raise(rb_eArgError, "Expected 1 or 2 arguments.");
@@ -1066,29 +1106,29 @@
     if (RTEST(rb_hash_lookup2(hash_args,
                               ID2SYM(rb_intern("preserve_proto_fieldnames")),
                               Qfalse))) {
-      options |= UPB_JSONENC_PROTONAMES;
+      options |= upb_JsonEncode_UseProtoNames;
     }
 
     if (RTEST(rb_hash_lookup2(hash_args, ID2SYM(rb_intern("emit_defaults")),
                               Qfalse))) {
-      options |= UPB_JSONENC_EMITDEFAULTS;
+      options |= upb_JsonEncode_EmitDefaults;
     }
   }
 
-  upb_status_clear(&status);
-  size = upb_json_encode(msg->msg, msg->msgdef, symtab, options, buf,
-                         sizeof(buf), &status);
+  upb_Status_Clear(&status);
+  size = upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf,
+                        sizeof(buf), &status);
 
-  if (!upb_ok(&status)) {
+  if (!upb_Status_IsOk(&status)) {
     rb_raise(cParseError, "Error occurred during encoding: %s",
-             upb_status_errmsg(&status));
+             upb_Status_ErrorMessage(&status));
   }
 
   VALUE ret;
   if (size >= sizeof(buf)) {
     char* buf2 = malloc(size + 1);
-    upb_json_encode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
-                    &status);
+    upb_JsonEncode(msg->msg, msg->msgdef, symtab, options, buf2, size + 1,
+                   &status);
     ret = rb_str_new(buf2, size);
     free(buf2);
   } else {
@@ -1111,10 +1151,10 @@
 }
 
 VALUE build_class_from_descriptor(VALUE descriptor) {
-  const char *name;
+  const char* name;
   VALUE klass;
 
-  name = upb_msgdef_fullname(Descriptor_GetMsgDef(descriptor));
+  name = upb_MessageDef_FullName(Descriptor_GetMsgDef(descriptor));
   if (name == NULL) {
     rb_raise(rb_eRuntimeError, "Descriptor does not have assigned name.");
   }
@@ -1122,8 +1162,7 @@
   klass = rb_define_class_id(
       // Docs say this parameter is ignored. User will assign return value to
       // their own toplevel constant class name.
-      rb_intern("Message"),
-      rb_cObject);
+      rb_intern("Message"), rb_cObject);
   rb_ivar_set(klass, descriptor_instancevar_interned, descriptor);
   rb_define_alloc_func(klass, Message_alloc);
   rb_require("google/protobuf/message_exts");
@@ -1131,10 +1170,9 @@
   rb_extend_object(
       klass, rb_eval_string("::Google::Protobuf::MessageExts::ClassMethods"));
 
-  rb_define_method(klass, "method_missing",
-                   Message_method_missing, -1);
-  rb_define_method(klass, "respond_to_missing?",
-                   Message_respond_to_missing, -1);
+  rb_define_method(klass, "method_missing", Message_method_missing, -1);
+  rb_define_method(klass, "respond_to_missing?", Message_respond_to_missing,
+                   -1);
   rb_define_method(klass, "initialize", Message_initialize, -1);
   rb_define_method(klass, "dup", Message_dup, 0);
   // Also define #clone so that we don't inherit Object#clone.
@@ -1167,13 +1205,12 @@
 static VALUE enum_lookup(VALUE self, VALUE number) {
   int32_t num = NUM2INT(number);
   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
-  const upb_enumdef *e = EnumDescriptor_GetEnumDef(desc);
-
-  const char* name = upb_enumdef_iton(e, num);
-  if (name == NULL) {
-    return Qnil;
+  const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
+  const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e, num);
+  if (ev) {
+    return ID2SYM(rb_intern(upb_EnumValueDef_Name(ev)));
   } else {
-    return ID2SYM(rb_intern(name));
+    return Qnil;
   }
 }
 
@@ -1187,14 +1224,12 @@
 static VALUE enum_resolve(VALUE self, VALUE sym) {
   const char* name = rb_id2name(SYM2ID(sym));
   VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
-  const upb_enumdef *e = EnumDescriptor_GetEnumDef(desc);
-
-  int32_t num = 0;
-  bool found = upb_enumdef_ntoiz(e, name, &num);
-  if (!found) {
-    return Qnil;
+  const upb_EnumDef* e = EnumDescriptor_GetEnumDef(desc);
+  const upb_EnumValueDef* ev = upb_EnumDef_FindValueByName(e, name);
+  if (ev) {
+    return INT2NUM(upb_EnumValueDef_Number(ev));
   } else {
-    return INT2NUM(num);
+    return Qnil;
   }
 }
 
@@ -1210,19 +1245,19 @@
 }
 
 VALUE build_module_from_enumdesc(VALUE _enumdesc) {
-  const upb_enumdef *e = EnumDescriptor_GetEnumDef(_enumdesc);
-  VALUE mod = rb_define_module_id(rb_intern(upb_enumdef_fullname(e)));
+  const upb_EnumDef* e = EnumDescriptor_GetEnumDef(_enumdesc);
+  VALUE mod = rb_define_module_id(rb_intern(upb_EnumDef_FullName(e)));
 
-  upb_enum_iter it;
-  for (upb_enum_begin(&it, e);
-       !upb_enum_done(&it);
-       upb_enum_next(&it)) {
-    const char* name = upb_enum_iter_name(&it);
-    int32_t value = upb_enum_iter_number(&it);
+  int n = upb_EnumDef_ValueCount(e);
+  for (int i = 0; i < n; i++) {
+    const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
+    const char* name = upb_EnumValueDef_Name(ev);
+    int32_t value = upb_EnumValueDef_Number(ev);
     if (name[0] < 'A' || name[0] > 'Z') {
-      rb_warn("Enum value '%s' does not start with an uppercase letter "
-              "as is required for Ruby constants.",
-              name);
+      rb_warn(
+          "Enum value '%s' does not start with an uppercase letter "
+          "as is required for Ruby constants.",
+          name);
     }
     rb_define_const(mod, name, INT2NUM(value));
   }
@@ -1236,80 +1271,84 @@
 }
 
 // Internal only; used by Google::Protobuf.deep_copy.
-upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
-                           upb_arena *arena) {
+upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
+                               upb_Arena* arena) {
   // Serialize and parse.
-  upb_arena *tmp_arena = upb_arena_new();
-  const upb_msglayout *layout = upb_msgdef_layout(m);
+  upb_Arena* tmp_arena = upb_Arena_New();
+  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
   size_t size;
 
-  char* data = upb_encode_ex(msg, layout, 0, tmp_arena, &size);
-  upb_msg* new_msg = upb_msg_new(m, arena);
+  char* data = upb_Encode(msg, layout, 0, tmp_arena, &size);
+  upb_Message* new_msg = upb_Message_New(m, arena);
 
-  if (!data || !upb_decode(data, size, new_msg, layout, arena)) {
-    upb_arena_free(tmp_arena);
+  if (!data || upb_Decode(data, size, new_msg, layout, NULL, 0, arena) !=
+                   kUpb_DecodeStatus_Ok) {
+    upb_Arena_Free(tmp_arena);
     rb_raise(cParseError, "Error occurred copying proto");
   }
 
-  upb_arena_free(tmp_arena);
+  upb_Arena_Free(tmp_arena);
   return new_msg;
 }
 
-const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
-                                     const char* name, upb_arena* arena) {
+const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
+                                         const char* name, upb_Arena* arena) {
   if (value == Qnil) {
     rb_raise(cTypeError, "nil message not allowed here.");
   }
 
   VALUE klass = CLASS_OF(value);
   VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned);
-  const upb_msgdef* val_m =
+  const upb_MessageDef* val_m =
       desc_rb == Qnil ? NULL : Descriptor_GetMsgDef(desc_rb);
 
   if (val_m != m) {
     // Check for possible implicit conversions
     // TODO: hash conversion?
 
-    switch (upb_msgdef_wellknowntype(m)) {
-      case UPB_WELLKNOWN_TIMESTAMP: {
+    switch (upb_MessageDef_WellKnownType(m)) {
+      case kUpb_WellKnown_Timestamp: {
         // Time -> Google::Protobuf::Timestamp
-        upb_msg *msg = upb_msg_new(m, arena);
-        upb_msgval sec, nsec;
+        upb_Message* msg = upb_Message_New(m, arena);
+        upb_MessageValue sec, nsec;
         struct timespec time;
-        const upb_fielddef *sec_f = upb_msgdef_itof(m, 1);
-        const upb_fielddef *nsec_f = upb_msgdef_itof(m, 2);
+        const upb_FieldDef* sec_f =
+            upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+        const upb_FieldDef* nsec_f =
+            upb_MessageDef_FindFieldByNumberWithSize(m, 2);
 
         if (!rb_obj_is_kind_of(value, rb_cTime)) goto badtype;
 
         time = rb_time_timespec(value);
         sec.int64_val = time.tv_sec;
         nsec.int32_val = time.tv_nsec;
-        upb_msg_set(msg, sec_f, sec, arena);
-        upb_msg_set(msg, nsec_f, nsec, arena);
+        upb_Message_Set(msg, sec_f, sec, arena);
+        upb_Message_Set(msg, nsec_f, nsec, arena);
         return msg;
       }
-      case UPB_WELLKNOWN_DURATION: {
+      case kUpb_WellKnown_Duration: {
         // Numeric -> Google::Protobuf::Duration
-        upb_msg *msg = upb_msg_new(m, arena);
-        upb_msgval sec, nsec;
-        const upb_fielddef *sec_f = upb_msgdef_itof(m, 1);
-        const upb_fielddef *nsec_f = upb_msgdef_itof(m, 2);
+        upb_Message* msg = upb_Message_New(m, arena);
+        upb_MessageValue sec, nsec;
+        const upb_FieldDef* sec_f =
+            upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+        const upb_FieldDef* nsec_f =
+            upb_MessageDef_FindFieldByNumberWithSize(m, 2);
 
         if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype;
 
         sec.int64_val = NUM2LL(value);
         nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
-        upb_msg_set(msg, sec_f, sec, arena);
-        upb_msg_set(msg, nsec_f, nsec, arena);
+        upb_Message_Set(msg, sec_f, sec, arena);
+        upb_Message_Set(msg, nsec_f, nsec, arena);
         return msg;
       }
       default:
       badtype:
         rb_raise(cTypeError,
                  "Invalid type %s to assign to submessage field '%s'.",
-                rb_class2name(CLASS_OF(value)), name);
+                 rb_class2name(CLASS_OF(value)), name);
     }
-
   }
 
   Message* self = ruby_to_Message(value);
diff --git a/ruby/ext/google/protobuf_c/message.h b/ruby/ext/google/protobuf_c/message.h
index 2ec440c..b409650 100644
--- a/ruby/ext/google/protobuf_c/message.h
+++ b/ruby/ext/google/protobuf_c/message.h
@@ -36,55 +36,58 @@
 #include "protobuf.h"
 #include "ruby-upb.h"
 
-// Gets the underlying upb_msg* and upb_msgdef for the given Ruby message
-// wrapper. Requires that |value| is indeed a message object.
-const upb_msg *Message_Get(VALUE value, const upb_msgdef **m);
+// Gets the underlying upb_Message* and upb_MessageDef for the given Ruby
+// message wrapper. Requires that |value| is indeed a message object.
+const upb_Message* Message_Get(VALUE value, const upb_MessageDef** m);
 
 // Like Message_Get(), but checks that the object is not frozen and returns a
 // mutable pointer.
-upb_msg *Message_GetMutable(VALUE value, const upb_msgdef **m);
+upb_Message* Message_GetMutable(VALUE value, const upb_MessageDef** m);
 
 // Returns the Arena object for this message.
 VALUE Message_GetArena(VALUE value);
 
-// Converts |value| into a upb_msg value of the expected upb_msgdef type,
-// raising an error if this is not possible. Used when assigning |value| to a
-// field of another message, which means the message must be of a particular
-// type.
+// Converts |value| into a upb_Message value of the expected upb_MessageDef
+// type, raising an error if this is not possible. Used when assigning |value|
+// to a field of another message, which means the message must be of a
+// particular type.
 //
 // This will perform automatic conversions in some cases (for example, Time ->
 // Google::Protobuf::Timestamp). If any new message is created, it will be
 // created on |arena|, and any existing message will have its arena fused with
 // |arena|.
-const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
-                                     const char* name, upb_arena* arena);
+const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
+                                         const char* name, upb_Arena* arena);
 
 // Gets or constructs a Ruby wrapper object for the given message. The wrapper
 // object will reference |arena| and ensure that it outlives this object.
-VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena);
+VALUE Message_GetRubyWrapper(upb_Message* msg, const upb_MessageDef* m,
+                             VALUE arena);
 
 // Gets the given field from this message.
-VALUE Message_getfield(VALUE _self, const upb_fielddef* f);
+VALUE Message_getfield(VALUE _self, const upb_FieldDef* f);
 
 // Implements #inspect for this message, printing the text to |b|.
-void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
-                          const upb_msgdef* m);
+void Message_PrintMessage(StringBuilder* b, const upb_Message* msg,
+                          const upb_MessageDef* m);
 
 // Returns a hash value for the given message.
-uint64_t Message_Hash(const upb_msg *msg, const upb_msgdef *m, uint64_t seed);
+uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
+                      uint64_t seed);
 
 // Returns a deep copy of the given message.
-upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
-                           upb_arena *arena);
+upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
+                               upb_Arena* arena);
 
 // Returns true if these two messages are equal.
-bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m);
+bool Message_Equal(const upb_Message* m1, const upb_Message* m2,
+                   const upb_MessageDef* m);
 
 // Checks that this Ruby object is a message, and raises an exception if not.
 void Message_CheckClass(VALUE klass);
 
 // Returns a new Hash object containing the contents of this message.
-VALUE Scalar_CreateHash(upb_msgval val, TypeInfo type_info);
+VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info);
 
 // Creates a message class or enum module for this descriptor, respectively.
 VALUE build_class_from_descriptor(VALUE descriptor);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index a61328b..4d3e1a5 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -40,14 +40,14 @@
 VALUE cParseError;
 VALUE cTypeError;
 
-const upb_fielddef* map_field_key(const upb_fielddef* field) {
-  const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
-  return upb_msgdef_itof(entry, 1);
+const upb_FieldDef *map_field_key(const upb_FieldDef *field) {
+  const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
+  return upb_MessageDef_FindFieldByNumberWithSize(entry, 1);
 }
 
-const upb_fielddef* map_field_value(const upb_fielddef* field) {
-  const upb_msgdef *entry = upb_fielddef_msgsubdef(field);
-  return upb_msgdef_itof(entry, 2);
+const upb_FieldDef *map_field_value(const upb_FieldDef *field) {
+  const upb_MessageDef *entry = upb_FieldDef_MessageSubDef(field);
+  return upb_MessageDef_FindFieldByNumberWithSize(entry, 2);
 }
 
 // -----------------------------------------------------------------------------
@@ -66,21 +66,21 @@
   return sizeof(StringBuilder) + cap;
 }
 
-StringBuilder* StringBuilder_New() {
+StringBuilder *StringBuilder_New() {
   const size_t cap = 128;
-  StringBuilder* builder = malloc(sizeof(*builder));
+  StringBuilder *builder = malloc(sizeof(*builder));
   builder->size = 0;
   builder->cap = cap;
   builder->data = malloc(builder->cap);
   return builder;
 }
 
-void StringBuilder_Free(StringBuilder* b) {
+void StringBuilder_Free(StringBuilder *b) {
   free(b->data);
   free(b);
 }
 
-void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...) {
+void StringBuilder_Printf(StringBuilder *b, const char *fmt, ...) {
   size_t have = b->cap - b->size;
   size_t n;
   va_list args;
@@ -104,60 +104,62 @@
   b->size += n;
 }
 
-VALUE StringBuilder_ToRubyString(StringBuilder* b) {
+VALUE StringBuilder_ToRubyString(StringBuilder *b) {
   VALUE ret = rb_str_new(b->data, b->size);
   rb_enc_associate(ret, rb_utf8_encoding());
   return ret;
 }
 
-static void StringBuilder_PrintEnum(StringBuilder* b, int32_t val,
-                                    const upb_enumdef* e) {
-  const char *name = upb_enumdef_iton(e, val);
-  if (name) {
-    StringBuilder_Printf(b, ":%s", name);
+static void StringBuilder_PrintEnum(StringBuilder *b, int32_t val,
+                                    const upb_EnumDef *e) {
+  const upb_EnumValueDef *ev = upb_EnumDef_FindValueByNumber(e, val);
+  if (ev) {
+    StringBuilder_Printf(b, ":%s", upb_EnumValueDef_Name(ev));
   } else {
     StringBuilder_Printf(b, "%" PRId32, val);
   }
 }
 
-void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val,
+void StringBuilder_PrintMsgval(StringBuilder *b, upb_MessageValue val,
                                TypeInfo info) {
   switch (info.type) {
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       StringBuilder_Printf(b, "%s", val.bool_val ? "true" : "false");
       break;
-    case UPB_TYPE_FLOAT: {
+    case kUpb_CType_Float: {
       VALUE str = rb_inspect(DBL2NUM(val.float_val));
       StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
       break;
     }
-    case UPB_TYPE_DOUBLE: {
+    case kUpb_CType_Double: {
       VALUE str = rb_inspect(DBL2NUM(val.double_val));
       StringBuilder_Printf(b, "%s", RSTRING_PTR(str));
       break;
     }
-    case UPB_TYPE_INT32:
+    case kUpb_CType_Int32:
       StringBuilder_Printf(b, "%" PRId32, val.int32_val);
       break;
-    case UPB_TYPE_UINT32:
+    case kUpb_CType_UInt32:
       StringBuilder_Printf(b, "%" PRIu32, val.uint32_val);
       break;
-    case UPB_TYPE_INT64:
+    case kUpb_CType_Int64:
       StringBuilder_Printf(b, "%" PRId64, val.int64_val);
       break;
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_UInt64:
       StringBuilder_Printf(b, "%" PRIu64, val.uint64_val);
       break;
-    case UPB_TYPE_STRING:
-      StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
+    case kUpb_CType_String:
+      StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
+                           val.str_val.data);
       break;
-    case UPB_TYPE_BYTES:
-      StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size, val.str_val.data);
+    case kUpb_CType_Bytes:
+      StringBuilder_Printf(b, "\"%.*s\"", (int)val.str_val.size,
+                           val.str_val.data);
       break;
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Enum:
       StringBuilder_PrintEnum(b, val.int32_val, info.def.enumdef);
       break;
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       Message_PrintMessage(b, val.msg_val, info.def.msgdef);
       break;
   }
@@ -168,7 +170,7 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  upb_arena *arena;
+  upb_Arena *arena;
   VALUE pinned_objs;
 } Arena;
 
@@ -179,44 +181,42 @@
 
 static void Arena_free(void *data) {
   Arena *arena = data;
-  upb_arena_free(arena->arena);
+  upb_Arena_Free(arena->arena);
   xfree(arena);
 }
 
 static VALUE cArena;
 
 const rb_data_type_t Arena_type = {
-  "Google::Protobuf::Internal::Arena",
-  { Arena_mark, Arena_free, NULL },
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::Internal::Arena",
+    {Arena_mark, Arena_free, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static VALUE Arena_alloc(VALUE klass) {
   Arena *arena = ALLOC(Arena);
-  arena->arena = upb_arena_new();
+  arena->arena = upb_Arena_New();
   arena->pinned_objs = Qnil;
   return TypedData_Wrap_Struct(klass, &Arena_type, arena);
 }
 
-upb_arena *Arena_get(VALUE _arena) {
+upb_Arena *Arena_get(VALUE _arena) {
   Arena *arena;
   TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
   return arena->arena;
 }
 
-void Arena_fuse(VALUE _arena, upb_arena *other) {
+void Arena_fuse(VALUE _arena, upb_Arena *other) {
   Arena *arena;
   TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
-  if (!upb_arena_fuse(arena->arena, other)) {
+  if (!upb_Arena_Fuse(arena->arena, other)) {
     rb_raise(rb_eRuntimeError,
              "Unable to fuse arenas. This should never happen since Ruby does "
              "not use initial blocks");
   }
 }
 
-VALUE Arena_new() {
-  return Arena_alloc(cArena);
-}
+VALUE Arena_new() { return Arena_alloc(cArena); }
 
 void Arena_Pin(VALUE _arena, VALUE obj) {
   Arena *arena;
@@ -333,8 +333,8 @@
   // avoid O(N^2) CPU costs.
   size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
   if (waste > threshold) {
-    rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2,
-               secondary_map, weak_obj_cache);
+    rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2, secondary_map,
+               weak_obj_cache);
   }
 }
 
@@ -353,7 +353,7 @@
 #endif
 
 // Requires: secondary_map_mutex is held by this thread iff create == true.
-static VALUE ObjectCache_GetKey(const void* key, bool create) {
+static VALUE ObjectCache_GetKey(const void *key, bool create) {
   VALUE key_val = (VALUE)key;
   PBRUBY_ASSERT((key_val & 3) == 0);
   VALUE ret = LL2NUM(key_val >> 2);
@@ -380,7 +380,7 @@
 #endif
 }
 
-void ObjectCache_Add(const void* key, VALUE val) {
+void ObjectCache_Add(const void *key, VALUE val) {
   PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
 #if USE_SECONDARY_MAP
   rb_mutex_lock(secondary_map_mutex);
@@ -394,7 +394,7 @@
 }
 
 // Returns the cached object for this key, if any. Otherwise returns Qnil.
-VALUE ObjectCache_Get(const void* key) {
+VALUE ObjectCache_Get(const void *key) {
   VALUE key_rb = ObjectCache_GetKey(key, false);
   return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
 }
@@ -407,9 +407,9 @@
  * unknown fields in submessages.
  */
 static VALUE Google_Protobuf_discard_unknown(VALUE self, VALUE msg_rb) {
-  const upb_msgdef *m;
-  upb_msg *msg = Message_GetMutable(msg_rb, &m);
-  if (!upb_msg_discardunknown(msg, m, 128)) {
+  const upb_MessageDef *m;
+  upb_Message *msg = Message_GetMutable(msg_rb, &m);
+  if (!upb_Message_DiscardUnknown(msg, m, 128)) {
     rb_raise(rb_eRuntimeError, "Messages nested too deeply.");
   }
 
@@ -431,10 +431,10 @@
     return Map_deep_copy(obj);
   } else {
     VALUE new_arena_rb = Arena_new();
-    upb_arena *new_arena = Arena_get(new_arena_rb);
-    const upb_msgdef *m;
-    const upb_msg *msg = Message_Get(obj, &m);
-    upb_msg* new_msg = Message_deep_copy(msg, m, new_arena);
+    upb_Arena *new_arena = Arena_get(new_arena_rb);
+    const upb_MessageDef *m;
+    const upb_Message *msg = Message_Get(obj, &m);
+    upb_Message *new_msg = Message_deep_copy(msg, m, new_arena);
     return Message_GetRubyWrapper(new_msg, m, new_arena_rb);
   }
 }
@@ -445,8 +445,7 @@
 
 // This must be named "Init_protobuf_c" because the Ruby module is named
 // "protobuf_c" -- the VM looks for this symbol in our .so.
-__attribute__ ((visibility ("default")))
-void Init_protobuf_c() {
+__attribute__((visibility("default"))) void Init_protobuf_c() {
   ObjectCache_Init();
 
   VALUE google = rb_define_module("Google");
@@ -465,6 +464,6 @@
 
   rb_define_singleton_method(protobuf, "discard_unknown",
                              Google_Protobuf_discard_unknown, 1);
-  rb_define_singleton_method(protobuf, "deep_copy",
-                             Google_Protobuf_deep_copy, 1);
+  rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
+                             1);
 }
diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h
index f7ac204..c6af98f 100644
--- a/ruby/ext/google/protobuf_c/protobuf.h
+++ b/ruby/ext/google/protobuf_c/protobuf.h
@@ -31,33 +31,33 @@
 #ifndef __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
 #define __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
 
+#include <ruby/encoding.h>
 #include <ruby/ruby.h>
 #include <ruby/vm.h>
-#include <ruby/encoding.h>
 
-#include "ruby-upb.h"
 #include "defs.h"
+#include "ruby-upb.h"
 
 // These operate on a map field (i.e., a repeated field of submessages whose
 // submessage type is a map-entry msgdef).
-const upb_fielddef* map_field_key(const upb_fielddef* field);
-const upb_fielddef* map_field_value(const upb_fielddef* field);
+const upb_FieldDef* map_field_key(const upb_FieldDef* field);
+const upb_FieldDef* map_field_value(const upb_FieldDef* field);
 
 // -----------------------------------------------------------------------------
 // Arena
 // -----------------------------------------------------------------------------
 
-// A Ruby object that wraps an underlying upb_arena.  Any objects that are
+// A Ruby object that wraps an underlying upb_Arena.  Any objects that are
 // allocated from this arena should reference the Arena in rb_gc_mark(), to
 // ensure that the object's underlying memory outlives any Ruby object that can
 // reach it.
 
 VALUE Arena_new();
-upb_arena *Arena_get(VALUE arena);
+upb_Arena* Arena_get(VALUE arena);
 
 // Fuses this arena to another, throwing a Ruby exception if this is not
 // possible.
-void Arena_fuse(VALUE arena, upb_arena *other);
+void Arena_fuse(VALUE arena, upb_Arena* other);
 
 // Pins this Ruby object to the lifetime of this arena, so that as long as the
 // arena is alive this object will not be collected.
@@ -93,10 +93,11 @@
 
 StringBuilder* StringBuilder_New();
 void StringBuilder_Free(StringBuilder* b);
-void StringBuilder_Printf(StringBuilder* b, const char *fmt, ...);
+void StringBuilder_Printf(StringBuilder* b, const char* fmt, ...);
 VALUE StringBuilder_ToRubyString(StringBuilder* b);
 
-void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val, TypeInfo info);
+void StringBuilder_PrintMsgval(StringBuilder* b, upb_MessageValue val,
+                               TypeInfo info);
 
 // -----------------------------------------------------------------------------
 // Utilities.
@@ -105,7 +106,9 @@
 extern VALUE cTypeError;
 
 #ifdef NDEBUG
-#define PBRUBY_ASSERT(expr) do {} while (false && (expr))
+#define PBRUBY_ASSERT(expr) \
+  do {                      \
+  } while (false && (expr))
 #else
 #define PBRUBY_ASSERT(expr) assert(expr)
 #endif
diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c
index 5ff3c76..700ca16 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.c
+++ b/ruby/ext/google/protobuf_c/repeated_field.c
@@ -40,10 +40,10 @@
 // -----------------------------------------------------------------------------
 
 typedef struct {
-  const upb_array *array;   // Can get as mutable when non-frozen.
+  const upb_Array* array;  // Can get as mutable when non-frozen.
   TypeInfo type_info;
   VALUE type_class;  // To GC-root the msgdef/enumdef in type_info.
-  VALUE arena;       // To GC-root the upb_array.
+  VALUE arena;       // To GC-root the upb_Array.
 } RepeatedField;
 
 VALUE cRepeatedField;
@@ -55,9 +55,9 @@
 }
 
 const rb_data_type_t RepeatedField_type = {
-  "Google::Protobuf::RepeatedField",
-  { RepeatedField_mark, RUBY_DEFAULT_FREE, NULL },
-  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+    "Google::Protobuf::RepeatedField",
+    {RepeatedField_mark, RUBY_DEFAULT_FREE, NULL},
+    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
 };
 
 static RepeatedField* ruby_to_RepeatedField(VALUE _self) {
@@ -66,9 +66,9 @@
   return self;
 }
 
-static upb_array *RepeatedField_GetMutable(VALUE _self) {
+static upb_Array* RepeatedField_GetMutable(VALUE _self) {
   rb_check_frozen(_self);
-  return (upb_array*)ruby_to_RepeatedField(_self)->array;
+  return (upb_Array*)ruby_to_RepeatedField(_self)->array;
 }
 
 VALUE RepeatedField_alloc(VALUE klass) {
@@ -79,7 +79,7 @@
   return TypedData_Wrap_Struct(klass, &RepeatedField_type, self);
 }
 
-VALUE RepeatedField_GetRubyWrapper(upb_array* array, TypeInfo type_info,
+VALUE RepeatedField_GetRubyWrapper(upb_Array* array, TypeInfo type_info,
                                    VALUE arena) {
   PBRUBY_ASSERT(array);
   VALUE val = ObjectCache_Get(array);
@@ -92,7 +92,7 @@
     self->array = array;
     self->arena = arena;
     self->type_info = type_info;
-    if (self->type_info.type == UPB_TYPE_MESSAGE) {
+    if (self->type_info.type == kUpb_CType_Message) {
       self->type_class = Descriptor_DefToClass(type_info.def.msgdef);
     }
   }
@@ -105,24 +105,24 @@
 
 static VALUE RepeatedField_new_this_type(RepeatedField* from) {
   VALUE arena_rb = Arena_new();
-  upb_array *array = upb_array_new(Arena_get(arena_rb), from->type_info.type);
+  upb_Array* array = upb_Array_New(Arena_get(arena_rb), from->type_info.type);
   VALUE ret = RepeatedField_GetRubyWrapper(array, from->type_info, arena_rb);
   PBRUBY_ASSERT(ruby_to_RepeatedField(ret)->type_class == from->type_class);
   return ret;
 }
 
-void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,
+void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array,
                            TypeInfo info) {
   bool first = true;
   StringBuilder_Printf(b, "[");
-  size_t n = array ? upb_array_size(array) : 0;
+  size_t n = array ? upb_Array_Size(array) : 0;
   for (size_t i = 0; i < n; i++) {
     if (first) {
       first = false;
     } else {
       StringBuilder_Printf(b, ", ");
     }
-    StringBuilder_PrintMsgval(b, upb_array_get(array, i), info);
+    StringBuilder_PrintMsgval(b, upb_Array_Get(array, i), info);
   }
   StringBuilder_Printf(b, "]");
 }
@@ -132,24 +132,24 @@
   VALUE new_rptfield = RepeatedField_new_this_type(self);
   RepeatedField* new_self = ruby_to_RepeatedField(new_rptfield);
   VALUE arena_rb = new_self->arena;
-  upb_array *new_array = RepeatedField_GetMutable(new_rptfield);
-  upb_arena *arena = Arena_get(arena_rb);
-  size_t elements = upb_array_size(self->array);
+  upb_Array* new_array = RepeatedField_GetMutable(new_rptfield);
+  upb_Arena* arena = Arena_get(arena_rb);
+  size_t elements = upb_Array_Size(self->array);
 
-  upb_array_resize(new_array, elements, arena);
+  upb_Array_Resize(new_array, elements, arena);
 
-  size_t size = upb_array_size(self->array);
+  size_t size = upb_Array_Size(self->array);
   for (size_t i = 0; i < size; i++) {
-    upb_msgval msgval = upb_array_get(self->array, i);
-    upb_msgval copy = Msgval_DeepCopy(msgval, self->type_info, arena);
-    upb_array_set(new_array, i, copy);
+    upb_MessageValue msgval = upb_Array_Get(self->array, i);
+    upb_MessageValue copy = Msgval_DeepCopy(msgval, self->type_info, arena);
+    upb_Array_Set(new_array, i, copy);
   }
 
   return new_rptfield;
 }
 
-const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef* field,
-                                           upb_arena* arena) {
+const upb_Array* RepeatedField_GetUpbArray(VALUE val, const upb_FieldDef* field,
+                                           upb_Arena* arena) {
   RepeatedField* self;
   TypeInfo type_info = TypeInfo_get(field);
 
@@ -173,17 +173,17 @@
 
 static int index_position(VALUE _index, RepeatedField* repeated_field) {
   int index = NUM2INT(_index);
-  if (index < 0) index += upb_array_size(repeated_field->array);
+  if (index < 0) index += upb_Array_Size(repeated_field->array);
   return index;
 }
 
 static VALUE RepeatedField_subarray(RepeatedField* self, long beg, long len) {
-  size_t size = upb_array_size(self->array);
+  size_t size = upb_Array_Size(self->array);
   VALUE ary = rb_ary_new2(size);
   long i;
 
   for (i = beg; i < beg + len; i++) {
-    upb_msgval msgval = upb_array_get(self->array, i);
+    upb_MessageValue msgval = upb_Array_Get(self->array, i);
     VALUE elem = Convert_UpbToRuby(msgval, self->type_info, self->arena);
     rb_ary_push(ary, elem);
   }
@@ -200,18 +200,17 @@
  */
 static VALUE RepeatedField_each(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  int size = upb_array_size(self->array);
+  int size = upb_Array_Size(self->array);
   int i;
 
   for (i = 0; i < size; i++) {
-    upb_msgval msgval = upb_array_get(self->array, i);
+    upb_MessageValue msgval = upb_Array_Get(self->array, i);
     VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
     rb_yield(val);
   }
   return _self;
 }
 
-
 /*
  * call-seq:
  *     RepeatedField.[](index) => value
@@ -220,20 +219,20 @@
  */
 static VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  long size = upb_array_size(self->array);
+  long size = upb_Array_Size(self->array);
 
   VALUE arg = argv[0];
   long beg, len;
 
-  if (argc == 1){
+  if (argc == 1) {
     if (FIXNUM_P(arg)) {
       /* standard case */
-      upb_msgval msgval;
+      upb_MessageValue msgval;
       int index = index_position(argv[0], self);
-      if (index < 0 || (size_t)index >= upb_array_size(self->array)) {
+      if (index < 0 || (size_t)index >= upb_Array_Size(self->array)) {
         return Qnil;
       }
-      msgval = upb_array_get(self->array, index);
+      msgval = upb_Array_Get(self->array, index);
       return Convert_UpbToRuby(msgval, self->type_info, self->arena);
     } else {
       /* check if idx is Range */
@@ -269,10 +268,10 @@
  */
 static VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  int size = upb_array_size(self->array);
-  upb_array *array = RepeatedField_GetMutable(_self);
-  upb_arena *arena = Arena_get(self->arena);
-  upb_msgval msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
+  int size = upb_Array_Size(self->array);
+  upb_Array* array = RepeatedField_GetMutable(_self);
+  upb_Arena* arena = Arena_get(self->arena);
+  upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
 
   int index = index_position(_index, self);
   if (index < 0 || index >= (INT_MAX - 1)) {
@@ -280,17 +279,17 @@
   }
 
   if (index >= size) {
-    upb_array_resize(array, index + 1, arena);
-    upb_msgval fill;
+    upb_Array_Resize(array, index + 1, arena);
+    upb_MessageValue fill;
     memset(&fill, 0, sizeof(fill));
     for (int i = size; i < index; i++) {
       // Fill default values.
       // TODO(haberman): should this happen at the upb level?
-      upb_array_set(array, i, fill);
+      upb_Array_Set(array, i, fill);
     }
   }
 
-  upb_array_set(array, index, msgval);
+  upb_Array_Set(array, index, msgval);
   return Qnil;
 }
 
@@ -302,13 +301,14 @@
  */
 static VALUE RepeatedField_push_vararg(int argc, VALUE* argv, VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  upb_arena *arena = Arena_get(self->arena);
-  upb_array *array = RepeatedField_GetMutable(_self);
+  upb_Arena* arena = Arena_get(self->arena);
+  upb_Array* array = RepeatedField_GetMutable(_self);
   int i;
 
   for (i = 0; i < argc; i++) {
-    upb_msgval msgval = Convert_RubyToUpb(argv[i], "", self->type_info, arena);
-    upb_array_append(array, msgval, arena);
+    upb_MessageValue msgval =
+        Convert_RubyToUpb(argv[i], "", self->type_info, arena);
+    upb_Array_Append(array, msgval, arena);
   }
 
   return _self;
@@ -322,11 +322,11 @@
  */
 static VALUE RepeatedField_push(VALUE _self, VALUE val) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  upb_arena *arena = Arena_get(self->arena);
-  upb_array *array = RepeatedField_GetMutable(_self);
+  upb_Arena* arena = Arena_get(self->arena);
+  upb_Array* array = RepeatedField_GetMutable(_self);
 
-  upb_msgval msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
-  upb_array_append(array, msgval, arena);
+  upb_MessageValue msgval = Convert_RubyToUpb(val, "", self->type_info, arena);
+  upb_Array_Append(array, msgval, arena);
 
   return _self;
 }
@@ -336,19 +336,19 @@
  */
 static VALUE RepeatedField_pop_one(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  size_t size = upb_array_size(self->array);
-  upb_array *array = RepeatedField_GetMutable(_self);
-  upb_msgval last;
+  size_t size = upb_Array_Size(self->array);
+  upb_Array* array = RepeatedField_GetMutable(_self);
+  upb_MessageValue last;
   VALUE ret;
 
   if (size == 0) {
     return Qnil;
   }
 
-  last = upb_array_get(self->array, size - 1);
+  last = upb_Array_Get(self->array, size - 1);
   ret = Convert_UpbToRuby(last, self->type_info, self->arena);
 
-  upb_array_resize(array, size - 1, Arena_get(self->arena));
+  upb_Array_Resize(array, size - 1, Arena_get(self->arena));
   return ret;
 }
 
@@ -360,11 +360,11 @@
  */
 static VALUE RepeatedField_replace(VALUE _self, VALUE list) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  upb_array *array = RepeatedField_GetMutable(_self);
+  upb_Array* array = RepeatedField_GetMutable(_self);
   int i;
 
   Check_Type(list, T_ARRAY);
-  upb_array_resize(array, 0, Arena_get(self->arena));
+  upb_Array_Resize(array, 0, Arena_get(self->arena));
 
   for (i = 0; i < RARRAY_LEN(list); i++) {
     RepeatedField_push(_self, rb_ary_entry(list, i));
@@ -381,8 +381,8 @@
  */
 static VALUE RepeatedField_clear(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  upb_array *array = RepeatedField_GetMutable(_self);
-  upb_array_resize(array, 0, Arena_get(self->arena));
+  upb_Array* array = RepeatedField_GetMutable(_self);
+  upb_Array_Resize(array, 0, Arena_get(self->arena));
   return _self;
 }
 
@@ -394,7 +394,7 @@
  */
 static VALUE RepeatedField_length(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  return INT2NUM(upb_array_size(self->array));
+  return INT2NUM(upb_Array_Size(self->array));
 }
 
 /*
@@ -408,16 +408,16 @@
   RepeatedField* self = ruby_to_RepeatedField(_self);
   VALUE new_rptfield = RepeatedField_new_this_type(self);
   RepeatedField* new_rptfield_self = ruby_to_RepeatedField(new_rptfield);
-  upb_array *new_array = RepeatedField_GetMutable(new_rptfield);
-  upb_arena* arena = Arena_get(new_rptfield_self->arena);
-  int size = upb_array_size(self->array);
+  upb_Array* new_array = RepeatedField_GetMutable(new_rptfield);
+  upb_Arena* arena = Arena_get(new_rptfield_self->arena);
+  int size = upb_Array_Size(self->array);
   int i;
 
   Arena_fuse(self->arena, arena);
 
   for (i = 0; i < size; i++) {
-    upb_msgval msgval = upb_array_get(self->array, i);
-    upb_array_append(new_array, msgval, arena);
+    upb_MessageValue msgval = upb_Array_Get(self->array, i);
+    upb_Array_Append(new_array, msgval, arena);
   }
 
   return new_rptfield;
@@ -432,12 +432,12 @@
  */
 VALUE RepeatedField_to_ary(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  int size = upb_array_size(self->array);
+  int size = upb_Array_Size(self->array);
   VALUE ary = rb_ary_new2(size);
   int i;
 
   for (i = 0; i < size; i++) {
-    upb_msgval msgval = upb_array_get(self->array, i);
+    upb_MessageValue msgval = upb_Array_Get(self->array, i);
     VALUE val = Convert_UpbToRuby(msgval, self->type_info, self->arena);
     rb_ary_push(ary, val);
   }
@@ -473,17 +473,17 @@
 
   self = ruby_to_RepeatedField(_self);
   other = ruby_to_RepeatedField(_other);
-  size_t n = upb_array_size(self->array);
+  size_t n = upb_Array_Size(self->array);
 
   if (self->type_info.type != other->type_info.type ||
       self->type_class != other->type_class ||
-      upb_array_size(other->array) != n) {
+      upb_Array_Size(other->array) != n) {
     return Qfalse;
   }
 
   for (size_t i = 0; i < n; i++) {
-    upb_msgval val1 = upb_array_get(self->array, i);
-    upb_msgval val2 = upb_array_get(other->array, i);
+    upb_MessageValue val1 = upb_Array_Get(self->array, i);
+    upb_MessageValue val2 = upb_Array_Get(other->array, i);
     if (!Msgval_IsEqual(val1, val2, self->type_info)) {
       return Qfalse;
     }
@@ -517,10 +517,10 @@
 VALUE RepeatedField_hash(VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
   uint64_t hash = 0;
-  size_t n = upb_array_size(self->array);
+  size_t n = upb_Array_Size(self->array);
 
   for (size_t i = 0; i < n; i++) {
-    upb_msgval val = upb_array_get(self->array, i);
+    upb_MessageValue val = upb_Array_Get(self->array, i);
     hash = Msgval_GetHash(val, self->type_info, hash);
   }
 
@@ -549,10 +549,10 @@
     RepeatedField* self = ruby_to_RepeatedField(_self);
     RepeatedField* list_rptfield = ruby_to_RepeatedField(list);
     RepeatedField* dupped = ruby_to_RepeatedField(dupped_);
-    upb_array *dupped_array = RepeatedField_GetMutable(dupped_);
-    upb_arena* arena = Arena_get(dupped->arena);
+    upb_Array* dupped_array = RepeatedField_GetMutable(dupped_);
+    upb_Arena* arena = Arena_get(dupped->arena);
     Arena_fuse(list_rptfield->arena, arena);
-    int size = upb_array_size(list_rptfield->array);
+    int size = upb_Array_Size(list_rptfield->array);
     int i;
 
     if (self->type_info.type != list_rptfield->type_info.type ||
@@ -562,8 +562,8 @@
     }
 
     for (i = 0; i < size; i++) {
-      upb_msgval msgval = upb_array_get(list_rptfield->array, i);
-      upb_array_append(dupped_array, msgval, arena);
+      upb_MessageValue msgval = upb_Array_Get(list_rptfield->array, i);
+      upb_Array_Append(dupped_array, msgval, arena);
     }
   } else {
     rb_raise(rb_eArgError, "Unknown type appending to RepeatedField");
@@ -601,7 +601,7 @@
  */
 VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
   RepeatedField* self = ruby_to_RepeatedField(_self);
-  upb_arena *arena;
+  upb_Arena* arena;
   VALUE ary = Qnil;
 
   self->arena = Arena_new();
@@ -612,7 +612,7 @@
   }
 
   self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
-  self->array = upb_array_new(arena, self->type_info.type);
+  self->array = upb_Array_New(arena, self->type_info.type);
   ObjectCache_Add(self->array, _self);
 
   if (ary != Qnil) {
@@ -627,14 +627,12 @@
 }
 
 void RepeatedField_register(VALUE module) {
-  VALUE klass = rb_define_class_under(
-      module, "RepeatedField", rb_cObject);
+  VALUE klass = rb_define_class_under(module, "RepeatedField", rb_cObject);
   rb_define_alloc_func(klass, RepeatedField_alloc);
   rb_gc_register_address(&cRepeatedField);
   cRepeatedField = klass;
 
-  rb_define_method(klass, "initialize",
-                   RepeatedField_init, -1);
+  rb_define_method(klass, "initialize", RepeatedField_init, -1);
   rb_define_method(klass, "each", RepeatedField_each, 0);
   rb_define_method(klass, "[]", RepeatedField_index, -1);
   rb_define_method(klass, "at", RepeatedField_index, -1);
diff --git a/ruby/ext/google/protobuf_c/repeated_field.h b/ruby/ext/google/protobuf_c/repeated_field.h
index e4ef252..b058163 100644
--- a/ruby/ext/google/protobuf_c/repeated_field.h
+++ b/ruby/ext/google/protobuf_c/repeated_field.h
@@ -36,19 +36,19 @@
 #include "protobuf.h"
 #include "ruby-upb.h"
 
-// Returns a Ruby wrapper object for the given upb_array, which will be created
+// Returns a Ruby wrapper object for the given upb_Array, which will be created
 // if one does not exist already.
-VALUE RepeatedField_GetRubyWrapper(upb_array* msg, TypeInfo type_info,
+VALUE RepeatedField_GetRubyWrapper(upb_Array* msg, TypeInfo type_info,
                                    VALUE arena);
 
-// Gets the underlying upb_array for this Ruby RepeatedField object, which must
+// Gets the underlying upb_Array for this Ruby RepeatedField object, which must
 // have a type that matches |f|. If this is not a repeated field or the type
 // doesn't match, raises an exception.
-const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f,
-                                           upb_arena* arena);
+const upb_Array* RepeatedField_GetUpbArray(VALUE value, const upb_FieldDef* f,
+                                           upb_Arena* arena);
 
 // Implements #inspect for this repeated field by appending its contents to |b|.
-void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,
+void RepeatedField_Inspect(StringBuilder* b, const upb_Array* array,
                            TypeInfo info);
 
 // Returns a deep copy of this RepeatedField object.
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c
index d68caac..15f2224 100755
--- a/ruby/ext/google/protobuf_c/ruby-upb.c
+++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -264,25 +264,25 @@
 
 /* Maps descriptor type -> elem_size_lg2.  */
 static const uint8_t desctype_to_elem_size_lg2[] = {
-    -1,               /* invalid descriptor type */
-    3,  /* DOUBLE */
-    2,   /* FLOAT */
-    3,   /* INT64 */
-    3,  /* UINT64 */
-    2,   /* INT32 */
-    3,  /* FIXED64 */
-    2,  /* FIXED32 */
-    0,    /* BOOL */
-    UPB_SIZE(3, 4),  /* STRING */
-    UPB_SIZE(2, 3),  /* GROUP */
-    UPB_SIZE(2, 3),  /* MESSAGE */
-    UPB_SIZE(3, 4),  /* BYTES */
-    2,  /* UINT32 */
-    2,    /* ENUM */
-    2,   /* SFIXED32 */
-    3,   /* SFIXED64 */
-    2,   /* SINT32 */
-    3,   /* SINT64 */
+    -1,             /* invalid descriptor type */
+    3,              /* DOUBLE */
+    2,              /* FLOAT */
+    3,              /* INT64 */
+    3,              /* UINT64 */
+    2,              /* INT32 */
+    3,              /* FIXED64 */
+    2,              /* FIXED32 */
+    0,              /* BOOL */
+    UPB_SIZE(3, 4), /* STRING */
+    UPB_SIZE(2, 3), /* GROUP */
+    UPB_SIZE(2, 3), /* MESSAGE */
+    UPB_SIZE(3, 4), /* BYTES */
+    2,              /* UINT32 */
+    2,              /* ENUM */
+    2,              /* SFIXED32 */
+    3,              /* SFIXED64 */
+    2,              /* SINT32 */
+    3,              /* SINT64 */
 };
 
 /* Maps descriptor type -> upb map size.  */
@@ -297,8 +297,8 @@
     4,                  /* FIXED32 */
     1,                  /* BOOL */
     UPB_MAPTYPE_STRING, /* STRING */
-    sizeof(void *),     /* GROUP */
-    sizeof(void *),     /* MESSAGE */
+    sizeof(void*),      /* GROUP */
+    sizeof(void*),      /* MESSAGE */
     UPB_MAPTYPE_STRING, /* BYTES */
     4,                  /* UINT32 */
     4,                  /* ENUM */
@@ -308,66 +308,80 @@
     8,                  /* SINT64 */
 };
 
-static const unsigned fixed32_ok = (1 << UPB_DTYPE_FLOAT) |
-                                   (1 << UPB_DTYPE_FIXED32) |
-                                   (1 << UPB_DTYPE_SFIXED32);
+static const unsigned FIXED32_OK_MASK = (1 << kUpb_FieldType_Float) |
+                                        (1 << kUpb_FieldType_Fixed32) |
+                                        (1 << kUpb_FieldType_SFixed32);
 
-static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) |
-                                   (1 << UPB_DTYPE_FIXED64) |
-                                   (1 << UPB_DTYPE_SFIXED64);
+static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) |
+                                        (1 << kUpb_FieldType_Fixed64) |
+                                        (1 << kUpb_FieldType_SFixed64);
+
+/* Three fake field types for MessageSet. */
+#define TYPE_MSGSET_ITEM 19
+#define TYPE_MSGSET_TYPE_ID 20
+#define TYPE_COUNT 20
 
 /* Op: an action to be performed for a wire-type/field-type combination. */
-#define OP_SCALAR_LG2(n) (n)      /* n in [0, 2, 3] => op in [0, 2, 3] */
+#define OP_UNKNOWN -1 /* Unknown field. */
+#define OP_MSGSET_ITEM -2
+#define OP_MSGSET_TYPEID -3
+#define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */
+#define OP_ENUM 1
 #define OP_STRING 4
 #define OP_BYTES 5
 #define OP_SUBMSG 6
-/* Ops above are scalar-only. Repeated fields can use any op.  */
-#define OP_FIXPCK_LG2(n) (n + 5)  /* n in [2, 3] => op in [7, 8] */
-#define OP_VARPCK_LG2(n) (n + 9)  /* n in [0, 2, 3] => op in [9, 11, 12] */
+/* Scalar fields use only ops above. Repeated fields can use any op.  */
+#define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */
+#define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */
+#define OP_PACKED_ENUM 13
 
-static const int8_t varint_ops[19] = {
-    -1,               /* field not found */
-    -1,               /* DOUBLE */
-    -1,               /* FLOAT */
+static const int8_t varint_ops[] = {
+    OP_UNKNOWN,       /* field not found */
+    OP_UNKNOWN,       /* DOUBLE */
+    OP_UNKNOWN,       /* FLOAT */
     OP_SCALAR_LG2(3), /* INT64 */
     OP_SCALAR_LG2(3), /* UINT64 */
     OP_SCALAR_LG2(2), /* INT32 */
-    -1,               /* FIXED64 */
-    -1,               /* FIXED32 */
+    OP_UNKNOWN,       /* FIXED64 */
+    OP_UNKNOWN,       /* FIXED32 */
     OP_SCALAR_LG2(0), /* BOOL */
-    -1,               /* STRING */
-    -1,               /* GROUP */
-    -1,               /* MESSAGE */
-    -1,               /* BYTES */
+    OP_UNKNOWN,       /* STRING */
+    OP_UNKNOWN,       /* GROUP */
+    OP_UNKNOWN,       /* MESSAGE */
+    OP_UNKNOWN,       /* BYTES */
     OP_SCALAR_LG2(2), /* UINT32 */
-    OP_SCALAR_LG2(2), /* ENUM */
-    -1,               /* SFIXED32 */
-    -1,               /* SFIXED64 */
+    OP_ENUM,          /* ENUM */
+    OP_UNKNOWN,       /* SFIXED32 */
+    OP_UNKNOWN,       /* SFIXED64 */
     OP_SCALAR_LG2(2), /* SINT32 */
     OP_SCALAR_LG2(3), /* SINT64 */
+    OP_UNKNOWN,       /* MSGSET_ITEM */
+    OP_MSGSET_TYPEID, /* MSGSET TYPEID */
 };
 
-static const int8_t delim_ops[37] = {
+static const int8_t delim_ops[] = {
     /* For non-repeated field type. */
-    -1,        /* field not found */
-    -1,        /* DOUBLE */
-    -1,        /* FLOAT */
-    -1,        /* INT64 */
-    -1,        /* UINT64 */
-    -1,        /* INT32 */
-    -1,        /* FIXED64 */
-    -1,        /* FIXED32 */
-    -1,        /* BOOL */
-    OP_STRING, /* STRING */
-    -1,        /* GROUP */
-    OP_SUBMSG, /* MESSAGE */
-    OP_BYTES,  /* BYTES */
-    -1,        /* UINT32 */
-    -1,        /* ENUM */
-    -1,        /* SFIXED32 */
-    -1,        /* SFIXED64 */
-    -1,        /* SINT32 */
-    -1,        /* SINT64 */
+    OP_UNKNOWN, /* field not found */
+    OP_UNKNOWN, /* DOUBLE */
+    OP_UNKNOWN, /* FLOAT */
+    OP_UNKNOWN, /* INT64 */
+    OP_UNKNOWN, /* UINT64 */
+    OP_UNKNOWN, /* INT32 */
+    OP_UNKNOWN, /* FIXED64 */
+    OP_UNKNOWN, /* FIXED32 */
+    OP_UNKNOWN, /* BOOL */
+    OP_STRING,  /* STRING */
+    OP_UNKNOWN, /* GROUP */
+    OP_SUBMSG,  /* MESSAGE */
+    OP_BYTES,   /* BYTES */
+    OP_UNKNOWN, /* UINT32 */
+    OP_UNKNOWN, /* ENUM */
+    OP_UNKNOWN, /* SFIXED32 */
+    OP_UNKNOWN, /* SFIXED64 */
+    OP_UNKNOWN, /* SINT32 */
+    OP_UNKNOWN, /* SINT64 */
+    OP_UNKNOWN, /* MSGSET_ITEM */
+    OP_UNKNOWN, /* MSGSET TYPEID */
     /* For repeated field type. */
     OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */
     OP_FIXPCK_LG2(2), /* REPEATED FLOAT */
@@ -382,11 +396,12 @@
     OP_SUBMSG,        /* REPEATED MESSAGE */
     OP_BYTES,         /* REPEATED BYTES */
     OP_VARPCK_LG2(2), /* REPEATED UINT32 */
-    OP_VARPCK_LG2(2), /* REPEATED ENUM */
+    OP_PACKED_ENUM,   /* REPEATED ENUM */
     OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */
     OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */
     OP_VARPCK_LG2(2), /* REPEATED SINT32 */
     OP_VARPCK_LG2(3), /* REPEATED SINT64 */
+    /* Omitting MSGSET_*, because we never emit a repeated msgset type */
 };
 
 typedef union {
@@ -396,61 +411,39 @@
   uint32_t size;
 } wireval;
 
-static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
-                              const upb_msglayout *layout);
+static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg,
+                              const upb_MiniTable* layout);
 
-UPB_NORETURN static void decode_err(upb_decstate *d) { UPB_LONGJMP(d->err, 1); }
+UPB_NORETURN static void* decode_err(upb_Decoder* d, upb_DecodeStatus status) {
+  assert(status != kUpb_DecodeStatus_Ok);
+  UPB_LONGJMP(d->err, status);
+}
 
-// We don't want to mark this NORETURN, see comment in .h.
-// Unfortunately this code to suppress the warning doesn't appear to be working.
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunknown-warning-option"
-#pragma clang diagnostic ignored "-Wsuggest-attribute"
-#endif
-
-const char *fastdecode_err(upb_decstate *d) {
-  longjmp(d->err, 1);
+const char* fastdecode_err(upb_Decoder* d, int status) {
+  assert(status != kUpb_DecodeStatus_Ok);
+  UPB_LONGJMP(d->err, status);
   return NULL;
 }
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-const uint8_t upb_utf8_offsets[] = {
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-    4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void decode_verifyutf8(upb_decstate *d, const char *buf, int len) {
-  if (!decode_verifyutf8_inl(buf, len)) decode_err(d);
+static void decode_verifyutf8(upb_Decoder* d, const char* buf, int len) {
+  if (!decode_verifyutf8_inl(buf, len))
+    decode_err(d, kUpb_DecodeStatus_BadUtf8);
 }
 
-static bool decode_reserve(upb_decstate *d, upb_array *arr, size_t elem) {
+static bool decode_reserve(upb_Decoder* d, upb_Array* arr, size_t elem) {
   bool need_realloc = arr->size - arr->len < elem;
   if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, &d->arena)) {
-    decode_err(d);
+    decode_err(d, kUpb_DecodeStatus_OutOfMemory);
   }
   return need_realloc;
 }
 
 typedef struct {
-  const char *ptr;
+  const char* ptr;
   uint64_t val;
 } decode_vret;
 
 UPB_NOINLINE
-static decode_vret decode_longvarint64(const char *ptr, uint64_t val) {
+static decode_vret decode_longvarint64(const char* ptr, uint64_t val) {
   decode_vret ret = {NULL, 0};
   uint64_t byte;
   int i;
@@ -467,120 +460,92 @@
 }
 
 UPB_FORCEINLINE
-static const char *decode_varint64(upb_decstate *d, const char *ptr,
-                                   uint64_t *val) {
+static const char* decode_varint64(upb_Decoder* d, const char* ptr,
+                                   uint64_t* val) {
   uint64_t byte = (uint8_t)*ptr;
   if (UPB_LIKELY((byte & 0x80) == 0)) {
     *val = byte;
     return ptr + 1;
   } else {
     decode_vret res = decode_longvarint64(ptr, byte);
-    if (!res.ptr) decode_err(d);
+    if (!res.ptr) return decode_err(d, kUpb_DecodeStatus_Malformed);
     *val = res.val;
     return res.ptr;
   }
 }
 
 UPB_FORCEINLINE
-static const char *decode_tag(upb_decstate *d, const char *ptr,
-                                   uint32_t *val) {
+static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) {
   uint64_t byte = (uint8_t)*ptr;
   if (UPB_LIKELY((byte & 0x80) == 0)) {
     *val = byte;
     return ptr + 1;
   } else {
-    const char *start = ptr;
+    const char* start = ptr;
     decode_vret res = decode_longvarint64(ptr, byte);
-    ptr = res.ptr;
+    if (!res.ptr || res.ptr - start > 5 || res.val > UINT32_MAX) {
+      return decode_err(d, kUpb_DecodeStatus_Malformed);
+    }
     *val = res.val;
-    if (!ptr || *val > UINT32_MAX || ptr - start > 5) decode_err(d);
-    return ptr;
+    return res.ptr;
   }
 }
 
-static void decode_munge(int type, wireval *val) {
+static void decode_munge_int32(wireval* val) {
+  if (!_upb_IsLittleEndian()) {
+    /* The next stage will memcpy(dst, &val, 4) */
+    val->uint32_val = val->uint64_val;
+  }
+}
+
+static void decode_munge(int type, wireval* val) {
   switch (type) {
-    case UPB_DESCRIPTOR_TYPE_BOOL:
+    case kUpb_FieldType_Bool:
       val->bool_val = val->uint64_val != 0;
       break;
-    case UPB_DESCRIPTOR_TYPE_SINT32: {
-      uint32_t n = val->uint32_val;
+    case kUpb_FieldType_SInt32: {
+      uint32_t n = val->uint64_val;
       val->uint32_val = (n >> 1) ^ -(int32_t)(n & 1);
       break;
     }
-    case UPB_DESCRIPTOR_TYPE_SINT64: {
+    case kUpb_FieldType_SInt64: {
       uint64_t n = val->uint64_val;
       val->uint64_val = (n >> 1) ^ -(int64_t)(n & 1);
       break;
     }
-    case UPB_DESCRIPTOR_TYPE_INT32:
-    case UPB_DESCRIPTOR_TYPE_UINT32:
-      if (!_upb_isle()) {
-        /* The next stage will memcpy(dst, &val, 4) */
-        val->uint32_val = val->uint64_val;
-      }
+    case kUpb_FieldType_Int32:
+    case kUpb_FieldType_UInt32:
+    case kUpb_FieldType_Enum:
+      decode_munge_int32(val);
       break;
   }
 }
 
-static const upb_msglayout_field *upb_find_field(const upb_msglayout *l,
-                                                 uint32_t field_number,
-                                                 int *last_field_index) {
-  static upb_msglayout_field none = {0, 0, 0, 0, 0, 0};
-
-  if (l == NULL) return &none;
-
-  size_t idx = ((size_t)field_number) - 1;  // 0 wraps to SIZE_MAX
-  if (idx < l->dense_below) {
-    goto found;
-  }
-
-  /* Resume scanning from last_field_index since fields are usually in order. */
-  int last = *last_field_index;
-  for (idx = last; idx < l->field_count; idx++) {
-    if (l->fields[idx].number == field_number) {
-      goto found;
-    }
-  }
-
-  for (idx = 0; idx < last; idx++) {
-    if (l->fields[idx].number == field_number) {
-      goto found;
-    }
-  }
-
-  return &none; /* Unknown field. */
-
- found:
-  UPB_ASSERT(l->fields[idx].number == field_number);
-  *last_field_index = idx;
-  return &l->fields[idx];
-}
-
-static upb_msg *decode_newsubmsg(upb_decstate *d,
-                                 upb_msglayout const *const *submsgs,
-                                 const upb_msglayout_field *field) {
-  const upb_msglayout *subl = submsgs[field->submsg_index];
-  return _upb_msg_new_inl(subl, &d->arena);
+static upb_Message* decode_newsubmsg(upb_Decoder* d,
+                                     const upb_MiniTable_Sub* subs,
+                                     const upb_MiniTable_Field* field) {
+  const upb_MiniTable* subl = subs[field->submsg_index].submsg;
+  return _upb_Message_New_inl(subl, &d->arena);
 }
 
 UPB_NOINLINE
-const char *decode_isdonefallback(upb_decstate *d, const char *ptr,
+const char* decode_isdonefallback(upb_Decoder* d, const char* ptr,
                                   int overrun) {
-  ptr = decode_isdonefallback_inl(d, ptr, overrun);
+  int status;
+  ptr = decode_isdonefallback_inl(d, ptr, overrun, &status);
   if (ptr == NULL) {
-    decode_err(d);
+    return decode_err(d, status);
   }
   return ptr;
 }
 
-static const char *decode_readstr(upb_decstate *d, const char *ptr, int size,
-                                  upb_strview *str) {
-  if (d->alias) {
+static const char* decode_readstr(upb_Decoder* d, const char* ptr, int size,
+                                  upb_StringView* str) {
+  if (d->options & kUpb_DecodeOption_AliasString) {
     str->data = ptr;
   } else {
-    char *data =  upb_arena_malloc(&d->arena, size);
-    if (!data) decode_err(d);
+    char* data = upb_Arena_Malloc(&d->arena, size);
+    if (!data) return decode_err(d, kUpb_DecodeStatus_OutOfMemory);
     memcpy(data, ptr, size);
     str->data = data;
   }
@@ -589,61 +554,222 @@
 }
 
 UPB_FORCEINLINE
-static const char *decode_tosubmsg(upb_decstate *d, const char *ptr,
-                                   upb_msg *submsg, 
-                                   upb_msglayout const *const *submsgs,
-                                   const upb_msglayout_field *field, int size) {
-  const upb_msglayout *subl = submsgs[field->submsg_index];
+static const char* decode_tosubmsg2(upb_Decoder* d, const char* ptr,
+                                    upb_Message* submsg,
+                                    const upb_MiniTable* subl, int size) {
   int saved_delta = decode_pushlimit(d, ptr, size);
-  if (--d->depth < 0) decode_err(d);
-  if (!decode_isdone(d, &ptr)) {
-    ptr = decode_msg(d, ptr, submsg, subl);
-  }
-  if (d->end_group != DECODE_NOGROUP) decode_err(d);
+  if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded);
+  ptr = decode_msg(d, ptr, submsg, subl);
+  if (d->end_group != DECODE_NOGROUP)
+    return decode_err(d, kUpb_DecodeStatus_Malformed);
   decode_poplimit(d, ptr, saved_delta);
   d->depth++;
   return ptr;
 }
 
 UPB_FORCEINLINE
-static const char *decode_group(upb_decstate *d, const char *ptr,
-                                upb_msg *submsg, const upb_msglayout *subl,
+static const char* decode_tosubmsg(upb_Decoder* d, const char* ptr,
+                                   upb_Message* submsg,
+                                   const upb_MiniTable_Sub* subs,
+                                   const upb_MiniTable_Field* field, int size) {
+  return decode_tosubmsg2(d, ptr, submsg, subs[field->submsg_index].submsg,
+                          size);
+}
+
+UPB_FORCEINLINE
+static const char* decode_group(upb_Decoder* d, const char* ptr,
+                                upb_Message* submsg, const upb_MiniTable* subl,
                                 uint32_t number) {
-  if (--d->depth < 0) decode_err(d);
+  if (--d->depth < 0) return decode_err(d, kUpb_DecodeStatus_MaxDepthExceeded);
   if (decode_isdone(d, &ptr)) {
-    decode_err(d);
+    return decode_err(d, kUpb_DecodeStatus_Malformed);
   }
   ptr = decode_msg(d, ptr, submsg, subl);
-  if (d->end_group != number) decode_err(d);
+  if (d->end_group != number) return decode_err(d, kUpb_DecodeStatus_Malformed);
   d->end_group = DECODE_NOGROUP;
   d->depth++;
   return ptr;
 }
 
 UPB_FORCEINLINE
-static const char *decode_togroup(upb_decstate *d, const char *ptr,
-                                  upb_msg *submsg,
-                                  upb_msglayout const *const *submsgs,
-                                  const upb_msglayout_field *field) {
-  const upb_msglayout *subl = submsgs[field->submsg_index];
+static const char* decode_togroup(upb_Decoder* d, const char* ptr,
+                                  upb_Message* submsg,
+                                  const upb_MiniTable_Sub* subs,
+                                  const upb_MiniTable_Field* field) {
+  const upb_MiniTable* subl = subs[field->submsg_index].submsg;
   return decode_group(d, ptr, submsg, subl, field->number);
 }
 
-static const char *decode_toarray(upb_decstate *d, const char *ptr,
-                                  upb_msg *msg,
-                                  upb_msglayout const *const *submsgs,
-                                  const upb_msglayout_field *field, wireval *val,
-                                  int op) {
-  upb_array **arrp = UPB_PTR_AT(msg, field->offset, void);
-  upb_array *arr = *arrp;
-  void *mem;
+static char* encode_varint32(uint32_t val, char* ptr) {
+  do {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val) byte |= 0x80U;
+    *(ptr++) = byte;
+  } while (val);
+  return ptr;
+}
+
+UPB_NOINLINE
+static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr,
+                                  upb_Message* msg, const upb_MiniTable_Enum* e,
+                                  const upb_MiniTable_Field* field,
+                                  uint32_t v) {
+  // OPT: binary search long lists?
+  int n = e->value_count;
+  for (int i = 0; i < n; i++) {
+    if ((uint32_t)e->values[i] == v) return true;
+  }
+
+  // Unrecognized enum goes into unknown fields.
+  // For packed fields the tag could be arbitrarily far in the past, so we
+  // just re-encode the tag here.
+  char buf[20];
+  char* end = buf;
+  uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint;
+  end = encode_varint32(tag, end);
+  end = encode_varint32(v, end);
+
+  if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) {
+    decode_err(d, kUpb_DecodeStatus_OutOfMemory);
+  }
+
+  return false;
+}
+
+UPB_FORCEINLINE
+static bool decode_checkenum(upb_Decoder* d, const char* ptr, upb_Message* msg,
+                             const upb_MiniTable_Enum* e,
+                             const upb_MiniTable_Field* field, wireval* val) {
+  uint32_t v = val->uint32_val;
+
+  if (UPB_LIKELY(v < 64) && UPB_LIKELY(((1ULL << v) & e->mask))) return true;
+
+  return decode_checkenum_slow(d, ptr, msg, e, field, v);
+}
+
+UPB_NOINLINE
+static const char* decode_enum_toarray(upb_Decoder* d, const char* ptr,
+                                       upb_Message* msg, upb_Array* arr,
+                                       const upb_MiniTable_Sub* subs,
+                                       const upb_MiniTable_Field* field,
+                                       wireval* val) {
+  const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum;
+  if (!decode_checkenum(d, ptr, msg, e, field, val)) return ptr;
+  void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void);
+  arr->len++;
+  memcpy(mem, val, 4);
+  return ptr;
+}
+
+UPB_FORCEINLINE
+static const char* decode_fixed_packed(upb_Decoder* d, const char* ptr,
+                                       upb_Array* arr, wireval* val,
+                                       const upb_MiniTable_Field* field,
+                                       int lg2) {
+  int mask = (1 << lg2) - 1;
+  size_t count = val->size >> lg2;
+  if ((val->size & mask) != 0) {
+    // Length isn't a round multiple of elem size.
+    return decode_err(d, kUpb_DecodeStatus_Malformed);
+  }
+  decode_reserve(d, arr, count);
+  void* mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+  arr->len += count;
+  // Note: if/when the decoder supports multi-buffer input, we will need to
+  // handle buffer seams here.
+  if (_upb_IsLittleEndian()) {
+    memcpy(mem, ptr, val->size);
+    ptr += val->size;
+  } else {
+    const char* end = ptr + val->size;
+    char* dst = mem;
+    while (ptr < end) {
+      if (lg2 == 2) {
+        uint32_t val;
+        memcpy(&val, ptr, sizeof(val));
+        val = _upb_BigEndian_Swap32(val);
+        memcpy(dst, &val, sizeof(val));
+      } else {
+        UPB_ASSERT(lg2 == 3);
+        uint64_t val;
+        memcpy(&val, ptr, sizeof(val));
+        val = _upb_BigEndian_Swap64(val);
+        memcpy(dst, &val, sizeof(val));
+      }
+      ptr += 1 << lg2;
+      dst += 1 << lg2;
+    }
+  }
+
+  return ptr;
+}
+
+UPB_FORCEINLINE
+static const char* decode_varint_packed(upb_Decoder* d, const char* ptr,
+                                        upb_Array* arr, wireval* val,
+                                        const upb_MiniTable_Field* field,
+                                        int lg2) {
+  int scale = 1 << lg2;
+  int saved_limit = decode_pushlimit(d, ptr, val->size);
+  char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+  while (!decode_isdone(d, &ptr)) {
+    wireval elem;
+    ptr = decode_varint64(d, ptr, &elem.uint64_val);
+    decode_munge(field->descriptortype, &elem);
+    if (decode_reserve(d, arr, 1)) {
+      out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
+    }
+    arr->len++;
+    memcpy(out, &elem, scale);
+    out += scale;
+  }
+  decode_poplimit(d, ptr, saved_limit);
+  return ptr;
+}
+
+UPB_NOINLINE
+static const char* decode_enum_packed(upb_Decoder* d, const char* ptr,
+                                      upb_Message* msg, upb_Array* arr,
+                                      const upb_MiniTable_Sub* subs,
+                                      const upb_MiniTable_Field* field,
+                                      wireval* val) {
+  const upb_MiniTable_Enum* e = subs[field->submsg_index].subenum;
+  int saved_limit = decode_pushlimit(d, ptr, val->size);
+  char* out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void);
+  while (!decode_isdone(d, &ptr)) {
+    wireval elem;
+    ptr = decode_varint64(d, ptr, &elem.uint64_val);
+    decode_munge_int32(&elem);
+    if (!decode_checkenum(d, ptr, msg, e, field, &elem)) {
+      continue;
+    }
+    if (decode_reserve(d, arr, 1)) {
+      out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len * 4, void);
+    }
+    arr->len++;
+    memcpy(out, &elem, 4);
+    out += 4;
+  }
+  decode_poplimit(d, ptr, saved_limit);
+  return ptr;
+}
+
+static const char* decode_toarray(upb_Decoder* d, const char* ptr,
+                                  upb_Message* msg,
+                                  const upb_MiniTable_Sub* subs,
+                                  const upb_MiniTable_Field* field,
+                                  wireval* val, int op) {
+  upb_Array** arrp = UPB_PTR_AT(msg, field->offset, void);
+  upb_Array* arr = *arrp;
+  void* mem;
 
   if (arr) {
     decode_reserve(d, arr, 1);
   } else {
     size_t lg2 = desctype_to_elem_size_lg2[field->descriptortype];
-    arr = _upb_array_new(&d->arena, 4, lg2);
-    if (!arr) decode_err(d);
+    arr = _upb_Array_New(&d->arena, 4, lg2);
+    if (!arr) return decode_err(d, kUpb_DecodeStatus_OutOfMemory);
     *arrp = arr;
   }
 
@@ -661,111 +787,95 @@
       /* Fallthrough. */
     case OP_BYTES: {
       /* Append bytes. */
-      upb_strview *str = (upb_strview*)_upb_array_ptr(arr) + arr->len;
+      upb_StringView* str = (upb_StringView*)_upb_array_ptr(arr) + arr->len;
       arr->len++;
       return decode_readstr(d, ptr, val->size, str);
     }
     case OP_SUBMSG: {
       /* Append submessage / group. */
-      upb_msg *submsg = decode_newsubmsg(d, submsgs, field);
-      *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void *), upb_msg *) =
+      upb_Message* submsg = decode_newsubmsg(d, subs, field);
+      *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void*), upb_Message*) =
           submsg;
       arr->len++;
-      if (UPB_UNLIKELY(field->descriptortype == UPB_DTYPE_GROUP)) {
-        return decode_togroup(d, ptr, submsg, submsgs, field);
+      if (UPB_UNLIKELY(field->descriptortype == kUpb_FieldType_Group)) {
+        return decode_togroup(d, ptr, submsg, subs, field);
       } else {
-        return decode_tosubmsg(d, ptr, submsg, submsgs, field, val->size);
+        return decode_tosubmsg(d, ptr, submsg, subs, field, val->size);
       }
     }
     case OP_FIXPCK_LG2(2):
-    case OP_FIXPCK_LG2(3): {
-      /* Fixed packed. */
-      int lg2 = op - OP_FIXPCK_LG2(0);
-      int mask = (1 << lg2) - 1;
-      size_t count = val->size >> lg2;
-      if ((val->size & mask) != 0) {
-        decode_err(d); /* Length isn't a round multiple of elem size. */
-      }
-      decode_reserve(d, arr, count);
-      mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
-      arr->len += count;
-      memcpy(mem, ptr, val->size);  /* XXX: ptr boundary. */
-      return ptr + val->size;
-    }
+    case OP_FIXPCK_LG2(3):
+      return decode_fixed_packed(d, ptr, arr, val, field,
+                                 op - OP_FIXPCK_LG2(0));
     case OP_VARPCK_LG2(0):
     case OP_VARPCK_LG2(2):
-    case OP_VARPCK_LG2(3): {
-      /* Varint packed. */
-      int lg2 = op - OP_VARPCK_LG2(0);
-      int scale = 1 << lg2;
-      int saved_limit = decode_pushlimit(d, ptr, val->size);
-      char *out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
-      while (!decode_isdone(d, &ptr)) {
-        wireval elem;
-        ptr = decode_varint64(d, ptr, &elem.uint64_val);
-        decode_munge(field->descriptortype, &elem);
-        if (decode_reserve(d, arr, 1)) {
-          out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void);
-        }
-        arr->len++;
-        memcpy(out, &elem, scale);
-        out += scale;
-      }
-      decode_poplimit(d, ptr, saved_limit);
-      return ptr;
-    }
+    case OP_VARPCK_LG2(3):
+      return decode_varint_packed(d, ptr, arr, val, field,
+                                  op - OP_VARPCK_LG2(0));
+    case OP_ENUM:
+      return decode_enum_toarray(d, ptr, msg, arr, subs, field, val);
+    case OP_PACKED_ENUM:
+      return decode_enum_packed(d, ptr, msg, arr, subs, field, val);
     default:
       UPB_UNREACHABLE();
   }
 }
 
-static const char *decode_tomap(upb_decstate *d, const char *ptr, upb_msg *msg,
-                                upb_msglayout const *const *submsgs,
-                                const upb_msglayout_field *field, wireval *val) {
-  upb_map **map_p = UPB_PTR_AT(msg, field->offset, upb_map *);
-  upb_map *map = *map_p;
-  upb_map_entry ent;
-  const upb_msglayout *entry = submsgs[field->submsg_index];
+static const char* decode_tomap(upb_Decoder* d, const char* ptr,
+                                upb_Message* msg, const upb_MiniTable_Sub* subs,
+                                const upb_MiniTable_Field* field,
+                                wireval* val) {
+  upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*);
+  upb_Map* map = *map_p;
+  upb_MapEntry ent;
+  const upb_MiniTable* entry = subs[field->submsg_index].submsg;
 
   if (!map) {
     /* Lazily create map. */
-    const upb_msglayout_field *key_field = &entry->fields[0];
-    const upb_msglayout_field *val_field = &entry->fields[1];
+    const upb_MiniTable_Field* key_field = &entry->fields[0];
+    const upb_MiniTable_Field* val_field = &entry->fields[1];
     char key_size = desctype_to_mapsize[key_field->descriptortype];
     char val_size = desctype_to_mapsize[val_field->descriptortype];
     UPB_ASSERT(key_field->offset == 0);
-    UPB_ASSERT(val_field->offset == sizeof(upb_strview));
-    map = _upb_map_new(&d->arena, key_size, val_size);
+    UPB_ASSERT(val_field->offset == sizeof(upb_StringView));
+    map = _upb_Map_New(&d->arena, key_size, val_size);
     *map_p = map;
   }
 
   /* Parse map entry. */
   memset(&ent, 0, sizeof(ent));
 
-  if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE ||
-      entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) {
+  if (entry->fields[1].descriptortype == kUpb_FieldType_Message ||
+      entry->fields[1].descriptortype == kUpb_FieldType_Group) {
     /* Create proactively to handle the case where it doesn't appear. */
-    ent.v.val = upb_value_ptr(_upb_msg_new(entry->submsgs[0], &d->arena));
+    ent.v.val =
+        upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena));
   }
 
-  ptr = decode_tosubmsg(d, ptr, &ent.k, submsgs, field, val->size);
-  _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena);
+  ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size);
+  _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena);
   return ptr;
 }
 
-static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg,
-                                upb_msglayout const *const *submsgs,
-                                const upb_msglayout_field *field, wireval *val,
+static const char* decode_tomsg(upb_Decoder* d, const char* ptr,
+                                upb_Message* msg, const upb_MiniTable_Sub* subs,
+                                const upb_MiniTable_Field* field, wireval* val,
                                 int op) {
-  void *mem = UPB_PTR_AT(msg, field->offset, void);
+  void* mem = UPB_PTR_AT(msg, field->offset, void);
   int type = field->descriptortype;
 
+  if (UPB_UNLIKELY(op == OP_ENUM) &&
+      !decode_checkenum(d, ptr, msg, subs[field->submsg_index].subenum, field,
+                        val)) {
+    return ptr;
+  }
+
   /* Set presence if necessary. */
   if (field->presence > 0) {
     _upb_sethas_field(msg, field);
   } else if (field->presence < 0) {
     /* Oneof case */
-    uint32_t *oneof_case = _upb_oneofcase_field(msg, field);
+    uint32_t* oneof_case = _upb_oneofcase_field(msg, field);
     if (op == OP_SUBMSG && *oneof_case != field->number) {
       memset(mem, 0, sizeof(void*));
     }
@@ -775,16 +885,16 @@
   /* Store into message. */
   switch (op) {
     case OP_SUBMSG: {
-      upb_msg **submsgp = mem;
-      upb_msg *submsg = *submsgp;
+      upb_Message** submsgp = mem;
+      upb_Message* submsg = *submsgp;
       if (!submsg) {
-        submsg = decode_newsubmsg(d, submsgs, field);
+        submsg = decode_newsubmsg(d, subs, field);
         *submsgp = submsg;
       }
-      if (UPB_UNLIKELY(type == UPB_DTYPE_GROUP)) {
-        ptr = decode_togroup(d, ptr, submsg, submsgs, field);
+      if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) {
+        ptr = decode_togroup(d, ptr, submsg, subs, field);
       } else {
-        ptr = decode_tosubmsg(d, ptr, submsg, submsgs, field, val->size);
+        ptr = decode_tosubmsg(d, ptr, submsg, subs, field, val->size);
       }
       break;
     }
@@ -796,6 +906,7 @@
     case OP_SCALAR_LG2(3):
       memcpy(mem, val, 8);
       break;
+    case OP_ENUM:
     case OP_SCALAR_LG2(2):
       memcpy(mem, val, 4);
       break;
@@ -809,9 +920,27 @@
   return ptr;
 }
 
+UPB_NOINLINE
+const char* decode_checkrequired(upb_Decoder* d, const char* ptr,
+                                 const upb_Message* msg,
+                                 const upb_MiniTable* l) {
+  assert(l->required_count);
+  if (UPB_LIKELY((d->options & kUpb_DecodeOption_CheckRequired) == 0)) {
+    return ptr;
+  }
+  uint64_t msg_head;
+  memcpy(&msg_head, msg, 8);
+  msg_head = _upb_BigEndian_Swap64(msg_head);
+  if (upb_MiniTable_requiredmask(l) & ~msg_head) {
+    d->missing_required = true;
+  }
+  return ptr;
+}
+
 UPB_FORCEINLINE
-static bool decode_tryfastdispatch(upb_decstate *d, const char **ptr,
-                                   upb_msg *msg, const upb_msglayout *layout) {
+static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr,
+                                   upb_Message* msg,
+                                   const upb_MiniTable* layout) {
 #if UPB_FASTTABLE
   if (layout && layout->table_mask != (unsigned char)-1) {
     uint16_t tag = fastdecode_loadtag(*ptr);
@@ -823,176 +952,385 @@
   return false;
 }
 
+static const char* decode_msgset(upb_Decoder* d, const char* ptr,
+                                 upb_Message* msg,
+                                 const upb_MiniTable* layout) {
+  // We create a temporary upb_MiniTable here and abuse its fields as temporary
+  // storage, to avoid creating lots of MessageSet-specific parsing code-paths:
+  //   1. We store 'layout' in item_layout.subs.  We will need this later as
+  //      a key to look up extensions for this MessageSet.
+  //   2. We use item_layout.fields as temporary storage to store the extension
+  //   we
+  //      found when parsing the type id.
+  upb_MiniTable item_layout = {
+      .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}},
+      .fields = NULL,
+      .size = 0,
+      .field_count = 0,
+      .ext = upb_ExtMode_IsMessageSet_ITEM,
+      .dense_below = 0,
+      .table_mask = -1};
+  return decode_group(d, ptr, msg, &item_layout, 1);
+}
+
+static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d,
+                                                   const upb_MiniTable* l,
+                                                   uint32_t field_number,
+                                                   int* last_field_index) {
+  static upb_MiniTable_Field none = {0, 0, 0, 0, 0, 0};
+  if (l == NULL) return &none;
+
+  size_t idx = ((size_t)field_number) - 1;  // 0 wraps to SIZE_MAX
+  if (idx < l->dense_below) {
+    /* Fastest case: index into dense fields. */
+    goto found;
+  }
+
+  if (l->dense_below < l->field_count) {
+    /* Linear search non-dense fields. Resume scanning from last_field_index
+     * since fields are usually in order. */
+    int last = *last_field_index;
+    for (idx = last; idx < l->field_count; idx++) {
+      if (l->fields[idx].number == field_number) {
+        goto found;
+      }
+    }
+
+    for (idx = l->dense_below; idx < last; idx++) {
+      if (l->fields[idx].number == field_number) {
+        goto found;
+      }
+    }
+  }
+
+  if (d->extreg) {
+    switch (l->ext) {
+      case upb_ExtMode_Extendable: {
+        const upb_MiniTable_Extension* ext =
+            _upb_extreg_get(d->extreg, l, field_number);
+        if (ext) return &ext->field;
+        break;
+      }
+      case upb_ExtMode_IsMessageSet:
+        if (field_number == _UPB_MSGSET_ITEM) {
+          static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0};
+          return &item;
+        }
+        break;
+      case upb_ExtMode_IsMessageSet_ITEM:
+        switch (field_number) {
+          case _UPB_MSGSET_TYPEID: {
+            static upb_MiniTable_Field type_id = {
+                0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0};
+            return &type_id;
+          }
+          case _UPB_MSGSET_MESSAGE:
+            if (l->fields) {
+              // We saw type_id previously and succeeded in looking up msg.
+              return l->fields;
+            } else {
+              // TODO: out of order MessageSet.
+              // This is a very rare case: all serializers will emit in-order
+              // MessageSets.  To hit this case there has to be some kind of
+              // re-ordering proxy.  We should eventually handle this case, but
+              // not today.
+            }
+            break;
+        }
+    }
+  }
+
+  return &none; /* Unknown field. */
+
+found:
+  UPB_ASSERT(l->fields[idx].number == field_number);
+  *last_field_index = idx;
+  return &l->fields[idx];
+}
+
+UPB_FORCEINLINE
+static const char* decode_wireval(upb_Decoder* d, const char* ptr,
+                                  const upb_MiniTable_Field* field,
+                                  int wire_type, wireval* val, int* op) {
+  switch (wire_type) {
+    case kUpb_WireType_Varint:
+      ptr = decode_varint64(d, ptr, &val->uint64_val);
+      *op = varint_ops[field->descriptortype];
+      decode_munge(field->descriptortype, val);
+      return ptr;
+    case kUpb_WireType_32Bit:
+      memcpy(&val->uint32_val, ptr, 4);
+      val->uint32_val = _upb_BigEndian_Swap32(val->uint32_val);
+      *op = OP_SCALAR_LG2(2);
+      if (((1 << field->descriptortype) & FIXED32_OK_MASK) == 0) {
+        *op = OP_UNKNOWN;
+      }
+      return ptr + 4;
+    case kUpb_WireType_64Bit:
+      memcpy(&val->uint64_val, ptr, 8);
+      val->uint64_val = _upb_BigEndian_Swap64(val->uint64_val);
+      *op = OP_SCALAR_LG2(3);
+      if (((1 << field->descriptortype) & FIXED64_OK_MASK) == 0) {
+        *op = OP_UNKNOWN;
+      }
+      return ptr + 8;
+    case kUpb_WireType_Delimited: {
+      int ndx = field->descriptortype;
+      uint64_t size;
+      if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT;
+      ptr = decode_varint64(d, ptr, &size);
+      if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) {
+        break; /* Length overflow. */
+      }
+      *op = delim_ops[ndx];
+      val->size = size;
+      return ptr;
+    }
+    case kUpb_WireType_StartGroup:
+      val->uint32_val = field->number;
+      if (field->descriptortype == kUpb_FieldType_Group) {
+        *op = OP_SUBMSG;
+      } else if (field->descriptortype == TYPE_MSGSET_ITEM) {
+        *op = OP_MSGSET_ITEM;
+      } else {
+        *op = OP_UNKNOWN;
+      }
+      return ptr;
+    default:
+      break;
+  }
+  return decode_err(d, kUpb_DecodeStatus_Malformed);
+}
+
+UPB_FORCEINLINE
+static const char* decode_known(upb_Decoder* d, const char* ptr,
+                                upb_Message* msg, const upb_MiniTable* layout,
+                                const upb_MiniTable_Field* field, int op,
+                                wireval* val) {
+  const upb_MiniTable_Sub* subs = layout->subs;
+  uint8_t mode = field->mode;
+
+  if (UPB_UNLIKELY(mode & upb_LabelFlags_IsExtension)) {
+    const upb_MiniTable_Extension* ext_layout =
+        (const upb_MiniTable_Extension*)field;
+    upb_Message_Extension* ext =
+        _upb_Message_Getorcreateext(msg, ext_layout, &d->arena);
+    if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory);
+    msg = &ext->data;
+    subs = &ext->ext->sub;
+  }
+
+  switch (mode & kUpb_FieldMode_Mask) {
+    case kUpb_FieldMode_Array:
+      return decode_toarray(d, ptr, msg, subs, field, val, op);
+    case kUpb_FieldMode_Map:
+      return decode_tomap(d, ptr, msg, subs, field, val);
+    case kUpb_FieldMode_Scalar:
+      return decode_tomsg(d, ptr, msg, subs, field, val, op);
+    default:
+      UPB_UNREACHABLE();
+  }
+}
+
+static const char* decode_reverse_skip_varint(const char* ptr, uint32_t val) {
+  uint32_t seen = 0;
+  do {
+    ptr--;
+    seen <<= 7;
+    seen |= *ptr & 0x7f;
+  } while (seen != val);
+  return ptr;
+}
+
+static const char* decode_unknown(upb_Decoder* d, const char* ptr,
+                                  upb_Message* msg, int field_number,
+                                  int wire_type, wireval val) {
+  if (field_number == 0) return decode_err(d, kUpb_DecodeStatus_Malformed);
+
+  // Since unknown fields are the uncommon case, we do a little extra work here
+  // to walk backwards through the buffer to find the field start.  This frees
+  // up a register in the fast paths (when the field is known), which leads to
+  // significant speedups in benchmarks.
+  const char* start = ptr;
+
+  if (wire_type == kUpb_WireType_Delimited) ptr += val.size;
+  if (msg) {
+    switch (wire_type) {
+      case kUpb_WireType_Varint:
+      case kUpb_WireType_Delimited:
+        start--;
+        while (start[-1] & 0x80) start--;
+        break;
+      case kUpb_WireType_32Bit:
+        start -= 4;
+        break;
+      case kUpb_WireType_64Bit:
+        start -= 8;
+        break;
+      default:
+        break;
+    }
+
+    assert(start == d->debug_valstart);
+    uint32_t tag = ((uint32_t)field_number << 3) | wire_type;
+    start = decode_reverse_skip_varint(start, tag);
+    assert(start == d->debug_tagstart);
+
+    if (wire_type == kUpb_WireType_StartGroup) {
+      d->unknown = start;
+      d->unknown_msg = msg;
+      ptr = decode_group(d, ptr, NULL, NULL, field_number);
+      start = d->unknown;
+      d->unknown_msg = NULL;
+      d->unknown = NULL;
+    }
+    if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) {
+      return decode_err(d, kUpb_DecodeStatus_OutOfMemory);
+    }
+  } else if (wire_type == kUpb_WireType_StartGroup) {
+    ptr = decode_group(d, ptr, NULL, NULL, field_number);
+  }
+  return ptr;
+}
+
 UPB_NOINLINE
-static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg,
-                              const upb_msglayout *layout) {
+static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg,
+                              const upb_MiniTable* layout) {
   int last_field_index = 0;
-  while (true) {
+
+#if UPB_FASTTABLE
+  // The first time we want to skip fast dispatch, because we may have just been
+  // invoked by the fast parser to handle a case that it bailed on.
+  if (!decode_isdone(d, &ptr)) goto nofast;
+#endif
+
+  while (!decode_isdone(d, &ptr)) {
     uint32_t tag;
-    const upb_msglayout_field *field;
+    const upb_MiniTable_Field* field;
     int field_number;
     int wire_type;
-    const char *field_start = ptr;
     wireval val;
     int op;
 
+    if (decode_tryfastdispatch(d, &ptr, msg, layout)) break;
+
+#if UPB_FASTTABLE
+  nofast:
+#endif
+
+#ifndef NDEBUG
+    d->debug_tagstart = ptr;
+#endif
+
     UPB_ASSERT(ptr < d->limit_ptr);
     ptr = decode_tag(d, ptr, &tag);
     field_number = tag >> 3;
     wire_type = tag & 7;
 
-    field = upb_find_field(layout, field_number, &last_field_index);
+#ifndef NDEBUG
+    d->debug_valstart = ptr;
+#endif
 
-    switch (wire_type) {
-      case UPB_WIRE_TYPE_VARINT:
-        ptr = decode_varint64(d, ptr, &val.uint64_val);
-        op = varint_ops[field->descriptortype];
-        decode_munge(field->descriptortype, &val);
-        break;
-      case UPB_WIRE_TYPE_32BIT:
-        memcpy(&val.uint32_val, ptr, 4);
-        val.uint32_val = _upb_be_swap32(val.uint32_val);
-        ptr += 4;
-        op = OP_SCALAR_LG2(2);
-        if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown;
-        break;
-      case UPB_WIRE_TYPE_64BIT:
-        memcpy(&val.uint64_val, ptr, 8);
-        val.uint64_val = _upb_be_swap64(val.uint64_val);
-        ptr += 8;
-        op = OP_SCALAR_LG2(3);
-        if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown;
-        break;
-      case UPB_WIRE_TYPE_DELIMITED: {
-        int ndx = field->descriptortype;
-        uint64_t size;
-        if (_upb_getmode(field) == _UPB_MODE_ARRAY) ndx += 18;
-        ptr = decode_varint64(d, ptr, &size);
-        if (size >= INT32_MAX ||
-            ptr - d->end + (int32_t)size > d->limit) {
-          decode_err(d); /* Length overflow. */
-        }
-        op = delim_ops[ndx];
-        val.size = size;
-        break;
-      }
-      case UPB_WIRE_TYPE_START_GROUP:
-        val.uint32_val = field_number;
-        op = OP_SUBMSG;
-        if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown;
-        break;
-      case UPB_WIRE_TYPE_END_GROUP:
-        d->end_group = field_number;
-        return ptr;
-      default:
-        decode_err(d);
+    if (wire_type == kUpb_WireType_EndGroup) {
+      d->end_group = field_number;
+      return ptr;
     }
 
+    field = decode_findfield(d, layout, field_number, &last_field_index);
+    ptr = decode_wireval(d, ptr, field, wire_type, &val, &op);
+
     if (op >= 0) {
-      /* Parse, using op for dispatch. */
-      switch (_upb_getmode(field)) {
-        case _UPB_MODE_ARRAY:
-          ptr = decode_toarray(d, ptr, msg, layout->submsgs, field, &val, op);
-          break;
-        case _UPB_MODE_MAP:
-          ptr = decode_tomap(d, ptr, msg, layout->submsgs, field, &val);
-          break;
-        case _UPB_MODE_SCALAR:
-          ptr = decode_tomsg(d, ptr, msg, layout->submsgs, field, &val, op);
-          break;
-        default:
-          UPB_UNREACHABLE();
-      }
+      ptr = decode_known(d, ptr, msg, layout, field, op, &val);
     } else {
-    unknown:
-      /* Skip unknown field. */
-      if (field_number == 0) decode_err(d);
-      if (wire_type == UPB_WIRE_TYPE_DELIMITED) ptr += val.size;
-      if (msg) {
-        if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
-          d->unknown = field_start;
-          d->unknown_msg = msg;
-          ptr = decode_group(d, ptr, NULL, NULL, field_number);
-          d->unknown_msg = NULL;
-          field_start = d->unknown;
+      switch (op) {
+        case OP_UNKNOWN:
+          ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val);
+          break;
+        case OP_MSGSET_ITEM:
+          ptr = decode_msgset(d, ptr, msg, layout);
+          break;
+        case OP_MSGSET_TYPEID: {
+          const upb_MiniTable_Extension* ext = _upb_extreg_get(
+              d->extreg, layout->subs[0].submsg, val.uint64_val);
+          if (ext) ((upb_MiniTable*)layout)->fields = &ext->field;
+          break;
         }
-        if (!_upb_msg_addunknown(msg, field_start, ptr - field_start,
-                                 &d->arena)) {
-          decode_err(d);
-        }
-      } else if (wire_type == UPB_WIRE_TYPE_START_GROUP) {
-        ptr = decode_group(d, ptr, NULL, NULL, field_number);
       }
     }
-
-    if (decode_isdone(d, &ptr)) return ptr;
-    if (decode_tryfastdispatch(d, &ptr, msg, layout)) return ptr;
   }
+
+  return UPB_UNLIKELY(layout && layout->required_count)
+             ? decode_checkrequired(d, ptr, msg, layout)
+             : ptr;
 }
 
-const char *fastdecode_generic(struct upb_decstate *d, const char *ptr,
-                               upb_msg *msg, intptr_t table, uint64_t hasbits,
-                               uint64_t data) {
+const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr,
+                               upb_Message* msg, intptr_t table,
+                               uint64_t hasbits, uint64_t data) {
   (void)data;
   *(uint32_t*)msg |= hasbits;
   return decode_msg(d, ptr, msg, decode_totablep(table));
 }
 
-static bool decode_top(struct upb_decstate *d, const char *buf, void *msg,
-                       const upb_msglayout *l) {
+static upb_DecodeStatus decode_top(struct upb_Decoder* d, const char* buf,
+                                   void* msg, const upb_MiniTable* l) {
   if (!decode_tryfastdispatch(d, &buf, msg, l)) {
     decode_msg(d, buf, msg, l);
   }
-  return d->end_group == DECODE_NOGROUP;
+  if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed;
+  if (d->missing_required) return kUpb_DecodeStatus_MissingRequired;
+  return kUpb_DecodeStatus_Ok;
 }
 
-bool _upb_decode(const char *buf, size_t size, void *msg,
-                 const upb_msglayout *l, const upb_extreg *extreg, int options,
-                 upb_arena *arena) {
-  bool ok;
-  upb_decstate state;
+upb_DecodeStatus upb_Decode(const char* buf, size_t size, void* msg,
+                            const upb_MiniTable* l,
+                            const upb_ExtensionRegistry* extreg, int options,
+                            upb_Arena* arena) {
+  upb_Decoder state;
   unsigned depth = (unsigned)options >> 16;
 
-  if (size == 0) {
-    return true;
-  } else if (size <= 16) {
+  if (size <= 16) {
     memset(&state.patch, 0, 32);
     memcpy(&state.patch, buf, size);
     buf = state.patch;
     state.end = buf + size;
     state.limit = 0;
-    state.alias = false;
+    options &= ~kUpb_DecodeOption_AliasString;  // Can't alias patch buf.
   } else {
     state.end = buf + size - 16;
     state.limit = 16;
-    state.alias = options & UPB_DECODE_ALIAS;
   }
 
+  state.extreg = extreg;
   state.limit_ptr = state.end;
   state.unknown_msg = NULL;
   state.depth = depth ? depth : 64;
   state.end_group = DECODE_NOGROUP;
+  state.options = (uint16_t)options;
+  state.missing_required = false;
   state.arena.head = arena->head;
   state.arena.last_size = arena->last_size;
   state.arena.cleanup_metadata = arena->cleanup_metadata;
   state.arena.parent = arena;
 
-  if (UPB_UNLIKELY(UPB_SETJMP(state.err))) {
-    ok = false;
-  } else {
-    ok = decode_top(&state, buf, msg, l);
+  upb_DecodeStatus status = UPB_SETJMP(state.err);
+  if (UPB_LIKELY(status == kUpb_DecodeStatus_Ok)) {
+    status = decode_top(&state, buf, msg, l);
   }
 
   arena->head.ptr = state.arena.head.ptr;
   arena->head.end = state.arena.head.end;
   arena->cleanup_metadata = state.arena.cleanup_metadata;
-  return ok;
+  return status;
 }
 
+#undef OP_UNKNOWN
+#undef OP_SKIP
 #undef OP_SCALAR_LG2
 #undef OP_FIXPCK_LG2
 #undef OP_VARPCK_LG2
 #undef OP_STRING
+#undef OP_BYTES
 #undef OP_SUBMSG
 
 /** upb/encode.c ************************************************************/
@@ -1008,7 +1346,7 @@
 #define UPB_PB_VARINT_MAX_LEN 10
 
 UPB_NOINLINE
-static size_t encode_varint64(uint64_t val, char *buf) {
+static size_t encode_varint64(uint64_t val, char* buf) {
   size_t i = 0;
   do {
     uint8_t byte = val & 0x7fU;
@@ -1019,12 +1357,16 @@
   return i;
 }
 
-static uint32_t encode_zz32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); }
-static uint64_t encode_zz64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); }
+static uint32_t encode_zz32(int32_t n) {
+  return ((uint32_t)n << 1) ^ (n >> 31);
+}
+static uint64_t encode_zz64(int64_t n) {
+  return ((uint64_t)n << 1) ^ (n >> 63);
+}
 
 typedef struct {
   jmp_buf err;
-  upb_alloc *alloc;
+  upb_alloc* alloc;
   char *buf, *ptr, *limit;
   int options;
   int depth;
@@ -1039,15 +1381,13 @@
   return ret;
 }
 
-UPB_NORETURN static void encode_err(upb_encstate *e) {
-  UPB_LONGJMP(e->err, 1);
-}
+UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); }
 
 UPB_NOINLINE
-static void encode_growbuffer(upb_encstate *e, size_t bytes) {
+static void encode_growbuffer(upb_encstate* e, size_t bytes) {
   size_t old_size = e->limit - e->buf;
   size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
-  char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
+  char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size);
 
   if (!new_buf) encode_err(e);
 
@@ -1066,7 +1406,7 @@
 /* Call to ensure that at least "bytes" bytes are available for writing at
  * e->ptr.  Returns false if the bytes could not be allocated. */
 UPB_FORCEINLINE
-static void encode_reserve(upb_encstate *e, size_t bytes) {
+static void encode_reserve(upb_encstate* e, size_t bytes) {
   if ((size_t)(e->ptr - e->buf) < bytes) {
     encode_growbuffer(e, bytes);
     return;
@@ -1076,26 +1416,26 @@
 }
 
 /* Writes the given bytes to the buffer, handling reserve/advance. */
-static void encode_bytes(upb_encstate *e, const void *data, size_t len) {
-  if (len == 0) return;  /* memcpy() with zero size is UB */
+static void encode_bytes(upb_encstate* e, const void* data, size_t len) {
+  if (len == 0) return; /* memcpy() with zero size is UB */
   encode_reserve(e, len);
   memcpy(e->ptr, data, len);
 }
 
-static void encode_fixed64(upb_encstate *e, uint64_t val) {
-  val = _upb_be_swap64(val);
+static void encode_fixed64(upb_encstate* e, uint64_t val) {
+  val = _upb_BigEndian_Swap64(val);
   encode_bytes(e, &val, sizeof(uint64_t));
 }
 
-static void encode_fixed32(upb_encstate *e, uint32_t val) {
-  val = _upb_be_swap32(val);
+static void encode_fixed32(upb_encstate* e, uint32_t val) {
+  val = _upb_BigEndian_Swap32(val);
   encode_bytes(e, &val, sizeof(uint32_t));
 }
 
 UPB_NOINLINE
-static void encode_longvarint(upb_encstate *e, uint64_t val) {
+static void encode_longvarint(upb_encstate* e, uint64_t val) {
   size_t len;
-  char *start;
+  char* start;
 
   encode_reserve(e, UPB_PB_VARINT_MAX_LEN);
   len = encode_varint64(val, e->ptr);
@@ -1105,7 +1445,7 @@
 }
 
 UPB_FORCEINLINE
-static void encode_varint(upb_encstate *e, uint64_t val) {
+static void encode_varint(upb_encstate* e, uint64_t val) {
   if (val < 128 && e->ptr != e->buf) {
     --e->ptr;
     *e->ptr = val;
@@ -1114,34 +1454,47 @@
   }
 }
 
-static void encode_double(upb_encstate *e, double d) {
+static void encode_double(upb_encstate* e, double d) {
   uint64_t u64;
   UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
   memcpy(&u64, &d, sizeof(uint64_t));
   encode_fixed64(e, u64);
 }
 
-static void encode_float(upb_encstate *e, float d) {
+static void encode_float(upb_encstate* e, float d) {
   uint32_t u32;
   UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
   memcpy(&u32, &d, sizeof(uint32_t));
   encode_fixed32(e, u32);
 }
 
-static void encode_tag(upb_encstate *e, uint32_t field_number,
+static void encode_tag(upb_encstate* e, uint32_t field_number,
                        uint8_t wire_type) {
   encode_varint(e, (field_number << 3) | wire_type);
 }
 
-static void encode_fixedarray(upb_encstate *e, const upb_array *arr,
-                               size_t elem_size, uint32_t tag) {
+static void encode_fixedarray(upb_encstate* e, const upb_Array* arr,
+                              size_t elem_size, uint32_t tag) {
   size_t bytes = arr->len * elem_size;
   const char* data = _upb_array_constptr(arr);
   const char* ptr = data + bytes - elem_size;
-  if (tag) {
+
+  if (tag || !_upb_IsLittleEndian()) {
     while (true) {
-      encode_bytes(e, ptr, elem_size);
-      encode_varint(e, tag);
+      if (elem_size == 4) {
+        uint32_t val;
+        memcpy(&val, ptr, sizeof(val));
+        val = _upb_BigEndian_Swap32(val);
+        encode_bytes(e, &val, elem_size);
+      } else {
+        UPB_ASSERT(elem_size == 8);
+        uint64_t val;
+        memcpy(&val, ptr, sizeof(val));
+        val = _upb_BigEndian_Swap64(val);
+        encode_bytes(e, &val, elem_size);
+      }
+
+      if (tag) encode_varint(e, tag);
       if (ptr == data) break;
       ptr -= elem_size;
     }
@@ -1150,87 +1503,81 @@
   }
 }
 
-static void encode_message(upb_encstate *e, const upb_msg *msg,
-                           const upb_msglayout *m, size_t *size);
+static void encode_message(upb_encstate* e, const upb_Message* msg,
+                           const upb_MiniTable* m, size_t* size);
 
-static void encode_scalar(upb_encstate *e, const void *_field_mem,
-                          const upb_msglayout *m, const upb_msglayout_field *f,
-                          bool skip_zero_value) {
-  const char *field_mem = _field_mem;
+static void encode_scalar(upb_encstate* e, const void* _field_mem,
+                          const upb_MiniTable_Sub* subs,
+                          const upb_MiniTable_Field* f) {
+  const char* field_mem = _field_mem;
   int wire_type;
 
 #define CASE(ctype, type, wtype, encodeval) \
   {                                         \
-    ctype val = *(ctype *)field_mem;        \
-    if (skip_zero_value && val == 0) {      \
-      return;                               \
-    }                                       \
+    ctype val = *(ctype*)field_mem;         \
     encode_##type(e, encodeval);            \
     wire_type = wtype;                      \
     break;                                  \
   }
 
   switch (f->descriptortype) {
-    case UPB_DESCRIPTOR_TYPE_DOUBLE:
-      CASE(double, double, UPB_WIRE_TYPE_64BIT, val);
-    case UPB_DESCRIPTOR_TYPE_FLOAT:
-      CASE(float, float, UPB_WIRE_TYPE_32BIT, val);
-    case UPB_DESCRIPTOR_TYPE_INT64:
-    case UPB_DESCRIPTOR_TYPE_UINT64:
-      CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val);
-    case UPB_DESCRIPTOR_TYPE_UINT32:
-      CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val);
-    case UPB_DESCRIPTOR_TYPE_INT32:
-    case UPB_DESCRIPTOR_TYPE_ENUM:
-      CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val);
-    case UPB_DESCRIPTOR_TYPE_SFIXED64:
-    case UPB_DESCRIPTOR_TYPE_FIXED64:
-      CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val);
-    case UPB_DESCRIPTOR_TYPE_FIXED32:
-    case UPB_DESCRIPTOR_TYPE_SFIXED32:
-      CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val);
-    case UPB_DESCRIPTOR_TYPE_BOOL:
-      CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
-    case UPB_DESCRIPTOR_TYPE_SINT32:
-      CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz32(val));
-    case UPB_DESCRIPTOR_TYPE_SINT64:
-      CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, encode_zz64(val));
-    case UPB_DESCRIPTOR_TYPE_STRING:
-    case UPB_DESCRIPTOR_TYPE_BYTES: {
-      upb_strview view = *(upb_strview*)field_mem;
-      if (skip_zero_value && view.size == 0) {
-        return;
-      }
+    case kUpb_FieldType_Double:
+      CASE(double, double, kUpb_WireType_64Bit, val);
+    case kUpb_FieldType_Float:
+      CASE(float, float, kUpb_WireType_32Bit, val);
+    case kUpb_FieldType_Int64:
+    case kUpb_FieldType_UInt64:
+      CASE(uint64_t, varint, kUpb_WireType_Varint, val);
+    case kUpb_FieldType_UInt32:
+      CASE(uint32_t, varint, kUpb_WireType_Varint, val);
+    case kUpb_FieldType_Int32:
+    case kUpb_FieldType_Enum:
+      CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val);
+    case kUpb_FieldType_SFixed64:
+    case kUpb_FieldType_Fixed64:
+      CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val);
+    case kUpb_FieldType_Fixed32:
+    case kUpb_FieldType_SFixed32:
+      CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val);
+    case kUpb_FieldType_Bool:
+      CASE(bool, varint, kUpb_WireType_Varint, val);
+    case kUpb_FieldType_SInt32:
+      CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val));
+    case kUpb_FieldType_SInt64:
+      CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val));
+    case kUpb_FieldType_String:
+    case kUpb_FieldType_Bytes: {
+      upb_StringView view = *(upb_StringView*)field_mem;
       encode_bytes(e, view.data, view.size);
       encode_varint(e, view.size);
-      wire_type = UPB_WIRE_TYPE_DELIMITED;
+      wire_type = kUpb_WireType_Delimited;
       break;
     }
-    case UPB_DESCRIPTOR_TYPE_GROUP: {
+    case kUpb_FieldType_Group: {
       size_t size;
-      void *submsg = *(void **)field_mem;
-      const upb_msglayout *subm = m->submsgs[f->submsg_index];
+      void* submsg = *(void**)field_mem;
+      const upb_MiniTable* subm = subs[f->submsg_index].submsg;
       if (submsg == NULL) {
         return;
       }
       if (--e->depth == 0) encode_err(e);
-      encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
+      encode_tag(e, f->number, kUpb_WireType_EndGroup);
       encode_message(e, submsg, subm, &size);
-      wire_type = UPB_WIRE_TYPE_START_GROUP;
+      wire_type = kUpb_WireType_StartGroup;
       e->depth++;
       break;
     }
-    case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+    case kUpb_FieldType_Message: {
       size_t size;
-      void *submsg = *(void **)field_mem;
-      const upb_msglayout *subm = m->submsgs[f->submsg_index];
+      void* submsg = *(void**)field_mem;
+      const upb_MiniTable* subm = subs[f->submsg_index].submsg;
       if (submsg == NULL) {
         return;
       }
       if (--e->depth == 0) encode_err(e);
       encode_message(e, submsg, subm, &size);
       encode_varint(e, size);
-      wire_type = UPB_WIRE_TYPE_DELIMITED;
+      wire_type = kUpb_WireType_Delimited;
       e->depth++;
       break;
     }
@@ -1242,10 +1589,11 @@
   encode_tag(e, f->number, wire_type);
 }
 
-static void encode_array(upb_encstate *e, const upb_msg *msg,
-                         const upb_msglayout *m, const upb_msglayout_field *f) {
-  const upb_array *arr = *UPB_PTR_AT(msg, f->offset, upb_array*);
-  bool packed = f->mode & _UPB_MODE_IS_PACKED;
+static void encode_array(upb_encstate* e, const upb_Message* msg,
+                         const upb_MiniTable_Sub* subs,
+                         const upb_MiniTable_Field* f) {
+  const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*);
+  bool packed = f->mode & upb_LabelFlags_IsPacked;
   size_t pre_len = e->limit - e->ptr;
 
   if (arr == NULL || arr->len == 0) {
@@ -1254,9 +1602,9 @@
 
 #define VARINT_CASE(ctype, encode)                                       \
   {                                                                      \
-    const ctype *start = _upb_array_constptr(arr);                       \
-    const ctype *ptr = start + arr->len;                                 \
-    uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \
+    const ctype* start = _upb_array_constptr(arr);                       \
+    const ctype* ptr = start + arr->len;                                 \
+    uint32_t tag = packed ? 0 : (f->number << 3) | kUpb_WireType_Varint; \
     do {                                                                 \
       ptr--;                                                             \
       encode_varint(e, encode);                                          \
@@ -1268,72 +1616,72 @@
 #define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type))
 
   switch (f->descriptortype) {
-    case UPB_DESCRIPTOR_TYPE_DOUBLE:
-      encode_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT));
+    case kUpb_FieldType_Double:
+      encode_fixedarray(e, arr, sizeof(double), TAG(kUpb_WireType_64Bit));
       break;
-    case UPB_DESCRIPTOR_TYPE_FLOAT:
-      encode_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT));
+    case kUpb_FieldType_Float:
+      encode_fixedarray(e, arr, sizeof(float), TAG(kUpb_WireType_32Bit));
       break;
-    case UPB_DESCRIPTOR_TYPE_SFIXED64:
-    case UPB_DESCRIPTOR_TYPE_FIXED64:
-      encode_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT));
+    case kUpb_FieldType_SFixed64:
+    case kUpb_FieldType_Fixed64:
+      encode_fixedarray(e, arr, sizeof(uint64_t), TAG(kUpb_WireType_64Bit));
       break;
-    case UPB_DESCRIPTOR_TYPE_FIXED32:
-    case UPB_DESCRIPTOR_TYPE_SFIXED32:
-      encode_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT));
+    case kUpb_FieldType_Fixed32:
+    case kUpb_FieldType_SFixed32:
+      encode_fixedarray(e, arr, sizeof(uint32_t), TAG(kUpb_WireType_32Bit));
       break;
-    case UPB_DESCRIPTOR_TYPE_INT64:
-    case UPB_DESCRIPTOR_TYPE_UINT64:
+    case kUpb_FieldType_Int64:
+    case kUpb_FieldType_UInt64:
       VARINT_CASE(uint64_t, *ptr);
-    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case kUpb_FieldType_UInt32:
       VARINT_CASE(uint32_t, *ptr);
-    case UPB_DESCRIPTOR_TYPE_INT32:
-    case UPB_DESCRIPTOR_TYPE_ENUM:
+    case kUpb_FieldType_Int32:
+    case kUpb_FieldType_Enum:
       VARINT_CASE(int32_t, (int64_t)*ptr);
-    case UPB_DESCRIPTOR_TYPE_BOOL:
+    case kUpb_FieldType_Bool:
       VARINT_CASE(bool, *ptr);
-    case UPB_DESCRIPTOR_TYPE_SINT32:
+    case kUpb_FieldType_SInt32:
       VARINT_CASE(int32_t, encode_zz32(*ptr));
-    case UPB_DESCRIPTOR_TYPE_SINT64:
+    case kUpb_FieldType_SInt64:
       VARINT_CASE(int64_t, encode_zz64(*ptr));
-    case UPB_DESCRIPTOR_TYPE_STRING:
-    case UPB_DESCRIPTOR_TYPE_BYTES: {
-      const upb_strview *start = _upb_array_constptr(arr);
-      const upb_strview *ptr = start + arr->len;
+    case kUpb_FieldType_String:
+    case kUpb_FieldType_Bytes: {
+      const upb_StringView* start = _upb_array_constptr(arr);
+      const upb_StringView* ptr = start + arr->len;
       do {
         ptr--;
         encode_bytes(e, ptr->data, ptr->size);
         encode_varint(e, ptr->size);
-        encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+        encode_tag(e, f->number, kUpb_WireType_Delimited);
       } while (ptr != start);
       return;
     }
-    case UPB_DESCRIPTOR_TYPE_GROUP: {
-      const void *const*start = _upb_array_constptr(arr);
-      const void *const*ptr = start + arr->len;
-      const upb_msglayout *subm = m->submsgs[f->submsg_index];
+    case kUpb_FieldType_Group: {
+      const void* const* start = _upb_array_constptr(arr);
+      const void* const* ptr = start + arr->len;
+      const upb_MiniTable* subm = subs[f->submsg_index].submsg;
       if (--e->depth == 0) encode_err(e);
       do {
         size_t size;
         ptr--;
-        encode_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP);
+        encode_tag(e, f->number, kUpb_WireType_EndGroup);
         encode_message(e, *ptr, subm, &size);
-        encode_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
+        encode_tag(e, f->number, kUpb_WireType_StartGroup);
       } while (ptr != start);
       e->depth++;
       return;
     }
-    case UPB_DESCRIPTOR_TYPE_MESSAGE: {
-      const void *const*start = _upb_array_constptr(arr);
-      const void *const*ptr = start + arr->len;
-      const upb_msglayout *subm = m->submsgs[f->submsg_index];
+    case kUpb_FieldType_Message: {
+      const void* const* start = _upb_array_constptr(arr);
+      const void* const* ptr = start + arr->len;
+      const upb_MiniTable* subm = subs[f->submsg_index].submsg;
       if (--e->depth == 0) encode_err(e);
       do {
         size_t size;
         ptr--;
         encode_message(e, *ptr, subm, &size);
         encode_varint(e, size);
-        encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+        encode_tag(e, f->number, kUpb_WireType_Delimited);
       } while (ptr != start);
       e->depth++;
       return;
@@ -1343,37 +1691,38 @@
 
   if (packed) {
     encode_varint(e, e->limit - e->ptr - pre_len);
-    encode_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+    encode_tag(e, f->number, kUpb_WireType_Delimited);
   }
 }
 
-static void encode_mapentry(upb_encstate *e, uint32_t number,
-                            const upb_msglayout *layout,
-                            const upb_map_entry *ent) {
-  const upb_msglayout_field *key_field = &layout->fields[0];
-  const upb_msglayout_field *val_field = &layout->fields[1];
+static void encode_mapentry(upb_encstate* e, uint32_t number,
+                            const upb_MiniTable* layout,
+                            const upb_MapEntry* ent) {
+  const upb_MiniTable_Field* key_field = &layout->fields[0];
+  const upb_MiniTable_Field* val_field = &layout->fields[1];
   size_t pre_len = e->limit - e->ptr;
   size_t size;
-  encode_scalar(e, &ent->v, layout, val_field, false);
-  encode_scalar(e, &ent->k, layout, key_field, false);
+  encode_scalar(e, &ent->v, layout->subs, val_field);
+  encode_scalar(e, &ent->k, layout->subs, key_field);
   size = (e->limit - e->ptr) - pre_len;
   encode_varint(e, size);
-  encode_tag(e, number, UPB_WIRE_TYPE_DELIMITED);
+  encode_tag(e, number, kUpb_WireType_Delimited);
 }
 
-static void encode_map(upb_encstate *e, const upb_msg *msg,
-                       const upb_msglayout *m, const upb_msglayout_field *f) {
-  const upb_map *map = *UPB_PTR_AT(msg, f->offset, const upb_map*);
-  const upb_msglayout *layout = m->submsgs[f->submsg_index];
+static void encode_map(upb_encstate* e, const upb_Message* msg,
+                       const upb_MiniTable_Sub* subs,
+                       const upb_MiniTable_Field* f) {
+  const upb_Map* map = *UPB_PTR_AT(msg, f->offset, const upb_Map*);
+  const upb_MiniTable* layout = subs[f->submsg_index].submsg;
   UPB_ASSERT(layout->field_count == 2);
 
   if (map == NULL) return;
 
-  if (e->options & UPB_ENCODE_DETERMINISTIC) {
+  if (e->options & kUpb_Encode_Deterministic) {
     _upb_sortedmap sorted;
     _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map,
                            &sorted);
-    upb_map_entry ent;
+    upb_MapEntry ent;
     while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
       encode_mapentry(e, f->number, layout, &ent);
     }
@@ -1381,10 +1730,10 @@
   } else {
     upb_strtable_iter i;
     upb_strtable_begin(&i, &map->table);
-    for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-      upb_strview key = upb_strtable_iter_key(&i);
+    for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+      upb_StringView key = upb_strtable_iter_key(&i);
       const upb_value val = upb_strtable_iter_value(&i);
-      upb_map_entry ent;
+      upb_MapEntry ent;
       _upb_map_fromkey(key, &ent.k, map->key_size);
       _upb_map_fromvalue(val, &ent.v, map->val_size);
       encode_mapentry(e, f->number, layout, &ent);
@@ -1392,71 +1741,145 @@
   }
 }
 
-static void encode_scalarfield(upb_encstate *e, const char *msg,
-                               const upb_msglayout *m,
-                               const upb_msglayout_field *f) {
-  bool skip_empty = false;
+static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg,
+                                const upb_MiniTable_Sub* subs,
+                                const upb_MiniTable_Field* f) {
   if (f->presence == 0) {
-    /* Proto3 presence. */
-    skip_empty = true;
+    /* Proto3 presence or map/array. */
+    const void* mem = UPB_PTR_AT(msg, f->offset, void);
+    switch (f->mode >> upb_FieldRep_Shift) {
+      case upb_FieldRep_1Byte: {
+        char ch;
+        memcpy(&ch, mem, 1);
+        return ch != 0;
+      }
+      case upb_FieldRep_4Byte: {
+        uint32_t u32;
+        memcpy(&u32, mem, 4);
+        return u32 != 0;
+      }
+      case upb_FieldRep_8Byte: {
+        uint64_t u64;
+        memcpy(&u64, mem, 8);
+        return u64 != 0;
+      }
+      case upb_FieldRep_StringView: {
+        const upb_StringView* str = (const upb_StringView*)mem;
+        return str->size != 0;
+      }
+      default:
+        UPB_UNREACHABLE();
+    }
   } else if (f->presence > 0) {
     /* Proto2 presence: hasbit. */
-    if (!_upb_hasbit_field(msg, f)) return;
+    return _upb_hasbit_field(msg, f);
   } else {
     /* Field is in a oneof. */
-    if (_upb_getoneofcase_field(msg, f) != f->number) return;
+    return _upb_getoneofcase_field(msg, f) == f->number;
   }
-  encode_scalar(e, msg + f->offset, m, f, skip_empty);
 }
 
-static void encode_message(upb_encstate *e, const upb_msg *msg,
-                           const upb_msglayout *m, size_t *size) {
-  size_t pre_len = e->limit - e->ptr;
-  const upb_msglayout_field *f = &m->fields[m->field_count];
-  const upb_msglayout_field *first = &m->fields[0];
+static void encode_field(upb_encstate* e, const upb_Message* msg,
+                         const upb_MiniTable_Sub* subs,
+                         const upb_MiniTable_Field* field) {
+  switch (upb_FieldMode_Get(field)) {
+    case kUpb_FieldMode_Array:
+      encode_array(e, msg, subs, field);
+      break;
+    case kUpb_FieldMode_Map:
+      encode_map(e, msg, subs, field);
+      break;
+    case kUpb_FieldMode_Scalar:
+      encode_scalar(e, UPB_PTR_AT(msg, field->offset, void), subs, field);
+      break;
+    default:
+      UPB_UNREACHABLE();
+  }
+}
 
-  if ((e->options & UPB_ENCODE_SKIPUNKNOWN) == 0) {
+/* message MessageSet {
+ *   repeated group Item = 1 {
+ *     required int32 type_id = 2;
+ *     required string message = 3;
+ *   }
+ * } */
+static void encode_msgset_item(upb_encstate* e,
+                               const upb_Message_Extension* ext) {
+  size_t size;
+  encode_tag(e, 1, kUpb_WireType_EndGroup);
+  encode_message(e, ext->data.ptr, ext->ext->sub.submsg, &size);
+  encode_varint(e, size);
+  encode_tag(e, 3, kUpb_WireType_Delimited);
+  encode_varint(e, ext->ext->field.number);
+  encode_tag(e, 2, kUpb_WireType_Varint);
+  encode_tag(e, 1, kUpb_WireType_StartGroup);
+}
+
+static void encode_message(upb_encstate* e, const upb_Message* msg,
+                           const upb_MiniTable* m, size_t* size) {
+  size_t pre_len = e->limit - e->ptr;
+
+  if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) {
+    uint64_t msg_head;
+    memcpy(&msg_head, msg, 8);
+    msg_head = _upb_BigEndian_Swap64(msg_head);
+    if (upb_MiniTable_requiredmask(m) & ~msg_head) {
+      encode_err(e);
+    }
+  }
+
+  if ((e->options & kUpb_Encode_SkipUnknown) == 0) {
     size_t unknown_size;
-    const char *unknown = upb_msg_getunknown(msg, &unknown_size);
+    const char* unknown = upb_Message_GetUnknown(msg, &unknown_size);
 
     if (unknown) {
       encode_bytes(e, unknown, unknown_size);
     }
   }
 
+  if (m->ext != upb_ExtMode_NonExtendable) {
+    /* Encode all extensions together. Unlike C++, we do not attempt to keep
+     * these in field number order relative to normal fields or even to each
+     * other. */
+    size_t ext_count;
+    const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count);
+    const upb_Message_Extension* end = ext + ext_count;
+    if (ext_count) {
+      for (; ext != end; ext++) {
+        if (UPB_UNLIKELY(m->ext == upb_ExtMode_IsMessageSet)) {
+          encode_msgset_item(e, ext);
+        } else {
+          encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field);
+        }
+      }
+    }
+  }
+
+  const upb_MiniTable_Field* f = &m->fields[m->field_count];
+  const upb_MiniTable_Field* first = &m->fields[0];
   while (f != first) {
     f--;
-    switch (_upb_getmode(f)) {
-      case _UPB_MODE_ARRAY:
-        encode_array(e, msg, m, f);
-        break;
-      case _UPB_MODE_MAP:
-        encode_map(e, msg, m, f);
-        break;
-      case _UPB_MODE_SCALAR:
-        encode_scalarfield(e, msg, m, f);
-        break;
-      default:
-        UPB_UNREACHABLE();
+    if (encode_shouldencode(e, msg, m->subs, f)) {
+      encode_field(e, msg, m->subs, f);
     }
   }
 
   *size = (e->limit - e->ptr) - pre_len;
 }
 
-char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
-                    upb_arena *arena, size_t *size) {
+char* upb_Encode(const void* msg, const upb_MiniTable* l, int options,
+                 upb_Arena* arena, size_t* size) {
   upb_encstate e;
   unsigned depth = (unsigned)options >> 16;
 
-  e.alloc = upb_arena_alloc(arena);
+  e.alloc = upb_Arena_Alloc(arena);
   e.buf = NULL;
   e.limit = NULL;
   e.ptr = NULL;
   e.depth = depth ? depth : 64;
   e.options = options;
   _upb_mapsorter_init(&e.sorter);
-  char *ret = NULL;
+  char* ret = NULL;
 
   if (UPB_SETJMP(e.err)) {
     *size = 0;
@@ -1480,30 +1903,32 @@
 /** upb/msg.c ************************************************************/
 
 
-/** upb_msg *******************************************************************/
+/** upb_Message
+ * *******************************************************************/
 
-static const size_t overhead = sizeof(upb_msg_internaldata);
+static const size_t overhead = sizeof(upb_Message_InternalData);
 
-static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) {
-  ptrdiff_t size = sizeof(upb_msg_internal);
-  return (upb_msg_internal*)((char*)msg - size);
+static const upb_Message_Internal* upb_Message_Getinternal_const(
+    const upb_Message* msg) {
+  ptrdiff_t size = sizeof(upb_Message_Internal);
+  return (upb_Message_Internal*)((char*)msg - size);
 }
 
-upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) {
-  return _upb_msg_new_inl(l, a);
+upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a) {
+  return _upb_Message_New_inl(l, a);
 }
 
-void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l) {
-  void *mem = UPB_PTR_AT(msg, -sizeof(upb_msg_internal), char);
+void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) {
+  void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char);
   memset(mem, 0, upb_msg_sizeof(l));
 }
 
-static bool realloc_internal(upb_msg *msg, size_t need, upb_arena *arena) {
-  upb_msg_internal *in = upb_msg_getinternal(msg);
+static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) {
+  upb_Message_Internal* in = upb_Message_Getinternal(msg);
   if (!in->internal) {
     /* No internal data, allocate from scratch. */
-    size_t size = UPB_MAX(128, _upb_lg2ceilsize(need + overhead));
-    upb_msg_internaldata *internal = upb_arena_malloc(arena, size);
+    size_t size = UPB_MAX(128, _upb_Log2Ceilingsize(need + overhead));
+    upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size);
     if (!internal) return false;
     internal->size = size;
     internal->unknown_end = overhead;
@@ -1511,15 +1936,15 @@
     in->internal = internal;
   } else if (in->internal->ext_begin - in->internal->unknown_end < need) {
     /* Internal data is too small, reallocate. */
-    size_t new_size = _upb_lg2ceilsize(in->internal->size + need);
+    size_t new_size = _upb_Log2Ceilingsize(in->internal->size + need);
     size_t ext_bytes = in->internal->size - in->internal->ext_begin;
     size_t new_ext_begin = new_size - ext_bytes;
-    upb_msg_internaldata *internal =
-        upb_arena_realloc(arena, in->internal, in->internal->size, new_size);
+    upb_Message_InternalData* internal =
+        upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size);
     if (!internal) return false;
     if (ext_bytes) {
       /* Need to move extension data to the end. */
-      char *ptr = (char*)internal;
+      char* ptr = (char*)internal;
       memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes);
     }
     internal->ext_begin = new_ext_begin;
@@ -1530,24 +1955,24 @@
   return true;
 }
 
-bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
-                         upb_arena *arena) {
+bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len,
+                             upb_Arena* arena) {
   if (!realloc_internal(msg, len, arena)) return false;
-  upb_msg_internal *in = upb_msg_getinternal(msg);
+  upb_Message_Internal* in = upb_Message_Getinternal(msg);
   memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len);
   in->internal->unknown_end += len;
   return true;
 }
 
-void _upb_msg_discardunknown_shallow(upb_msg *msg) {
-  upb_msg_internal *in = upb_msg_getinternal(msg);
+void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
+  upb_Message_Internal* in = upb_Message_Getinternal(msg);
   if (in->internal) {
     in->internal->unknown_end = overhead;
   }
 }
 
-const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) {
-  const upb_msg_internal *in = upb_msg_getinternal_const(msg);
+const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) {
+  const upb_Message_Internal* in = upb_Message_Getinternal_const(msg);
   if (in->internal) {
     *len = in->internal->unknown_end - overhead;
     return (char*)(in->internal + 1);
@@ -1557,11 +1982,12 @@
   }
 }
 
-const upb_msg_ext *_upb_msg_getexts(const upb_msg *msg, size_t *count) {
-  const upb_msg_internal *in = upb_msg_getinternal_const(msg);
+const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg,
+                                                  size_t* count) {
+  const upb_Message_Internal* in = upb_Message_Getinternal_const(msg);
   if (in->internal) {
-    *count =
-        (in->internal->size - in->internal->ext_begin) / sizeof(upb_msg_ext);
+    *count = (in->internal->size - in->internal->ext_begin) /
+             sizeof(upb_Message_Extension);
     return UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
   } else {
     *count = 0;
@@ -1569,10 +1995,10 @@
   }
 }
 
-const upb_msg_ext *_upb_msg_getext(const upb_msg *msg,
-                                   const upb_msglayout_ext *e) {
+const upb_Message_Extension* _upb_Message_Getext(
+    const upb_Message* msg, const upb_MiniTable_Extension* e) {
   size_t n;
-  const upb_msg_ext *ext = _upb_msg_getexts(msg, &n);
+  const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n);
 
   /* For now we use linear search exclusively to find extensions. If this
    * becomes an issue due to messages with lots of extensions, we can introduce
@@ -1586,22 +2012,43 @@
   return NULL;
 }
 
-upb_msg_ext *_upb_msg_getorcreateext(upb_msg *msg, const upb_msglayout_ext *e,
-                                     upb_arena *arena) {
-  upb_msg_ext *ext = (upb_msg_ext*)_upb_msg_getext(msg, e);
+void _upb_Message_Clearext(upb_Message* msg,
+                           const upb_MiniTable_Extension* ext_l) {
+  upb_Message_Internal* in = upb_Message_Getinternal(msg);
+  if (!in->internal) return;
+  const upb_Message_Extension* base =
+      UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
+  upb_Message_Extension* ext =
+      (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l);
+  if (ext) {
+    *ext = *base;
+    in->internal->ext_begin += sizeof(upb_Message_Extension);
+  }
+}
+
+upb_Message_Extension* _upb_Message_Getorcreateext(
+    upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) {
+  upb_Message_Extension* ext =
+      (upb_Message_Extension*)_upb_Message_Getext(msg, e);
   if (ext) return ext;
-  if (!realloc_internal(msg, sizeof(upb_msg_ext), arena)) return NULL;
-  upb_msg_internal *in = upb_msg_getinternal(msg);
-  in->internal->ext_begin -= sizeof(upb_msg_ext);
+  if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL;
+  upb_Message_Internal* in = upb_Message_Getinternal(msg);
+  in->internal->ext_begin -= sizeof(upb_Message_Extension);
   ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
-  memset(ext, 0, sizeof(upb_msg_ext));
+  memset(ext, 0, sizeof(upb_Message_Extension));
   ext->ext = e;
   return ext;
 }
 
-/** upb_array *****************************************************************/
+size_t upb_Message_ExtensionCount(const upb_Message* msg) {
+  size_t count;
+  _upb_Message_Getexts(msg, &count);
+  return count;
+}
 
-bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) {
+/** upb_Array *****************************************************************/
+
+bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena) {
   size_t new_size = UPB_MAX(arr->size, 4);
   int elem_size_lg2 = arr->data & 7;
   size_t old_bytes = arr->size << elem_size_lg2;
@@ -1612,7 +2059,7 @@
   while (new_size < min_size) new_size *= 2;
 
   new_bytes = new_size << elem_size_lg2;
-  ptr = upb_arena_realloc(arena, ptr, old_bytes, new_bytes);
+  ptr = upb_Arena_Realloc(arena, ptr, old_bytes, new_bytes);
 
   if (!ptr) {
     return false;
@@ -1623,44 +2070,44 @@
   return true;
 }
 
-static upb_array *getorcreate_array(upb_array **arr_ptr, int elem_size_lg2,
-                                    upb_arena *arena) {
-  upb_array *arr = *arr_ptr;
+static upb_Array* getorcreate_array(upb_Array** arr_ptr, int elem_size_lg2,
+                                    upb_Arena* arena) {
+  upb_Array* arr = *arr_ptr;
   if (!arr) {
-    arr = _upb_array_new(arena, 4, elem_size_lg2);
+    arr = _upb_Array_New(arena, 4, elem_size_lg2);
     if (!arr) return NULL;
     *arr_ptr = arr;
   }
   return arr;
 }
 
-void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size,
-                                 int elem_size_lg2, upb_arena *arena) {
-  upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
-  return arr && _upb_array_resize(arr, size, arena) ? _upb_array_ptr(arr)
+void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size,
+                                 int elem_size_lg2, upb_Arena* arena) {
+  upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
+  return arr && _upb_Array_Resize(arr, size, arena) ? _upb_array_ptr(arr)
                                                     : NULL;
 }
 
-bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value,
-                                int elem_size_lg2, upb_arena *arena) {
-  upb_array *arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
+bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value,
+                                int elem_size_lg2, upb_Arena* arena) {
+  upb_Array* arr = getorcreate_array(arr_ptr, elem_size_lg2, arena);
   if (!arr) return false;
 
   size_t elems = arr->len;
 
-  if (!_upb_array_resize(arr, elems + 1, arena)) {
+  if (!_upb_Array_Resize(arr, elems + 1, arena)) {
     return false;
   }
 
-  char *data = _upb_array_ptr(arr);
+  char* data = _upb_array_ptr(arr);
   memcpy(data + (elems << elem_size_lg2), value, 1 << elem_size_lg2);
   return true;
 }
 
-/** upb_map *******************************************************************/
+/** upb_Map *******************************************************************/
 
-upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) {
-  upb_map *map = upb_arena_malloc(a, sizeof(upb_map));
+upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) {
+  upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map));
 
   if (!map) {
     return NULL;
@@ -1673,65 +2120,69 @@
   return map;
 }
 
-static void _upb_mapsorter_getkeys(const void *_a, const void *_b, void *a_key,
-                                   void *b_key, size_t size) {
-  const upb_tabent *const*a = _a;
-  const upb_tabent *const*b = _b;
-  upb_strview a_tabkey = upb_tabstrview((*a)->key);
-  upb_strview b_tabkey = upb_tabstrview((*b)->key);
+static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key,
+                                   void* b_key, size_t size) {
+  const upb_tabent* const* a = _a;
+  const upb_tabent* const* b = _b;
+  upb_StringView a_tabkey = upb_tabstrview((*a)->key);
+  upb_StringView b_tabkey = upb_tabstrview((*b)->key);
   _upb_map_fromkey(a_tabkey, a_key, size);
   _upb_map_fromkey(b_tabkey, b_key, size);
 }
 
-static int _upb_mapsorter_cmpi64(const void *_a, const void *_b) {
+#define UPB_COMPARE_INTEGERS(a, b) ((a) < (b) ? -1 : ((a) == (b) ? 0 : 1))
+
+static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) {
   int64_t a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
-  return a - b;
+  return UPB_COMPARE_INTEGERS(a, b);
 }
 
-static int _upb_mapsorter_cmpu64(const void *_a, const void *_b) {
+static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) {
   uint64_t a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, 8);
-  return a - b;
+  return UPB_COMPARE_INTEGERS(a, b);
 }
 
-static int _upb_mapsorter_cmpi32(const void *_a, const void *_b) {
+static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) {
   int32_t a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
-  return a - b;
+  return UPB_COMPARE_INTEGERS(a, b);
 }
 
-static int _upb_mapsorter_cmpu32(const void *_a, const void *_b) {
+static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) {
   uint32_t a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, 4);
-  return a - b;
+  return UPB_COMPARE_INTEGERS(a, b);
 }
 
-static int _upb_mapsorter_cmpbool(const void *_a, const void *_b) {
+static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) {
   bool a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, 1);
-  return a - b;
+  return UPB_COMPARE_INTEGERS(a, b);
 }
 
-static int _upb_mapsorter_cmpstr(const void *_a, const void *_b) {
-  upb_strview a, b;
+static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) {
+  upb_StringView a, b;
   _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING);
   size_t common_size = UPB_MIN(a.size, b.size);
   int cmp = memcmp(a.data, b.data, common_size);
-  if (cmp) return cmp;
-  return a.size - b.size;
+  if (cmp) return -cmp;
+  return UPB_COMPARE_INTEGERS(a.size, b.size);
 }
 
-bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
-                            const upb_map *map, _upb_sortedmap *sorted) {
-  int map_size = _upb_map_size(map);
+#undef UPB_COMPARE_INTEGERS
+
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+                            const upb_Map* map, _upb_sortedmap* sorted) {
+  int map_size = _upb_Map_Size(map);
   sorted->start = s->size;
   sorted->pos = sorted->start;
   sorted->end = sorted->start + map_size;
 
   /* Grow s->entries if necessary. */
   if (sorted->end > s->cap) {
-    s->cap = _upb_lg2ceilsize(sorted->end);
+    s->cap = _upb_Log2Ceilingsize(sorted->end);
     s->entries = realloc(s->entries, s->cap * sizeof(*s->entries));
     if (!s->entries) return false;
   }
@@ -1739,9 +2190,9 @@
   s->size = sorted->end;
 
   /* Copy non-empty entries from the table to s->entries. */
-  upb_tabent const**dst = &s->entries[sorted->start];
-  const upb_tabent *src = map->table.t.entries;
-  const upb_tabent *end = src + upb_table_size(&map->table.t);
+  upb_tabent const** dst = &s->entries[sorted->start];
+  const upb_tabent* src = map->table.t.entries;
+  const upb_tabent* end = src + upb_table_size(&map->table.t);
   for (; src < end; src++) {
     if (!upb_tabent_isempty(src)) {
       *dst = src;
@@ -1752,32 +2203,33 @@
 
   /* Sort entries according to the key type. */
 
-  int (*compar)(const void *, const void *);
+  int (*compar)(const void*, const void*);
 
   switch (key_type) {
-    case UPB_DESCRIPTOR_TYPE_INT64:
-    case UPB_DESCRIPTOR_TYPE_SFIXED64:
-    case UPB_DESCRIPTOR_TYPE_SINT64:
+    case kUpb_FieldType_Int64:
+    case kUpb_FieldType_SFixed64:
+    case kUpb_FieldType_SInt64:
       compar = _upb_mapsorter_cmpi64;
       break;
-    case UPB_DESCRIPTOR_TYPE_UINT64:
-    case UPB_DESCRIPTOR_TYPE_FIXED64:
+    case kUpb_FieldType_UInt64:
+    case kUpb_FieldType_Fixed64:
       compar = _upb_mapsorter_cmpu64;
       break;
-    case UPB_DESCRIPTOR_TYPE_INT32:
-    case UPB_DESCRIPTOR_TYPE_SINT32:
-    case UPB_DESCRIPTOR_TYPE_SFIXED32:
-    case UPB_DESCRIPTOR_TYPE_ENUM:
+    case kUpb_FieldType_Int32:
+    case kUpb_FieldType_SInt32:
+    case kUpb_FieldType_SFixed32:
+    case kUpb_FieldType_Enum:
       compar = _upb_mapsorter_cmpi32;
       break;
-    case UPB_DESCRIPTOR_TYPE_UINT32:
-    case UPB_DESCRIPTOR_TYPE_FIXED32:
+    case kUpb_FieldType_UInt32:
+    case kUpb_FieldType_Fixed32:
       compar = _upb_mapsorter_cmpu32;
       break;
-    case UPB_DESCRIPTOR_TYPE_BOOL:
+    case kUpb_FieldType_Bool:
       compar = _upb_mapsorter_cmpbool;
       break;
-    case UPB_DESCRIPTOR_TYPE_STRING:
+    case kUpb_FieldType_String:
+    case kUpb_FieldType_Bytes:
       compar = _upb_mapsorter_cmpstr;
       break;
     default:
@@ -1788,36 +2240,39 @@
   return true;
 }
 
-/** upb_extreg ****************************************************************/
+/** upb_ExtensionRegistry
+ * ****************************************************************/
 
-struct upb_extreg {
-  upb_arena *arena;
-  upb_strtable exts;  /* Key is upb_msglayout* concatenated with fieldnum. */
+struct upb_ExtensionRegistry {
+  upb_Arena* arena;
+  upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */
 };
 
-#define EXTREG_KEY_SIZE (sizeof(upb_msglayout*) + sizeof(uint32_t))
+#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t))
 
-static void extreg_key(char *buf, const upb_msglayout *l, uint32_t fieldnum) {
+static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) {
   memcpy(buf, &l, sizeof(l));
   memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum));
 }
 
-upb_extreg *upb_extreg_new(upb_arena *arena) {
-  upb_extreg *r = upb_arena_malloc(arena, sizeof(*r));
+upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) {
+  upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r));
   if (!r) return NULL;
   r->arena = arena;
   if (!upb_strtable_init(&r->exts, 8, arena)) return NULL;
   return r;
 }
 
-bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext *e, size_t count) {
+bool _upb_extreg_add(upb_ExtensionRegistry* r,
+                     const upb_MiniTable_Extension** e, size_t count) {
   char buf[EXTREG_KEY_SIZE];
-  const upb_msglayout_ext *start = e;
-  const upb_msglayout_ext *end = e + count;
+  const upb_MiniTable_Extension** start = e;
+  const upb_MiniTable_Extension** end = UPB_PTRADD(e, count);
   for (; e < end; e++) {
-    extreg_key(buf, e->extendee, e->field.number);
+    const upb_MiniTable_Extension* ext = *e;
+    extreg_key(buf, ext->extendee, ext->field.number);
     if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE,
-                             upb_value_constptr(e), r->arena)) {
+                             upb_value_constptr(ext), r->arena)) {
       goto failure;
     }
   }
@@ -1826,15 +2281,16 @@
 failure:
   /* Back out the entries previously added. */
   for (end = e, e = start; e < end; e++) {
-    extreg_key(buf, e->extendee, e->field.number);
-    upb_strtable_remove(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
+    const upb_MiniTable_Extension* ext = *e;
+    extreg_key(buf, ext->extendee, ext->field.number);
+    upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
   }
   return false;
 }
 
-const upb_msglayout_field *_upb_extreg_get(const upb_extreg *r,
-                                           const upb_msglayout *l,
-                                           uint32_t num) {
+const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r,
+                                               const upb_MiniTable* l,
+                                               uint32_t num) {
   char buf[EXTREG_KEY_SIZE];
   upb_value v;
   extreg_key(buf, l, num);
@@ -1857,11 +2313,11 @@
 
 /* Must be last. */
 
-#define UPB_MAXARRSIZE 16  /* 64k. */
+#define UPB_MAXARRSIZE 16 /* 64k. */
 
 /* From Chromium. */
 #define ARRAY_SIZE(x) \
-    ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+  ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
 
 static const double MAX_LOAD = 0.85;
 
@@ -1882,20 +2338,20 @@
   int ret = 0;
   bool pow2 = is_pow2(v);
   while (v >>= 1) ret++;
-  ret = pow2 ? ret : ret + 1;  /* Ceiling. */
+  ret = pow2 ? ret : ret + 1; /* Ceiling. */
   return UPB_MIN(UPB_MAXARRSIZE, ret);
 }
 
-char *upb_strdup2(const char *s, size_t len, upb_arena *a) {
+char* upb_strdup2(const char* s, size_t len, upb_Arena* a) {
   size_t n;
-  char *p;
+  char* p;
 
   /* Prevent overflow errors. */
   if (len == SIZE_MAX) return NULL;
   /* Always null-terminate, even if binary data; but don't rely on the input to
    * have a null-terminating byte since it may be a raw binary buffer. */
   n = len + 1;
-  p = upb_arena_malloc(a, n);
+  p = upb_Arena_Malloc(a, n);
   if (p) {
     memcpy(p, s, len);
     p[len] = 0;
@@ -1907,12 +2363,12 @@
 typedef union {
   uintptr_t num;
   struct {
-    const char *str;
+    const char* str;
     size_t len;
   } str;
 } lookupkey_t;
 
-static lookupkey_t strkey2(const char *str, size_t len) {
+static lookupkey_t strkey2(const char* str, size_t len) {
   lookupkey_t k;
   k.str.str = str;
   k.str.len = len;
@@ -1930,24 +2386,17 @@
 
 /* Base table (shared code) ***************************************************/
 
-static uint32_t upb_inthash(uintptr_t key) {
-  return (uint32_t)key;
-}
+static uint32_t upb_inthash(uintptr_t key) { return (uint32_t)key; }
 
-static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
+static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) {
   return t->entries + (hash & t->mask);
 }
 
-static bool upb_arrhas(upb_tabval key) {
-  return key.val != (uint64_t)-1;
-}
+static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; }
 
+static bool isfull(upb_table* t) { return t->count == t->max_count; }
 
-static bool isfull(upb_table *t) {
-  return t->count == t->max_count;
-}
-
-static bool init(upb_table *t, uint8_t size_lg2, upb_arena *a) {
+static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) {
   size_t bytes;
 
   t->count = 0;
@@ -1956,7 +2405,7 @@
   t->max_count = upb_table_size(t) * MAX_LOAD;
   bytes = upb_table_size(t) * sizeof(upb_tabent);
   if (bytes > 0) {
-    t->entries = upb_arena_malloc(a, bytes);
+    t->entries = upb_Arena_Malloc(a, bytes);
     if (!t->entries) return false;
     memset(t->entries, 0, bytes);
   } else {
@@ -1965,9 +2414,9 @@
   return true;
 }
 
-static upb_tabent *emptyent(upb_table *t, upb_tabent *e) {
-  upb_tabent *begin = t->entries;
-  upb_tabent *end = begin + upb_table_size(t);
+static upb_tabent* emptyent(upb_table* t, upb_tabent* e) {
+  upb_tabent* begin = t->entries;
+  upb_tabent* end = begin + upb_table_size(t);
   for (e = e + 1; e < end; e++) {
     if (upb_tabent_isempty(e)) return e;
   }
@@ -1978,13 +2427,13 @@
   return NULL;
 }
 
-static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) {
   return (upb_tabent*)upb_getentry(t, hash);
 }
 
-static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
-                                   uint32_t hash, eqlfunc_t *eql) {
-  const upb_tabent *e;
+static const upb_tabent* findentry(const upb_table* t, lookupkey_t key,
+                                   uint32_t hash, eqlfunc_t* eql) {
+  const upb_tabent* e;
 
   if (t->size_lg2 == 0) return NULL;
   e = upb_getentry(t, hash);
@@ -1995,14 +2444,14 @@
   }
 }
 
-static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
-                                     uint32_t hash, eqlfunc_t *eql) {
+static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key,
+                                     uint32_t hash, eqlfunc_t* eql) {
   return (upb_tabent*)findentry(t, key, hash, eql);
 }
 
-static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
-                   uint32_t hash, eqlfunc_t *eql) {
-  const upb_tabent *e = findentry(t, key, hash, eql);
+static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v,
+                   uint32_t hash, eqlfunc_t* eql) {
+  const upb_tabent* e = findentry(t, key, hash, eql);
   if (e) {
     if (v) {
       _upb_value_setval(v, e->val.val);
@@ -2014,11 +2463,11 @@
 }
 
 /* The given key must not already exist in the table. */
-static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
-                   upb_value val, uint32_t hash,
-                   hashfunc_t *hashfunc, eqlfunc_t *eql) {
-  upb_tabent *mainpos_e;
-  upb_tabent *our_e;
+static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey,
+                   upb_value val, uint32_t hash, hashfunc_t* hashfunc,
+                   eqlfunc_t* eql) {
+  upb_tabent* mainpos_e;
+  upb_tabent* our_e;
 
   UPB_ASSERT(findentry(t, key, hash, eql) == NULL);
 
@@ -2031,12 +2480,13 @@
     our_e->next = NULL;
   } else {
     /* Collision. */
-    upb_tabent *new_e = emptyent(t, mainpos_e);
+    upb_tabent* new_e = emptyent(t, mainpos_e);
     /* Head of collider's chain. */
-    upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+    upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key));
     if (chain == mainpos_e) {
       /* Existing ent is in its main position (it has the same hash as us, and
-       * is the head of our chain).  Insert to new ent and append to this chain. */
+       * is the head of our chain).  Insert to new ent and append to this chain.
+       */
       new_e->next = mainpos_e->next;
       mainpos_e->next = new_e;
       our_e = new_e;
@@ -2044,7 +2494,7 @@
       /* Existing ent is not in its main position (it is a node in some other
        * chain).  This implies that no existing ent in the table has our hash.
        * Evict it (updating its chain) and use its ent for head of our chain. */
-      *new_e = *mainpos_e;  /* copies next. */
+      *new_e = *mainpos_e; /* copies next. */
       while (chain->next != mainpos_e) {
         chain = (upb_tabent*)chain->next;
         UPB_ASSERT(chain);
@@ -2059,9 +2509,9 @@
   UPB_ASSERT(findentry(t, key, hash, eql) == our_e);
 }
 
-static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
-               upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
-  upb_tabent *chain = getentry_mutable(t, hash);
+static bool rm(upb_table* t, lookupkey_t key, upb_value* val,
+               upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) {
+  upb_tabent* chain = getentry_mutable(t, hash);
   if (upb_tabent_isempty(chain)) return false;
   if (eql(chain->key, key)) {
     /* Element to remove is at the head of its chain. */
@@ -2069,11 +2519,11 @@
     if (val) _upb_value_setval(val, chain->val.val);
     if (removed) *removed = chain->key;
     if (chain->next) {
-      upb_tabent *move = (upb_tabent*)chain->next;
+      upb_tabent* move = (upb_tabent*)chain->next;
       *chain = *move;
-      move->key = 0;  /* Make the slot empty. */
+      move->key = 0; /* Make the slot empty. */
     } else {
-      chain->key = 0;  /* Make the slot empty. */
+      chain->key = 0; /* Make the slot empty. */
     }
     return true;
   } else {
@@ -2084,11 +2534,11 @@
     }
     if (chain->next) {
       /* Found element to remove. */
-      upb_tabent *rm = (upb_tabent*)chain->next;
+      upb_tabent* rm = (upb_tabent*)chain->next;
       t->count--;
       if (val) _upb_value_setval(val, chain->next->val.val);
       if (removed) *removed = rm->key;
-      rm->key = 0;  /* Make the slot empty. */
+      rm->key = 0; /* Make the slot empty. */
       chain->next = rm->next;
       return true;
     } else {
@@ -2098,27 +2548,24 @@
   }
 }
 
-static size_t next(const upb_table *t, size_t i) {
+static size_t next(const upb_table* t, size_t i) {
   do {
-    if (++i >= upb_table_size(t))
-      return SIZE_MAX - 1;  /* Distinct from -1. */
-  } while(upb_tabent_isempty(&t->entries[i]));
+    if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */
+  } while (upb_tabent_isempty(&t->entries[i]));
 
   return i;
 }
 
-static size_t begin(const upb_table *t) {
-  return next(t, -1);
-}
-
+static size_t begin(const upb_table* t) { return next(t, -1); }
 
 /* upb_strtable ***************************************************************/
 
-/* A simple "subclass" of upb_table that only adds a hash function for strings. */
+/* A simple "subclass" of upb_table that only adds a hash function for strings.
+ */
 
-static upb_tabkey strcopy(lookupkey_t k2, upb_arena *a) {
-  uint32_t len = (uint32_t) k2.str.len;
-  char *str = upb_arena_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
+static upb_tabkey strcopy(lookupkey_t k2, upb_Arena* a) {
+  uint32_t len = (uint32_t)k2.str.len;
+  char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1);
   if (str == NULL) return 0;
   memcpy(str, &len, sizeof(uint32_t));
   if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len);
@@ -2128,13 +2575,13 @@
 
 /* Adapted from ABSL's wyhash. */
 
-static uint64_t UnalignedLoad64(const void *p) {
+static uint64_t UnalignedLoad64(const void* p) {
   uint64_t val;
   memcpy(&val, p, 8);
   return val;
 }
 
-static uint32_t UnalignedLoad32(const void *p) {
+static uint32_t UnalignedLoad32(const void* p) {
   uint32_t val;
   memcpy(&val, p, 4);
   return val;
@@ -2177,8 +2624,8 @@
   return low ^ high;
 }
 
-uint64_t Wyhash(const void *data, size_t len, uint64_t seed,
-                const uint64_t salt[]) {
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+                       const uint64_t salt[]) {
   const uint8_t* ptr = (const uint8_t*)data;
   uint64_t starting_length = (uint64_t)len;
   uint64_t current_state = seed ^ salt[0];
@@ -2261,45 +2708,45 @@
     0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL,
 };
 
-static uint32_t table_hash(const char *p, size_t n) {
+static uint32_t table_hash(const char* p, size_t n) {
   return Wyhash(p, n, 0, kWyhashSalt);
 }
 
 static uint32_t strhash(upb_tabkey key) {
   uint32_t len;
-  char *str = upb_tabstr(key, &len);
+  char* str = upb_tabstr(key, &len);
   return table_hash(str, len);
 }
 
 static bool streql(upb_tabkey k1, lookupkey_t k2) {
   uint32_t len;
-  char *str = upb_tabstr(k1, &len);
+  char* str = upb_tabstr(k1, &len);
   return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0);
 }
 
-bool upb_strtable_init(upb_strtable *t, size_t expected_size, upb_arena *a) {
-  // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2 denominator.
+bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) {
+  // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2
+  // denominator.
   size_t need_entries = (expected_size + 1) * 1204 / 1024;
   UPB_ASSERT(need_entries >= expected_size * 0.85);
-  int size_lg2 = _upb_lg2ceil(need_entries);
+  int size_lg2 = _upb_Log2Ceiling(need_entries);
   return init(&t->t, size_lg2, a);
 }
 
-void upb_strtable_clear(upb_strtable *t) {
+void upb_strtable_clear(upb_strtable* t) {
   size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent);
   t->t.count = 0;
   memset((char*)t->t.entries, 0, bytes);
 }
 
-bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a) {
+bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) {
   upb_strtable new_table;
   upb_strtable_iter i;
 
-  if (!init(&new_table.t, size_lg2, a))
-    return false;
+  if (!init(&new_table.t, size_lg2, a)) return false;
   upb_strtable_begin(&i, t);
-  for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
-    upb_strview key = upb_strtable_iter_key(&i);
+  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    upb_StringView key = upb_strtable_iter_key(&i);
     upb_strtable_insert(&new_table, key.data, key.size,
                         upb_strtable_iter_value(&i), a);
   }
@@ -2307,8 +2754,8 @@
   return true;
 }
 
-bool upb_strtable_insert(upb_strtable *t, const char *k, size_t len,
-                         upb_value v, upb_arena *a) {
+bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len,
+                         upb_value v, upb_Arena* a) {
   lookupkey_t key;
   upb_tabkey tabkey;
   uint32_t hash;
@@ -2329,14 +2776,14 @@
   return true;
 }
 
-bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
-                          upb_value *v) {
+bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
+                          upb_value* v) {
   uint32_t hash = table_hash(key, len);
   return lookup(&t->t, strkey2(key, len), v, hash, &streql);
 }
 
-bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len,
-                         upb_value *val) {
+bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
+                          upb_value* val) {
   uint32_t hash = table_hash(key, len);
   upb_tabkey tabkey;
   return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql);
@@ -2344,23 +2791,23 @@
 
 /* Iteration */
 
-void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) {
   i->t = t;
   i->index = begin(&t->t);
 }
 
-void upb_strtable_next(upb_strtable_iter *i) {
+void upb_strtable_next(upb_strtable_iter* i) {
   i->index = next(&i->t->t, i->index);
 }
 
-bool upb_strtable_done(const upb_strtable_iter *i) {
+bool upb_strtable_done(const upb_strtable_iter* i) {
   if (!i->t) return true;
   return i->index >= upb_table_size(&i->t->t) ||
          upb_tabent_isempty(str_tabent(i));
 }
 
-upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) {
-  upb_strview key;
+upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) {
+  upb_StringView key;
   uint32_t len;
   UPB_ASSERT(!upb_strtable_done(i));
   key.data = upb_tabstr(str_tabent(i)->key, &len);
@@ -2368,24 +2815,22 @@
   return key;
 }
 
-upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+upb_value upb_strtable_iter_value(const upb_strtable_iter* i) {
   UPB_ASSERT(!upb_strtable_done(i));
   return _upb_value_val(str_tabent(i)->val.val);
 }
 
-void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+void upb_strtable_iter_setdone(upb_strtable_iter* i) {
   i->t = NULL;
   i->index = SIZE_MAX;
 }
 
-bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
-                               const upb_strtable_iter *i2) {
-  if (upb_strtable_done(i1) && upb_strtable_done(i2))
-    return true;
+bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
+                               const upb_strtable_iter* i2) {
+  if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true;
   return i1->t == i2->t && i1->index == i2->index;
 }
 
-
 /* upb_inttable ***************************************************************/
 
 /* For inttables we use a hybrid structure where small keys are kept in an
@@ -2393,34 +2838,32 @@
 
 static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
 
-static bool inteql(upb_tabkey k1, lookupkey_t k2) {
-  return k1 == k2.num;
-}
+static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; }
 
-static upb_tabval *mutable_array(upb_inttable *t) {
+static upb_tabval* mutable_array(upb_inttable* t) {
   return (upb_tabval*)t->array;
 }
 
-static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) {
+static upb_tabval* inttable_val(upb_inttable* t, uintptr_t key) {
   if (key < t->array_size) {
     return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
   } else {
-    upb_tabent *e =
+    upb_tabent* e =
         findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
     return e ? &e->val : NULL;
   }
 }
 
-static const upb_tabval *inttable_val_const(const upb_inttable *t,
+static const upb_tabval* inttable_val_const(const upb_inttable* t,
                                             uintptr_t key) {
   return inttable_val((upb_inttable*)t, key);
 }
 
-size_t upb_inttable_count(const upb_inttable *t) {
+size_t upb_inttable_count(const upb_inttable* t) {
   return t->t.count + t->array_count;
 }
 
-static void check(upb_inttable *t) {
+static void check(upb_inttable* t) {
   UPB_UNUSED(t);
 #if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
   {
@@ -2428,7 +2871,7 @@
     size_t count = 0;
     upb_inttable_iter i;
     upb_inttable_begin(&i, t);
-    for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+    for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
       UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
     }
     UPB_ASSERT(count == upb_inttable_count(t));
@@ -2436,8 +2879,8 @@
 #endif
 }
 
-bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2,
-                            upb_arena *a) {
+bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2,
+                            upb_Arena* a) {
   size_t array_bytes;
 
   if (!init(&t->t, hsize_lg2, a)) return false;
@@ -2446,7 +2889,7 @@
   t->array_size = UPB_MAX(1, asize);
   t->array_count = 0;
   array_bytes = t->array_size * sizeof(upb_value);
-  t->array = upb_arena_malloc(a, array_bytes);
+  t->array = upb_Arena_Malloc(a, array_bytes);
   if (!t->array) {
     return false;
   }
@@ -2455,15 +2898,16 @@
   return true;
 }
 
-bool upb_inttable_init(upb_inttable *t, upb_arena *a) {
+bool upb_inttable_init(upb_inttable* t, upb_Arena* a) {
   return upb_inttable_sizedinit(t, 0, 4, a);
 }
 
-bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val,
-                         upb_arena *a) {
+bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
+                         upb_Arena* a) {
   upb_tabval tabval;
   tabval.val = val.val;
-  UPB_ASSERT(upb_arrhas(tabval));  /* This will reject (uint64_t)-1.  Fix this. */
+  UPB_ASSERT(
+      upb_arrhas(tabval)); /* This will reject (uint64_t)-1.  Fix this. */
 
   if (key < t->array_size) {
     UPB_ASSERT(!upb_arrhas(t->array[key]));
@@ -2480,7 +2924,7 @@
       }
 
       for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
-        const upb_tabent *e = &t->t.entries[i];
+        const upb_tabent* e = &t->t.entries[i];
         uint32_t hash;
         upb_value v;
 
@@ -2499,21 +2943,21 @@
   return true;
 }
 
-bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
-  const upb_tabval *table_v = inttable_val_const(t, key);
+bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) {
+  const upb_tabval* table_v = inttable_val_const(t, key);
   if (!table_v) return false;
   if (v) _upb_value_setval(v, table_v->val);
   return true;
 }
 
-bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
-  upb_tabval *table_v = inttable_val(t, key);
+bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) {
+  upb_tabval* table_v = inttable_val(t, key);
   if (!table_v) return false;
   table_v->val = val.val;
   return true;
 }
 
-bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) {
   bool success;
   if (key < t->array_size) {
     if (upb_arrhas(t->array[key])) {
@@ -2534,7 +2978,7 @@
   return success;
 }
 
-void upb_inttable_compact(upb_inttable *t, upb_arena *a) {
+void upb_inttable_compact(upb_inttable* t, upb_Arena* a) {
   /* A power-of-two histogram of the table keys. */
   size_t counts[UPB_MAXARRSIZE + 1] = {0};
 
@@ -2573,7 +3017,7 @@
 
   {
     /* Insert all elements into new, perfectly-sized table. */
-    size_t arr_size = max[size_lg2] + 1;  /* +1 so arr[max] will fit. */
+    size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */
     size_t hash_count = upb_inttable_count(t) - arr_count;
     size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
     int hashsize_lg2 = log2ceil(hash_size);
@@ -2592,25 +3036,25 @@
 
 /* Iteration. */
 
-static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+static const upb_tabent* int_tabent(const upb_inttable_iter* i) {
   UPB_ASSERT(!i->array_part);
   return &i->t->t.entries[i->index];
 }
 
-static upb_tabval int_arrent(const upb_inttable_iter *i) {
+static upb_tabval int_arrent(const upb_inttable_iter* i) {
   UPB_ASSERT(i->array_part);
   return i->t->array[i->index];
 }
 
-void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t) {
   i->t = t;
   i->index = -1;
   i->array_part = true;
   upb_inttable_next(i);
 }
 
-void upb_inttable_next(upb_inttable_iter *iter) {
-  const upb_inttable *t = iter->t;
+void upb_inttable_next(upb_inttable_iter* iter) {
+  const upb_inttable* t = iter->t;
   if (iter->array_part) {
     while (++iter->index < t->array_size) {
       if (upb_arrhas(int_arrent(iter))) {
@@ -2624,45 +3068,137 @@
   }
 }
 
-bool upb_inttable_done(const upb_inttable_iter *i) {
+bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val,
+                        intptr_t* iter) {
+  intptr_t i = *iter;
+  if (i < t->array_size) {
+    while (++i < t->array_size) {
+      upb_tabval ent = t->array[i];
+      if (upb_arrhas(ent)) {
+        *key = i;
+        *val = _upb_value_val(ent.val);
+        *iter = i;
+        return true;
+      }
+    }
+  }
+
+  size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size);
+  if (tab_idx < upb_table_size(&t->t)) {
+    upb_tabent* ent = &t->t.entries[tab_idx];
+    *key = ent->key;
+    *val = _upb_value_val(ent->val.val);
+    *iter = tab_idx + t->array_size;
+    return true;
+  }
+
+  return false;
+}
+
+void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) {
+  intptr_t i = *iter;
+  if (i < t->array_size) {
+    t->array_count--;
+    mutable_array(t)[i].val = -1;
+  } else {
+    upb_tabent* ent = &t->t.entries[i - t->array_size];
+    upb_tabent* prev = NULL;
+
+    // Linear search, not great.
+    upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
+    for (upb_tabent* e = t->t.entries; e != end; e++) {
+      if (e->next == ent) {
+        prev = e;
+        break;
+      }
+    }
+
+    if (prev) {
+      prev->next = ent->next;
+    }
+
+    t->t.count--;
+    ent->key = 0;
+    ent->next = NULL;
+  }
+}
+
+bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
+                        upb_value* val, intptr_t* iter) {
+  size_t tab_idx = next(&t->t, *iter);
+  if (tab_idx < upb_table_size(&t->t)) {
+    upb_tabent* ent = &t->t.entries[tab_idx];
+    uint32_t len;
+    key->data = upb_tabstr(ent->key, &len);
+    key->size = len;
+    *val = _upb_value_val(ent->val.val);
+    *iter = tab_idx;
+    return true;
+  }
+
+  return false;
+}
+
+void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) {
+  intptr_t i = *iter;
+  upb_tabent* ent = &t->t.entries[i];
+  upb_tabent* prev = NULL;
+
+  // Linear search, not great.
+  upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
+  for (upb_tabent* e = t->t.entries; e != end; e++) {
+    if (e->next == ent) {
+      prev = e;
+      break;
+    }
+  }
+
+  if (prev) {
+    prev->next = ent->next;
+  }
+
+  t->t.count--;
+  ent->key = 0;
+  ent->next = NULL;
+}
+
+bool upb_inttable_done(const upb_inttable_iter* i) {
   if (!i->t) return true;
   if (i->array_part) {
-    return i->index >= i->t->array_size ||
-           !upb_arrhas(int_arrent(i));
+    return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i));
   } else {
     return i->index >= upb_table_size(&i->t->t) ||
            upb_tabent_isempty(int_tabent(i));
   }
 }
 
-uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i) {
   UPB_ASSERT(!upb_inttable_done(i));
   return i->array_part ? i->index : int_tabent(i)->key;
 }
 
-upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+upb_value upb_inttable_iter_value(const upb_inttable_iter* i) {
   UPB_ASSERT(!upb_inttable_done(i));
-  return _upb_value_val(
-      i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val);
+  return _upb_value_val(i->array_part ? i->t->array[i->index].val
+                                      : int_tabent(i)->val.val);
 }
 
-void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+void upb_inttable_iter_setdone(upb_inttable_iter* i) {
   i->t = NULL;
   i->index = SIZE_MAX;
   i->array_part = false;
 }
 
-bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
-                                          const upb_inttable_iter *i2) {
-  if (upb_inttable_done(i1) && upb_inttable_done(i2))
-    return true;
+bool upb_inttable_iter_isequal(const upb_inttable_iter* i1,
+                               const upb_inttable_iter* i2) {
+  if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true;
   return i1->t == i2->t && i1->index == i2->index &&
          i1->array_part == i2->array_part;
 }
 
 /** upb/upb.c ************************************************************/
-
 #include <errno.h>
+#include <float.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -2671,51 +3207,57 @@
 #include <string.h>
 
 
-/* upb_status *****************************************************************/
+// Must be last.
 
-void upb_status_clear(upb_status *status) {
+/* upb_Status *****************************************************************/
+
+void upb_Status_Clear(upb_Status* status) {
   if (!status) return;
   status->ok = true;
   status->msg[0] = '\0';
 }
 
-bool upb_ok(const upb_status *status) { return status->ok; }
+bool upb_Status_IsOk(const upb_Status* status) { return status->ok; }
 
-const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
-
-void upb_status_seterrmsg(upb_status *status, const char *msg) {
-  if (!status) return;
-  status->ok = false;
-  strncpy(status->msg, msg, UPB_STATUS_MAX_MESSAGE - 1);
-  status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+const char* upb_Status_ErrorMessage(const upb_Status* status) {
+  return status->msg;
 }
 
-void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) {
+  if (!status) return;
+  status->ok = false;
+  strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1);
+  status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
+}
+
+void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) {
   va_list args;
   va_start(args, fmt);
-  upb_status_vseterrf(status, fmt, args);
+  upb_Status_VSetErrorFormat(status, fmt, args);
   va_end(args);
 }
 
-void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
+                                va_list args) {
   if (!status) return;
   status->ok = false;
   vsnprintf(status->msg, sizeof(status->msg), fmt, args);
-  status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+  status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
 }
 
-void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args) {
+void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
+                                   va_list args) {
   size_t len;
   if (!status) return;
   status->ok = false;
   len = strlen(status->msg);
   vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args);
-  status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
+  status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
 }
 
 /* upb_alloc ******************************************************************/
 
-static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
+static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
                                   size_t size) {
   UPB_UNUSED(alloc);
   UPB_UNUSED(oldsize);
@@ -2727,53 +3269,53 @@
   }
 }
 
-static uint32_t *upb_cleanup_pointer(uintptr_t cleanup_metadata) {
-  return (uint32_t *)(cleanup_metadata & ~0x1);
+static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) {
+  return (uint32_t*)(cleanup_metadata & ~0x1);
 }
 
 static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) {
   return cleanup_metadata & 0x1;
 }
 
-static uintptr_t upb_cleanup_metadata(uint32_t *cleanup,
+static uintptr_t upb_cleanup_metadata(uint32_t* cleanup,
                                       bool has_initial_block) {
   return (uintptr_t)cleanup | has_initial_block;
 }
 
 upb_alloc upb_alloc_global = {&upb_global_allocfunc};
 
-/* upb_arena ******************************************************************/
+/* upb_Arena ******************************************************************/
 
 /* Be conservative and choose 16 in case anyone is using SSE. */
 
 struct mem_block {
-  struct mem_block *next;
+  struct mem_block* next;
   uint32_t size;
   uint32_t cleanups;
   /* Data follows. */
 };
 
 typedef struct cleanup_ent {
-  upb_cleanup_func *cleanup;
-  void *ud;
+  upb_CleanupFunc* cleanup;
+  void* ud;
 } cleanup_ent;
 
 static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16);
 
-static upb_arena *arena_findroot(upb_arena *a) {
+static upb_Arena* arena_findroot(upb_Arena* a) {
   /* Path splitting keeps time complexity down, see:
    *   https://en.wikipedia.org/wiki/Disjoint-set_data_structure */
   while (a->parent != a) {
-    upb_arena *next = a->parent;
+    upb_Arena* next = a->parent;
     a->parent = next->parent;
     a = next;
   }
   return a;
 }
 
-static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr,
+static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr,
                                size_t size) {
-  mem_block *block = ptr;
+  mem_block* block = ptr;
 
   /* The block is for arena |a|, but should appear in the freelist of |root|. */
   block->next = root->freelist;
@@ -2791,33 +3333,33 @@
   UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr);
 }
 
-static bool upb_arena_allocblock(upb_arena *a, size_t size) {
-  upb_arena *root = arena_findroot(a);
+static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) {
+  upb_Arena* root = arena_findroot(a);
   size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve;
-  mem_block *block = upb_malloc(root->block_alloc, block_size);
+  mem_block* block = upb_malloc(root->block_alloc, block_size);
 
   if (!block) return false;
-  upb_arena_addblock(a, root, block, block_size);
+  upb_Arena_addblock(a, root, block, block_size);
   return true;
 }
 
-void *_upb_arena_slowmalloc(upb_arena *a, size_t size) {
-  if (!upb_arena_allocblock(a, size)) return NULL;  /* Out of memory. */
-  UPB_ASSERT(_upb_arenahas(a) >= size);
-  return upb_arena_malloc(a, size);
+void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) {
+  if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */
+  UPB_ASSERT(_upb_ArenaHas(a) >= size);
+  return upb_Arena_Malloc(a, size);
 }
 
-static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize,
                                size_t size) {
-  upb_arena *a = (upb_arena*)alloc;  /* upb_alloc is initial member. */
-  return upb_arena_realloc(a, ptr, oldsize, size);
+  upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */
+  return upb_Arena_Realloc(a, ptr, oldsize, size);
 }
 
 /* Public Arena API ***********************************************************/
 
-upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) {
-  const size_t first_block_overhead = sizeof(upb_arena) + memblock_reserve;
-  upb_arena *a;
+upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) {
+  const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve;
+  upb_Arena* a;
 
   /* We need to malloc the initial block. */
   n = first_block_overhead + 256;
@@ -2825,10 +3367,10 @@
     return NULL;
   }
 
-  a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena);
+  a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
   n -= sizeof(*a);
 
-  a->head.alloc.func = &upb_arena_doalloc;
+  a->head.alloc.func = &upb_Arena_doalloc;
   a->block_alloc = alloc;
   a->parent = a;
   a->refcount = 1;
@@ -2836,25 +3378,33 @@
   a->freelist_tail = NULL;
   a->cleanup_metadata = upb_cleanup_metadata(NULL, false);
 
-  upb_arena_addblock(a, a, mem, n);
+  upb_Arena_addblock(a, a, mem, n);
 
   return a;
 }
 
-upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) {
-  upb_arena *a;
+upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
+  upb_Arena* a;
+
+  if (n) {
+    /* Align initial pointer up so that we return properly-aligned pointers. */
+    void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16);
+    size_t delta = (uintptr_t)aligned - (uintptr_t)mem;
+    n = delta <= n ? n - delta : 0;
+    mem = aligned;
+  }
 
   /* Round block size down to alignof(*a) since we will allocate the arena
    * itself at the end. */
-  n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_arena));
+  n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena));
 
-  if (UPB_UNLIKELY(n < sizeof(upb_arena))) {
+  if (UPB_UNLIKELY(n < sizeof(upb_Arena))) {
     return arena_initslow(mem, n, alloc);
   }
 
-  a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena);
+  a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
 
-  a->head.alloc.func = &upb_arena_doalloc;
+  a->head.alloc.func = &upb_Arena_doalloc;
   a->block_alloc = alloc;
   a->parent = a;
   a->refcount = 1;
@@ -2867,18 +3417,18 @@
   return a;
 }
 
-static void arena_dofree(upb_arena *a) {
-  mem_block *block = a->freelist;
+static void arena_dofree(upb_Arena* a) {
+  mem_block* block = a->freelist;
   UPB_ASSERT(a->parent == a);
   UPB_ASSERT(a->refcount == 0);
 
   while (block) {
     /* Load first since we are deleting block. */
-    mem_block *next = block->next;
+    mem_block* next = block->next;
 
     if (block->cleanups > 0) {
-      cleanup_ent *end = UPB_PTR_AT(block, block->size, void);
-      cleanup_ent *ptr = end - block->cleanups;
+      cleanup_ent* end = UPB_PTR_AT(block, block->size, void);
+      cleanup_ent* ptr = end - block->cleanups;
 
       for (; ptr < end; ptr++) {
         ptr->cleanup(ptr->ud);
@@ -2890,18 +3440,18 @@
   }
 }
 
-void upb_arena_free(upb_arena *a) {
+void upb_Arena_Free(upb_Arena* a) {
   a = arena_findroot(a);
   if (--a->refcount == 0) arena_dofree(a);
 }
 
-bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) {
-  cleanup_ent *ent;
+bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) {
+  cleanup_ent* ent;
   uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata);
 
-  if (!cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) {
-    if (!upb_arena_allocblock(a, 128)) return false;  /* Out of memory. */
-    UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent));
+  if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) {
+    if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */
+    UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent));
     cleanups = upb_cleanup_pointer(a->cleanup_metadata);
   }
 
@@ -2916,11 +3466,11 @@
   return true;
 }
 
-bool upb_arena_fuse(upb_arena *a1, upb_arena *a2) {
-  upb_arena *r1 = arena_findroot(a1);
-  upb_arena *r2 = arena_findroot(a2);
+bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) {
+  upb_Arena* r1 = arena_findroot(a1);
+  upb_Arena* r2 = arena_findroot(a2);
 
-  if (r1 == r2) return true;  /* Already fused. */
+  if (r1 == r2) return true; /* Already fused. */
 
   /* Do not fuse initial blocks since we cannot lifetime extend them. */
   if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false;
@@ -2932,7 +3482,7 @@
   /* We want to join the smaller tree to the larger tree.
    * So swap first if they are backwards. */
   if (r1->refcount < r2->refcount) {
-    upb_arena *tmp = r1;
+    upb_Arena* tmp = r1;
     r1 = r2;
     r2 = tmp;
   }
@@ -2948,6 +3498,40 @@
   return true;
 }
 
+/* Miscellaneous utilities ****************************************************/
+
+static void upb_FixLocale(char* p) {
+  /* printf() is dependent on locales; sadly there is no easy and portable way
+   * to avoid this. This little post-processing step will translate 1,2 -> 1.2
+   * since JSON needs the latter. Arguably a hack, but it is simple and the
+   * alternatives are far more complicated, platform-dependent, and/or larger
+   * in code size. */
+  for (; *p; p++) {
+    if (*p == ',') *p = '.';
+  }
+}
+
+
+void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) {
+  assert(size >= kUpb_RoundTripBufferSize);
+  snprintf(buf, size, "%.*g", DBL_DIG, val);
+  if (strtod(buf, NULL) != val) {
+    snprintf(buf, size, "%.*g", DBL_DIG + 2, val);
+    assert(strtod(buf, NULL) == val);
+  }
+  upb_FixLocale(buf);
+}
+
+void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) {
+  assert(size >= kUpb_RoundTripBufferSize);
+  snprintf(buf, size, "%.*g", FLT_DIG, val);
+  if (strtof(buf, NULL) != val) {
+    snprintf(buf, size, "%.*g", FLT_DIG + 3, val);
+    assert(strtof(buf, NULL) == val);
+  }
+  upb_FixLocale(buf);
+}
+
 /** upb/decode_fast.c ************************************************************/
 // Fast decoder: ~3x the speed of decode.c, but requires x86-64/ARM64.
 // Also the table size grows by 2x.
@@ -2967,44 +3551,48 @@
 
 // The standard set of arguments passed to each parsing function.
 // Thanks to x86-64 calling conventions, these will stay in registers.
-#define UPB_PARSE_PARAMS                                          \
-  upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \
+#define UPB_PARSE_PARAMS                                             \
+  upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \
       uint64_t hasbits, uint64_t data
 
 #define UPB_PARSE_ARGS d, ptr, msg, table, hasbits, data
 
-#define RETURN_GENERIC(m)                                                      \
-  /* Uncomment either of these for debugging purposes. */                      \
-  /* fprintf(stderr, m); */                                                    \
-  /*__builtin_trap(); */                                                       \
+#define RETURN_GENERIC(m)                                 \
+  /* Uncomment either of these for debugging purposes. */ \
+  /* fprintf(stderr, m); */                               \
+  /*__builtin_trap(); */                                  \
   return fastdecode_generic(d, ptr, msg, table, hasbits, 0);
 
 typedef enum {
-  CARD_s = 0,  /* Singular (optional, non-repeated) */
-  CARD_o = 1,  /* Oneof */
-  CARD_r = 2,  /* Repeated */
-  CARD_p = 3   /* Packed Repeated */
+  CARD_s = 0, /* Singular (optional, non-repeated) */
+  CARD_o = 1, /* Oneof */
+  CARD_r = 2, /* Repeated */
+  CARD_p = 3  /* Packed Repeated */
 } upb_card;
 
 UPB_NOINLINE
-static const char *fastdecode_isdonefallback(UPB_PARSE_PARAMS) {
+static const char* fastdecode_isdonefallback(UPB_PARSE_PARAMS) {
   int overrun = data;
-  ptr = decode_isdonefallback_inl(d, ptr, overrun);
+  int status;
+  ptr = decode_isdonefallback_inl(d, ptr, overrun, &status);
   if (ptr == NULL) {
-    return fastdecode_err(d);
+    return fastdecode_err(d, status);
   }
   data = fastdecode_loadtag(ptr);
   UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);
 }
 
 UPB_FORCEINLINE
-static const char *fastdecode_dispatch(UPB_PARSE_PARAMS) {
+static const char* fastdecode_dispatch(UPB_PARSE_PARAMS) {
   if (UPB_UNLIKELY(ptr >= d->limit_ptr)) {
     int overrun = ptr - d->end;
     if (UPB_LIKELY(overrun == d->limit)) {
       // Parse is finished.
       *(uint32_t*)msg |= hasbits;  // Sync hasbits.
-      return ptr;
+      const upb_MiniTable* l = decode_totablep(table);
+      return UPB_UNLIKELY(l->required_count)
+                 ? decode_checkrequired(d, ptr, msg, l)
+                 : ptr;
     } else {
       data = overrun;
       UPB_MUSTTAIL return fastdecode_isdonefallback(UPB_PARSE_ARGS);
@@ -3026,7 +3614,7 @@
 }
 
 UPB_FORCEINLINE
-static const char *fastdecode_longsize(const char *ptr, int *size) {
+static const char* fastdecode_longsize(const char* ptr, int* size) {
   int i;
   UPB_ASSERT(*size & 0x80);
   *size &= 0xff;
@@ -3046,8 +3634,8 @@
 }
 
 UPB_FORCEINLINE
-static bool fastdecode_boundscheck(const char *ptr, size_t len,
-                                   const char *end) {
+static bool fastdecode_boundscheck(const char* ptr, size_t len,
+                                   const char* end) {
   uintptr_t uptr = (uintptr_t)ptr;
   uintptr_t uend = (uintptr_t)end + 16;
   uintptr_t res = uptr + len;
@@ -3055,8 +3643,8 @@
 }
 
 UPB_FORCEINLINE
-static bool fastdecode_boundscheck2(const char *ptr, size_t len,
-                                    const char *end) {
+static bool fastdecode_boundscheck2(const char* ptr, size_t len,
+                                    const char* end) {
   // This is one extra branch compared to the more normal:
   //   return (size_t)(end - ptr) < size;
   // However it is one less computation if we are just about to use "ptr + len":
@@ -3068,12 +3656,12 @@
   return res < uptr || res > uend;
 }
 
-typedef const char *fastdecode_delimfunc(upb_decstate *d, const char *ptr,
-                                         void *ctx);
+typedef const char* fastdecode_delimfunc(upb_Decoder* d, const char* ptr,
+                                         void* ctx);
 
 UPB_FORCEINLINE
-static const char *fastdecode_delimited(upb_decstate *d, const char *ptr,
-                                        fastdecode_delimfunc *func, void *ctx) {
+static const char* fastdecode_delimited(upb_Decoder* d, const char* ptr,
+                                        fastdecode_delimfunc* func, void* ctx) {
   ptr++;
   int len = (int8_t)ptr[-1];
   if (fastdecode_boundscheck2(ptr, len, d->limit_ptr)) {
@@ -3098,7 +3686,7 @@
   } else {
     // Fast case: Sub-message is <128 bytes and fits in the current buffer.
     // This means we can preserve limit/limit_ptr verbatim.
-    const char *saved_limit_ptr = d->limit_ptr;
+    const char* saved_limit_ptr = d->limit_ptr;
     int saved_limit = d->limit;
     d->limit_ptr = ptr + len;
     d->limit = d->limit_ptr - d->end;
@@ -3114,8 +3702,8 @@
 /* singular, oneof, repeated field handling ***********************************/
 
 typedef struct {
-  upb_array *arr;
-  void *end;
+  upb_Array* arr;
+  void* end;
 } fastdecode_arr;
 
 typedef enum {
@@ -3125,21 +3713,21 @@
 } fastdecode_next;
 
 typedef struct {
-  void *dst;
+  void* dst;
   fastdecode_next next;
   uint32_t tag;
 } fastdecode_nextret;
 
 UPB_FORCEINLINE
-static void *fastdecode_resizearr(upb_decstate *d, void *dst,
-                                  fastdecode_arr *farr, int valbytes) {
+static void* fastdecode_resizearr(upb_Decoder* d, void* dst,
+                                  fastdecode_arr* farr, int valbytes) {
   if (UPB_UNLIKELY(dst == farr->end)) {
     size_t old_size = farr->arr->size;
     size_t old_bytes = old_size * valbytes;
     size_t new_size = old_size * 2;
     size_t new_bytes = new_size * valbytes;
-    char *old_ptr = _upb_array_ptr(farr->arr);
-    char *new_ptr = upb_arena_realloc(&d->arena, old_ptr, old_bytes, new_bytes);
+    char* old_ptr = _upb_array_ptr(farr->arr);
+    char* new_ptr = upb_Arena_Realloc(&d->arena, old_ptr, old_bytes, new_bytes);
     uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
     farr->arr->size = new_size;
     farr->arr->data = _upb_array_tagptr(new_ptr, elem_size_lg2);
@@ -3159,20 +3747,20 @@
 }
 
 UPB_FORCEINLINE
-static void fastdecode_commitarr(void *dst, fastdecode_arr *farr,
+static void fastdecode_commitarr(void* dst, fastdecode_arr* farr,
                                  int valbytes) {
   farr->arr->len =
-      (size_t)((char *)dst - (char *)_upb_array_ptr(farr->arr)) / valbytes;
+      (size_t)((char*)dst - (char*)_upb_array_ptr(farr->arr)) / valbytes;
 }
 
 UPB_FORCEINLINE
-static fastdecode_nextret fastdecode_nextrepeated(upb_decstate *d, void *dst,
-                                                  const char **ptr,
-                                                  fastdecode_arr *farr,
+static fastdecode_nextret fastdecode_nextrepeated(upb_Decoder* d, void* dst,
+                                                  const char** ptr,
+                                                  fastdecode_arr* farr,
                                                   uint64_t data, int tagbytes,
                                                   int valbytes) {
   fastdecode_nextret ret;
-  dst = (char *)dst + valbytes;
+  dst = (char*)dst + valbytes;
 
   if (UPB_LIKELY(!decode_isdone(d, ptr))) {
     ret.tag = fastdecode_loadtag(*ptr);
@@ -3192,16 +3780,16 @@
 }
 
 UPB_FORCEINLINE
-static void *fastdecode_fieldmem(upb_msg *msg, uint64_t data) {
+static void* fastdecode_fieldmem(upb_Message* msg, uint64_t data) {
   size_t ofs = data >> 48;
-  return (char *)msg + ofs;
+  return (char*)msg + ofs;
 }
 
 UPB_FORCEINLINE
-static void *fastdecode_getfield(upb_decstate *d, const char *ptr, upb_msg *msg,
-                                 uint64_t *data, uint64_t *hasbits,
-                                 fastdecode_arr *farr, int valbytes,
-                                 upb_card card) {
+static void* fastdecode_getfield(upb_Decoder* d, const char* ptr,
+                                 upb_Message* msg, uint64_t* data,
+                                 uint64_t* hasbits, fastdecode_arr* farr,
+                                 int valbytes, upb_card card) {
   switch (card) {
     case CARD_s: {
       uint8_t hasbit_index = *data >> 24;
@@ -3211,20 +3799,20 @@
     }
     case CARD_o: {
       uint16_t case_ofs = *data >> 32;
-      uint32_t *oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t);
+      uint32_t* oneof_case = UPB_PTR_AT(msg, case_ofs, uint32_t);
       uint8_t field_number = *data >> 24;
       *oneof_case = field_number;
       return fastdecode_fieldmem(msg, *data);
     }
     case CARD_r: {
-      // Get pointer to upb_array and allocate/expand if necessary.
+      // Get pointer to upb_Array and allocate/expand if necessary.
       uint8_t elem_size_lg2 = __builtin_ctz(valbytes);
-      upb_array **arr_p = fastdecode_fieldmem(msg, *data);
-      char *begin;
+      upb_Array** arr_p = fastdecode_fieldmem(msg, *data);
+      char* begin;
       *(uint32_t*)msg |= *hasbits;
       *hasbits = 0;
       if (UPB_LIKELY(!*arr_p)) {
-        farr->arr = _upb_array_new(&d->arena, 8, elem_size_lg2);
+        farr->arr = _upb_Array_New(&d->arena, 8, elem_size_lg2);
         *arr_p = farr->arr;
       } else {
         farr->arr = *arr_p;
@@ -3240,17 +3828,17 @@
 }
 
 UPB_FORCEINLINE
-static bool fastdecode_flippacked(uint64_t *data, int tagbytes) {
+static bool fastdecode_flippacked(uint64_t* data, int tagbytes) {
   *data ^= (0x2 ^ 0x0);  // Patch data to match packed wiretype.
   return fastdecode_checktag(*data, tagbytes);
 }
 
-#define FASTDECODE_CHECKPACKED(tagbytes, card, func)                           \
-  if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {                    \
-    if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) {            \
-      UPB_MUSTTAIL return func(UPB_PARSE_ARGS);                                \
-    }                                                                          \
-    RETURN_GENERIC("packed check tag mismatch\n");                             \
+#define FASTDECODE_CHECKPACKED(tagbytes, card, func)                \
+  if (UPB_UNLIKELY(!fastdecode_checktag(data, tagbytes))) {         \
+    if (card == CARD_r && fastdecode_flippacked(&data, tagbytes)) { \
+      UPB_MUSTTAIL return func(UPB_PARSE_ARGS);                     \
+    }                                                               \
+    RETURN_GENERIC("packed check tag mismatch\n");                  \
   }
 
 /* varint fields **************************************************************/
@@ -3272,7 +3860,7 @@
 }
 
 UPB_FORCEINLINE
-static const char *fastdecode_varint64(const char *ptr, uint64_t *val) {
+static const char* fastdecode_varint64(const char* ptr, uint64_t* val) {
   ptr++;
   *val = (uint8_t)ptr[-1];
   if (UPB_UNLIKELY(*val & 0x80)) {
@@ -3298,7 +3886,7 @@
 #define FASTDECODE_UNPACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \
                                   valbytes, card, zigzag, packed)              \
   uint64_t val;                                                                \
-  void *dst;                                                                   \
+  void* dst;                                                                   \
   fastdecode_arr farr;                                                         \
                                                                                \
   FASTDECODE_CHECKPACKED(tagbytes, card, packed);                              \
@@ -3318,8 +3906,7 @@
                                                                                \
   ptr += tagbytes;                                                             \
   ptr = fastdecode_varint64(ptr, &val);                                        \
-  if (ptr == NULL)                                                             \
-    return fastdecode_err(d);                                                  \
+  if (ptr == NULL) return fastdecode_err(d, kUpb_DecodeStatus_Malformed);      \
   val = fastdecode_munge(val, valbytes, zigzag);                               \
   memcpy(dst, &val, valbytes);                                                 \
                                                                                \
@@ -3327,14 +3914,14 @@
     fastdecode_nextret ret = fastdecode_nextrepeated(                          \
         d, dst, &ptr, &farr, data, tagbytes, valbytes);                        \
     switch (ret.next) {                                                        \
-    case FD_NEXT_SAMEFIELD:                                                    \
-      dst = ret.dst;                                                           \
-      goto again;                                                              \
-    case FD_NEXT_OTHERFIELD:                                                   \
-      data = ret.tag;                                                          \
-      UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);              \
-    case FD_NEXT_ATLIMIT:                                                      \
-      return ptr;                                                              \
+      case FD_NEXT_SAMEFIELD:                                                  \
+        dst = ret.dst;                                                         \
+        goto again;                                                            \
+      case FD_NEXT_OTHERFIELD:                                                 \
+        data = ret.tag;                                                        \
+        UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);            \
+      case FD_NEXT_ATLIMIT:                                                    \
+        return ptr;                                                            \
     }                                                                          \
   }                                                                            \
                                                                                \
@@ -3343,15 +3930,15 @@
 typedef struct {
   uint8_t valbytes;
   bool zigzag;
-  void *dst;
+  void* dst;
   fastdecode_arr farr;
 } fastdecode_varintdata;
 
 UPB_FORCEINLINE
-static const char *fastdecode_topackedvarint(upb_decstate *d, const char *ptr,
-                                             void *ctx) {
-  fastdecode_varintdata *data = ctx;
-  void *dst = data->dst;
+static const char* fastdecode_topackedvarint(upb_Decoder* d, const char* ptr,
+                                             void* ctx) {
+  fastdecode_varintdata* data = ctx;
+  void* dst = data->dst;
   uint64_t val;
 
   while (!decode_isdone(d, &ptr)) {
@@ -3360,32 +3947,32 @@
     if (ptr == NULL) return NULL;
     val = fastdecode_munge(val, data->valbytes, data->zigzag);
     memcpy(dst, &val, data->valbytes);
-    dst = (char *)dst + data->valbytes;
+    dst = (char*)dst + data->valbytes;
   }
 
   fastdecode_commitarr(dst, &data->farr, data->valbytes);
   return ptr;
 }
 
-#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes,   \
-                                valbytes, zigzag, unpacked)                    \
-  fastdecode_varintdata ctx = {valbytes, zigzag};                              \
-                                                                               \
-  FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked);                          \
-                                                                               \
-  ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr,       \
-                                valbytes, CARD_r);                             \
-  if (UPB_UNLIKELY(!ctx.dst)) {                                                \
-    RETURN_GENERIC("need array resize\n");                                     \
-  }                                                                            \
-                                                                               \
-  ptr += tagbytes;                                                             \
-  ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx);        \
-                                                                               \
-  if (UPB_UNLIKELY(ptr == NULL)) {                                             \
-    return fastdecode_err(d);                                                  \
-  }                                                                            \
-                                                                               \
+#define FASTDECODE_PACKEDVARINT(d, ptr, msg, table, hasbits, data, tagbytes, \
+                                valbytes, zigzag, unpacked)                  \
+  fastdecode_varintdata ctx = {valbytes, zigzag};                            \
+                                                                             \
+  FASTDECODE_CHECKPACKED(tagbytes, CARD_r, unpacked);                        \
+                                                                             \
+  ctx.dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &ctx.farr,     \
+                                valbytes, CARD_r);                           \
+  if (UPB_UNLIKELY(!ctx.dst)) {                                              \
+    RETURN_GENERIC("need array resize\n");                                   \
+  }                                                                          \
+                                                                             \
+  ptr += tagbytes;                                                           \
+  ptr = fastdecode_delimited(d, ptr, &fastdecode_topackedvarint, &ctx);      \
+                                                                             \
+  if (UPB_UNLIKELY(ptr == NULL)) {                                           \
+    return fastdecode_err(d, kUpb_DecodeStatus_Malformed);                   \
+  }                                                                          \
+                                                                             \
   UPB_MUSTTAIL return fastdecode_dispatch(d, ptr, msg, table, hasbits, 0);
 
 #define FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes,     \
@@ -3407,7 +3994,7 @@
 
 #define F(card, type, valbytes, tagbytes)                                      \
   UPB_NOINLINE                                                                 \
-  const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+  const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
     FASTDECODE_VARINT(d, ptr, msg, table, hasbits, data, tagbytes, valbytes,   \
                       CARD_##card, type##_ZZ,                                  \
                       upb_pr##type##valbytes##_##tagbytes##bt,                 \
@@ -3443,48 +4030,47 @@
 #undef FASTDECODE_PACKEDVARINT
 #undef FASTDECODE_VARINT
 
-
 /* fixed fields ***************************************************************/
 
-#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes,  \
-                                 valbytes, card, packed)                       \
-  void *dst;                                                                   \
-  fastdecode_arr farr;                                                         \
-                                                                               \
-  FASTDECODE_CHECKPACKED(tagbytes, card, packed)                               \
-                                                                               \
-  dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes,     \
-                            card);                                             \
-  if (card == CARD_r) {                                                        \
-    if (UPB_UNLIKELY(!dst)) {                                                  \
-      RETURN_GENERIC("couldn't allocate array in arena\n");                    \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  again:                                                                       \
-  if (card == CARD_r) {                                                        \
-    dst = fastdecode_resizearr(d, dst, &farr, valbytes);                       \
-  }                                                                            \
-                                                                               \
-  ptr += tagbytes;                                                             \
-  memcpy(dst, ptr, valbytes);                                                  \
-  ptr += valbytes;                                                             \
-                                                                               \
-  if (card == CARD_r) {                                                        \
-    fastdecode_nextret ret = fastdecode_nextrepeated(                          \
-        d, dst, &ptr, &farr, data, tagbytes, valbytes);                        \
-    switch (ret.next) {                                                        \
-    case FD_NEXT_SAMEFIELD:                                                    \
-      dst = ret.dst;                                                           \
-      goto again;                                                              \
-    case FD_NEXT_OTHERFIELD:                                                   \
-      data = ret.tag;                                                          \
-      UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);              \
-    case FD_NEXT_ATLIMIT:                                                      \
-      return ptr;                                                              \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
+#define FASTDECODE_UNPACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \
+                                 valbytes, card, packed)                      \
+  void* dst;                                                                  \
+  fastdecode_arr farr;                                                        \
+                                                                              \
+  FASTDECODE_CHECKPACKED(tagbytes, card, packed)                              \
+                                                                              \
+  dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr, valbytes,    \
+                            card);                                            \
+  if (card == CARD_r) {                                                       \
+    if (UPB_UNLIKELY(!dst)) {                                                 \
+      RETURN_GENERIC("couldn't allocate array in arena\n");                   \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  again:                                                                      \
+  if (card == CARD_r) {                                                       \
+    dst = fastdecode_resizearr(d, dst, &farr, valbytes);                      \
+  }                                                                           \
+                                                                              \
+  ptr += tagbytes;                                                            \
+  memcpy(dst, ptr, valbytes);                                                 \
+  ptr += valbytes;                                                            \
+                                                                              \
+  if (card == CARD_r) {                                                       \
+    fastdecode_nextret ret = fastdecode_nextrepeated(                         \
+        d, dst, &ptr, &farr, data, tagbytes, valbytes);                       \
+    switch (ret.next) {                                                       \
+      case FD_NEXT_SAMEFIELD:                                                 \
+        dst = ret.dst;                                                        \
+        goto again;                                                           \
+      case FD_NEXT_OTHERFIELD:                                                \
+        data = ret.tag;                                                       \
+        UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);           \
+      case FD_NEXT_ATLIMIT:                                                   \
+        return ptr;                                                           \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
   UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS);
 
 #define FASTDECODE_PACKEDFIXED(d, ptr, msg, table, hasbits, data, tagbytes, \
@@ -3500,24 +4086,24 @@
                                                                             \
   if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr) ||       \
                    (size % valbytes) != 0)) {                               \
-    return fastdecode_err(d);                                               \
+    return fastdecode_err(d, kUpb_DecodeStatus_Malformed);                  \
   }                                                                         \
                                                                             \
-  upb_array **arr_p = fastdecode_fieldmem(msg, data);                       \
-  upb_array *arr = *arr_p;                                                  \
+  upb_Array** arr_p = fastdecode_fieldmem(msg, data);                       \
+  upb_Array* arr = *arr_p;                                                  \
   uint8_t elem_size_lg2 = __builtin_ctz(valbytes);                          \
   int elems = size / valbytes;                                              \
                                                                             \
   if (UPB_LIKELY(!arr)) {                                                   \
-    *arr_p = arr = _upb_array_new(&d->arena, elems, elem_size_lg2);         \
+    *arr_p = arr = _upb_Array_New(&d->arena, elems, elem_size_lg2);         \
     if (!arr) {                                                             \
-      return fastdecode_err(d);                                             \
+      return fastdecode_err(d, kUpb_DecodeStatus_Malformed);                \
     }                                                                       \
   } else {                                                                  \
-    _upb_array_resize(arr, elems, &d->arena);                               \
+    _upb_Array_Resize(arr, elems, &d->arena);                               \
   }                                                                         \
                                                                             \
-  char *dst = _upb_array_ptr(arr);                                          \
+  char* dst = _upb_array_ptr(arr);                                          \
   memcpy(dst, ptr, size);                                                   \
   arr->len = elems;                                                         \
                                                                             \
@@ -3539,7 +4125,7 @@
 
 #define F(card, valbytes, tagbytes)                                         \
   UPB_NOINLINE                                                              \
-  const char *upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
+  const char* upb_p##card##f##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS) { \
     FASTDECODE_FIXED(d, ptr, msg, table, hasbits, data, tagbytes, valbytes, \
                      CARD_##card, upb_ppf##valbytes##_##tagbytes##bt,       \
                      upb_prf##valbytes##_##tagbytes##bt);                   \
@@ -3566,18 +4152,19 @@
 
 /* string fields **************************************************************/
 
-typedef const char *fastdecode_copystr_func(struct upb_decstate *d,
-                                            const char *ptr, upb_msg *msg,
-                                            const upb_msglayout *table,
-                                            uint64_t hasbits, upb_strview *dst);
+typedef const char* fastdecode_copystr_func(struct upb_Decoder* d,
+                                            const char* ptr, upb_Message* msg,
+                                            const upb_MiniTable* table,
+                                            uint64_t hasbits,
+                                            upb_StringView* dst);
 
 UPB_NOINLINE
-static const char *fastdecode_verifyutf8(upb_decstate *d, const char *ptr,
-                                         upb_msg *msg, intptr_t table,
+static const char* fastdecode_verifyutf8(upb_Decoder* d, const char* ptr,
+                                         upb_Message* msg, intptr_t table,
                                          uint64_t hasbits, uint64_t data) {
-  upb_strview *dst = (upb_strview*)data;
+  upb_StringView* dst = (upb_StringView*)data;
   if (!decode_verifyutf8_inl(dst->data, dst->size)) {
-    return fastdecode_err(d);
+    return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8);
   }
   UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS);
 }
@@ -3591,16 +4178,16 @@
                                                                                \
   if (UPB_UNLIKELY(fastdecode_boundscheck(ptr, size, d->limit_ptr))) {         \
     dst->size = 0;                                                             \
-    return fastdecode_err(d);                                                  \
+    return fastdecode_err(d, kUpb_DecodeStatus_Malformed);                     \
   }                                                                            \
                                                                                \
-  if (d->alias) {                                                              \
+  if (d->options & kUpb_DecodeOption_AliasString) {                            \
     dst->data = ptr;                                                           \
     dst->size = size;                                                          \
   } else {                                                                     \
-    char *data = upb_arena_malloc(&d->arena, size);                            \
+    char* data = upb_Arena_Malloc(&d->arena, size);                            \
     if (!data) {                                                               \
-      return fastdecode_err(d);                                                \
+      return fastdecode_err(d, kUpb_DecodeStatus_OutOfMemory);                 \
     }                                                                          \
     memcpy(data, ptr, size);                                                   \
     dst->data = data;                                                          \
@@ -3616,27 +4203,25 @@
   }
 
 UPB_NOINLINE
-static const char *fastdecode_longstring_utf8(struct upb_decstate *d,
-                                              const char *ptr, upb_msg *msg,
+static const char* fastdecode_longstring_utf8(struct upb_Decoder* d,
+                                              const char* ptr, upb_Message* msg,
                                               intptr_t table, uint64_t hasbits,
                                               uint64_t data) {
-  upb_strview *dst = (upb_strview*)data;
+  upb_StringView* dst = (upb_StringView*)data;
   FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, true);
 }
 
 UPB_NOINLINE
-static const char *fastdecode_longstring_noutf8(struct upb_decstate *d,
-                                                const char *ptr, upb_msg *msg,
-                                                intptr_t table,
-                                                uint64_t hasbits,
-                                                uint64_t data) {
-  upb_strview *dst = (upb_strview*)data;
+static const char* fastdecode_longstring_noutf8(
+    struct upb_Decoder* d, const char* ptr, upb_Message* msg, intptr_t table,
+    uint64_t hasbits, uint64_t data) {
+  upb_StringView* dst = (upb_StringView*)data;
   FASTDECODE_LONGSTRING(d, ptr, msg, table, hasbits, dst, false);
 }
 
 UPB_FORCEINLINE
-static void fastdecode_docopy(upb_decstate *d, const char *ptr, uint32_t size,
-                              int copy, char *data, upb_strview *dst) {
+static void fastdecode_docopy(upb_Decoder* d, const char* ptr, uint32_t size,
+                              int copy, char* data, upb_StringView* dst) {
   d->arena.head.ptr += copy;
   dst->data = data;
   UPB_UNPOISON_MEMORY_REGION(data, copy);
@@ -3644,96 +4229,95 @@
   UPB_POISON_MEMORY_REGION(data + size, copy - size);
 }
 
-#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes,     \
-                              card, validate_utf8)                             \
-  upb_strview *dst;                                                            \
-  fastdecode_arr farr;                                                         \
-  int64_t size;                                                                \
-  size_t arena_has;                                                            \
-  size_t common_has;                                                           \
-  char *buf;                                                                   \
-                                                                               \
-  UPB_ASSERT(!d->alias);                                                       \
-  UPB_ASSERT(fastdecode_checktag(data, tagbytes));                             \
-                                                                               \
-  dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,               \
-                            sizeof(upb_strview), card);                        \
-                                                                               \
-  again:                                                                       \
-  if (card == CARD_r) {                                                        \
-    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview));            \
-  }                                                                            \
-                                                                               \
-  size = (uint8_t)ptr[tagbytes];                                               \
-  ptr += tagbytes + 1;                                                         \
-  dst->size = size;                                                            \
-                                                                               \
-  buf = d->arena.head.ptr;                                                     \
-  arena_has = _upb_arenahas(&d->arena);                                        \
-  common_has = UPB_MIN(arena_has, (d->end - ptr) + 16);                        \
-                                                                               \
-  if (UPB_LIKELY(size <= 15 - tagbytes)) {                                     \
-    if (arena_has < 16)                                                        \
-      goto longstr;                                                            \
-    d->arena.head.ptr += 16;                                                   \
-    memcpy(buf, ptr - tagbytes - 1, 16);                                       \
-    dst->data = buf + tagbytes + 1;                                            \
-  } else if (UPB_LIKELY(size <= 32)) {                                         \
-    if (UPB_UNLIKELY(common_has < 32))                                         \
-      goto longstr;                                                            \
-    fastdecode_docopy(d, ptr, size, 32, buf, dst);                             \
-  } else if (UPB_LIKELY(size <= 64)) {                                         \
-    if (UPB_UNLIKELY(common_has < 64))                                         \
-      goto longstr;                                                            \
-    fastdecode_docopy(d, ptr, size, 64, buf, dst);                             \
-  } else if (UPB_LIKELY(size < 128)) {                                         \
-    if (UPB_UNLIKELY(common_has < 128))                                        \
-      goto longstr;                                                            \
-    fastdecode_docopy(d, ptr, size, 128, buf, dst);                            \
-  } else {                                                                     \
-    goto longstr;                                                              \
-  }                                                                            \
-                                                                               \
-  ptr += size;                                                                 \
-                                                                               \
-  if (card == CARD_r) {                                                        \
-    if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) {       \
-      return fastdecode_err(d);                                                \
-    }                                                                          \
-    fastdecode_nextret ret = fastdecode_nextrepeated(                          \
-        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview));             \
-    switch (ret.next) {                                                        \
-    case FD_NEXT_SAMEFIELD:                                                    \
-      dst = ret.dst;                                                           \
-      goto again;                                                              \
-    case FD_NEXT_OTHERFIELD:                                                   \
-      data = ret.tag;                                                          \
-      UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);              \
-    case FD_NEXT_ATLIMIT:                                                      \
-      return ptr;                                                              \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  if (card != CARD_r && validate_utf8) {                                       \
-    data = (uint64_t)dst;                                                      \
-    UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS);                 \
-  }                                                                            \
-                                                                               \
-  UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS);                     \
-                                                                               \
-  longstr:                                                                     \
-  ptr--;                                                                       \
-  if (validate_utf8) {                                                         \
-    UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table,         \
-                                                   hasbits, (uint64_t)dst);    \
-  } else {                                                                     \
-    UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table,       \
-                                                     hasbits, (uint64_t)dst);  \
+#define FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes,    \
+                              card, validate_utf8)                            \
+  upb_StringView* dst;                                                        \
+  fastdecode_arr farr;                                                        \
+  int64_t size;                                                               \
+  size_t arena_has;                                                           \
+  size_t common_has;                                                          \
+  char* buf;                                                                  \
+                                                                              \
+  UPB_ASSERT((d->options & kUpb_DecodeOption_AliasString) == 0);              \
+  UPB_ASSERT(fastdecode_checktag(data, tagbytes));                            \
+                                                                              \
+  dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,              \
+                            sizeof(upb_StringView), card);                    \
+                                                                              \
+  again:                                                                      \
+  if (card == CARD_r) {                                                       \
+    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView));        \
+  }                                                                           \
+                                                                              \
+  size = (uint8_t)ptr[tagbytes];                                              \
+  ptr += tagbytes + 1;                                                        \
+  dst->size = size;                                                           \
+                                                                              \
+  buf = d->arena.head.ptr;                                                    \
+  arena_has = _upb_ArenaHas(&d->arena);                                       \
+  common_has = UPB_MIN(arena_has, (d->end - ptr) + 16);                       \
+                                                                              \
+  if (UPB_LIKELY(size <= 15 - tagbytes)) {                                    \
+    if (arena_has < 16) goto longstr;                                         \
+    d->arena.head.ptr += 16;                                                  \
+    memcpy(buf, ptr - tagbytes - 1, 16);                                      \
+    dst->data = buf + tagbytes + 1;                                           \
+  } else if (UPB_LIKELY(size <= 32)) {                                        \
+    if (UPB_UNLIKELY(common_has < 32)) goto longstr;                          \
+    fastdecode_docopy(d, ptr, size, 32, buf, dst);                            \
+  } else if (UPB_LIKELY(size <= 64)) {                                        \
+    if (UPB_UNLIKELY(common_has < 64)) goto longstr;                          \
+    fastdecode_docopy(d, ptr, size, 64, buf, dst);                            \
+  } else if (UPB_LIKELY(size < 128)) {                                        \
+    if (UPB_UNLIKELY(common_has < 128)) goto longstr;                         \
+    fastdecode_docopy(d, ptr, size, 128, buf, dst);                           \
+  } else {                                                                    \
+    goto longstr;                                                             \
+  }                                                                           \
+                                                                              \
+  ptr += size;                                                                \
+                                                                              \
+  if (card == CARD_r) {                                                       \
+    if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) {      \
+      return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8);                    \
+    }                                                                         \
+    fastdecode_nextret ret = fastdecode_nextrepeated(                         \
+        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView));         \
+    switch (ret.next) {                                                       \
+      case FD_NEXT_SAMEFIELD:                                                 \
+        dst = ret.dst;                                                        \
+        goto again;                                                           \
+      case FD_NEXT_OTHERFIELD:                                                \
+        data = ret.tag;                                                       \
+        UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);           \
+      case FD_NEXT_ATLIMIT:                                                   \
+        return ptr;                                                           \
+    }                                                                         \
+  }                                                                           \
+                                                                              \
+  if (card != CARD_r && validate_utf8) {                                      \
+    data = (uint64_t)dst;                                                     \
+    UPB_MUSTTAIL return fastdecode_verifyutf8(UPB_PARSE_ARGS);                \
+  }                                                                           \
+                                                                              \
+  UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS);                    \
+                                                                              \
+  longstr:                                                                    \
+  if (card == CARD_r) {                                                       \
+    fastdecode_commitarr(dst + 1, &farr, sizeof(upb_StringView));             \
+  }                                                                           \
+  ptr--;                                                                      \
+  if (validate_utf8) {                                                        \
+    UPB_MUSTTAIL return fastdecode_longstring_utf8(d, ptr, msg, table,        \
+                                                   hasbits, (uint64_t)dst);   \
+  } else {                                                                    \
+    UPB_MUSTTAIL return fastdecode_longstring_noutf8(d, ptr, msg, table,      \
+                                                     hasbits, (uint64_t)dst); \
   }
 
 #define FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes, card,   \
                           copyfunc, validate_utf8)                             \
-  upb_strview *dst;                                                            \
+  upb_StringView* dst;                                                         \
   fastdecode_arr farr;                                                         \
   int64_t size;                                                                \
                                                                                \
@@ -3741,16 +4325,16 @@
     RETURN_GENERIC("string field tag mismatch\n");                             \
   }                                                                            \
                                                                                \
-  if (UPB_UNLIKELY(!d->alias)) {                                               \
+  if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) {       \
     UPB_MUSTTAIL return copyfunc(UPB_PARSE_ARGS);                              \
   }                                                                            \
                                                                                \
   dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,               \
-                            sizeof(upb_strview), card);                        \
+                            sizeof(upb_StringView), card);                     \
                                                                                \
   again:                                                                       \
   if (card == CARD_r) {                                                        \
-    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_strview));            \
+    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_StringView));         \
   }                                                                            \
                                                                                \
   size = (int8_t)ptr[tagbytes];                                                \
@@ -3773,27 +4357,27 @@
                                                                                \
   if (card == CARD_r) {                                                        \
     if (validate_utf8 && !decode_verifyutf8_inl(dst->data, dst->size)) {       \
-      return fastdecode_err(d);                                                \
+      return fastdecode_err(d, kUpb_DecodeStatus_BadUtf8);                     \
     }                                                                          \
     fastdecode_nextret ret = fastdecode_nextrepeated(                          \
-        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_strview));             \
+        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_StringView));          \
     switch (ret.next) {                                                        \
-    case FD_NEXT_SAMEFIELD:                                                    \
-      dst = ret.dst;                                                           \
-      if (UPB_UNLIKELY(!d->alias)) {                                           \
-        /* Buffer flipped and we can't alias any more. Bounce to */            \
-        /* copyfunc(), but via dispatch since we need to reload table */       \
-        /* data also. */                                                       \
-        fastdecode_commitarr(dst, &farr, sizeof(upb_strview));                 \
+      case FD_NEXT_SAMEFIELD:                                                  \
+        dst = ret.dst;                                                         \
+        if (UPB_UNLIKELY((d->options & kUpb_DecodeOption_AliasString) == 0)) { \
+          /* Buffer flipped and we can't alias any more. Bounce to */          \
+          /* copyfunc(), but via dispatch since we need to reload table */     \
+          /* data also. */                                                     \
+          fastdecode_commitarr(dst, &farr, sizeof(upb_StringView));            \
+          data = ret.tag;                                                      \
+          UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);          \
+        }                                                                      \
+        goto again;                                                            \
+      case FD_NEXT_OTHERFIELD:                                                 \
         data = ret.tag;                                                        \
         UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);            \
-      }                                                                        \
-      goto again;                                                              \
-    case FD_NEXT_OTHERFIELD:                                                   \
-      data = ret.tag;                                                          \
-      UPB_MUSTTAIL return fastdecode_tagdispatch(UPB_PARSE_ARGS);              \
-    case FD_NEXT_ATLIMIT:                                                      \
-      return ptr;                                                              \
+      case FD_NEXT_ATLIMIT:                                                    \
+        return ptr;                                                            \
     }                                                                          \
   }                                                                            \
                                                                                \
@@ -3812,11 +4396,11 @@
 
 #define F(card, tagbytes, type)                                        \
   UPB_NOINLINE                                                         \
-  const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) {   \
+  const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) {   \
     FASTDECODE_COPYSTRING(d, ptr, msg, table, hasbits, data, tagbytes, \
                           CARD_##card, type##_VALIDATE);               \
   }                                                                    \
-  const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) {   \
+  const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS) {   \
     FASTDECODE_STRING(d, ptr, msg, table, hasbits, data, tagbytes,     \
                       CARD_##card, upb_c##card##type##_##tagbytes##bt, \
                       type##_VALIDATE);                                \
@@ -3845,12 +4429,12 @@
 /* message fields *************************************************************/
 
 UPB_INLINE
-upb_msg *decode_newmsg_ceil(upb_decstate *d, const upb_msglayout *l,
-                            int msg_ceil_bytes) {
-  size_t size = l->size + sizeof(upb_msg_internal);
-  char *msg_data;
+upb_Message* decode_newmsg_ceil(upb_Decoder* d, const upb_MiniTable* l,
+                                int msg_ceil_bytes) {
+  size_t size = l->size + sizeof(upb_Message_Internal);
+  char* msg_data;
   if (UPB_LIKELY(msg_ceil_bytes > 0 &&
-                 _upb_arenahas(&d->arena) >= msg_ceil_bytes)) {
+                 _upb_ArenaHas(&d->arena) >= msg_ceil_bytes)) {
     UPB_ASSERT(size <= (size_t)msg_ceil_bytes);
     msg_data = d->arena.head.ptr;
     d->arena.head.ptr += size;
@@ -3858,21 +4442,21 @@
     memset(msg_data, 0, msg_ceil_bytes);
     UPB_POISON_MEMORY_REGION(msg_data + size, msg_ceil_bytes - size);
   } else {
-    msg_data = (char*)upb_arena_malloc(&d->arena, size);
+    msg_data = (char*)upb_Arena_Malloc(&d->arena, size);
     memset(msg_data, 0, size);
   }
-  return msg_data + sizeof(upb_msg_internal);
+  return msg_data + sizeof(upb_Message_Internal);
 }
 
 typedef struct {
   intptr_t table;
-  upb_msg *msg;
+  upb_Message* msg;
 } fastdecode_submsgdata;
 
 UPB_FORCEINLINE
-static const char *fastdecode_tosubmsg(upb_decstate *d, const char *ptr,
-                                       void *ctx) {
-  fastdecode_submsgdata *submsg = ctx;
+static const char* fastdecode_tosubmsg(upb_Decoder* d, const char* ptr,
+                                       void* ctx) {
+  fastdecode_submsgdata* submsg = ctx;
   ptr = fastdecode_dispatch(d, ptr, submsg->msg, submsg->table, 0, 0);
   UPB_ASSUME(ptr != NULL);
   return ptr;
@@ -3885,12 +4469,14 @@
     RETURN_GENERIC("submessage field tag mismatch\n");                    \
   }                                                                       \
                                                                           \
-  if (--d->depth == 0) return fastdecode_err(d);                          \
+  if (--d->depth == 0) {                                                  \
+    return fastdecode_err(d, kUpb_DecodeStatus_MaxDepthExceeded);         \
+  }                                                                       \
                                                                           \
-  upb_msg **dst;                                                          \
+  upb_Message** dst;                                                      \
   uint32_t submsg_idx = (data >> 16) & 0xff;                              \
-  const upb_msglayout *tablep = decode_totablep(table);                   \
-  const upb_msglayout *subtablep = tablep->submsgs[submsg_idx];           \
+  const upb_MiniTable* tablep = decode_totablep(table);                   \
+  const upb_MiniTable* subtablep = tablep->subs[submsg_idx].submsg;       \
   fastdecode_submsgdata submsg = {decode_totable(subtablep)};             \
   fastdecode_arr farr;                                                    \
                                                                           \
@@ -3899,16 +4485,16 @@
   }                                                                       \
                                                                           \
   dst = fastdecode_getfield(d, ptr, msg, &data, &hasbits, &farr,          \
-                            sizeof(upb_msg *), card);                     \
+                            sizeof(upb_Message*), card);                  \
                                                                           \
   if (card == CARD_s) {                                                   \
-    *(uint32_t *)msg |= hasbits;                                          \
+    *(uint32_t*)msg |= hasbits;                                           \
     hasbits = 0;                                                          \
   }                                                                       \
                                                                           \
   again:                                                                  \
   if (card == CARD_r) {                                                   \
-    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_msg *));         \
+    dst = fastdecode_resizearr(d, dst, &farr, sizeof(upb_Message*));      \
   }                                                                       \
                                                                           \
   submsg.msg = *dst;                                                      \
@@ -3921,12 +4507,12 @@
   ptr = fastdecode_delimited(d, ptr, fastdecode_tosubmsg, &submsg);       \
                                                                           \
   if (UPB_UNLIKELY(ptr == NULL || d->end_group != DECODE_NOGROUP)) {      \
-    return fastdecode_err(d);                                             \
+    return fastdecode_err(d, kUpb_DecodeStatus_Malformed);                \
   }                                                                       \
                                                                           \
   if (card == CARD_r) {                                                   \
     fastdecode_nextret ret = fastdecode_nextrepeated(                     \
-        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_msg *));          \
+        d, dst, &ptr, &farr, data, tagbytes, sizeof(upb_Message*));       \
     switch (ret.next) {                                                   \
       case FD_NEXT_SAMEFIELD:                                             \
         dst = ret.dst;                                                    \
@@ -3945,21 +4531,21 @@
   UPB_MUSTTAIL return fastdecode_dispatch(UPB_PARSE_ARGS);
 
 #define F(card, tagbytes, size_ceil, ceil_arg)                               \
-  const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b(               \
+  const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(               \
       UPB_PARSE_PARAMS) {                                                    \
     FASTDECODE_SUBMSG(d, ptr, msg, table, hasbits, data, tagbytes, ceil_arg, \
                       CARD_##card);                                          \
   }
 
 #define SIZES(card, tagbytes) \
-  F(card, tagbytes, 64, 64) \
+  F(card, tagbytes, 64, 64)   \
   F(card, tagbytes, 128, 128) \
   F(card, tagbytes, 192, 192) \
   F(card, tagbytes, 256, 256) \
   F(card, tagbytes, max, -1)
 
 #define TAGBYTES(card) \
-  SIZES(card, 1) \
+  SIZES(card, 1)       \
   SIZES(card, 2)
 
 TAGBYTES(s)
@@ -3971,7 +4557,7 @@
 #undef F
 #undef FASTDECODE_SUBMSG
 
-#endif  /* UPB_FASTTABLE */
+#endif /* UPB_FASTTABLE */
 
 /** bazel-out/k8-fastbuild/bin/external/com_google_protobuf/google/protobuf/descriptor.upb.c ************************************************************//* This file was generated by upbc (the upb compiler) from the input
  * file:
@@ -3984,474 +4570,564 @@
 #include <stddef.h>
 
 
-static const upb_msglayout *const google_protobuf_FileDescriptorSet_submsgs[1] = {
-  &google_protobuf_FileDescriptorProto_msginit,
+static const upb_MiniTable_Sub google_protobuf_FileDescriptorSet_submsgs[1] = {
+  {.submsg = &google_protobuf_FileDescriptorProto_msginit},
 };
 
-static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY},
+static const upb_MiniTable_Field google_protobuf_FileDescriptorSet__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
 };
 
-const upb_msglayout google_protobuf_FileDescriptorSet_msginit = {
+const upb_MiniTable google_protobuf_FileDescriptorSet_msginit = {
   &google_protobuf_FileDescriptorSet_submsgs[0],
   &google_protobuf_FileDescriptorSet__fields[0],
-  UPB_SIZE(8, 8), 1, false, 1, 255,
+  UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0,
 };
 
-static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] = {
-  &google_protobuf_DescriptorProto_msginit,
-  &google_protobuf_EnumDescriptorProto_msginit,
-  &google_protobuf_FieldDescriptorProto_msginit,
-  &google_protobuf_FileOptions_msginit,
-  &google_protobuf_ServiceDescriptorProto_msginit,
-  &google_protobuf_SourceCodeInfo_msginit,
+static const upb_MiniTable_Sub google_protobuf_FileDescriptorProto_submsgs[6] = {
+  {.submsg = &google_protobuf_DescriptorProto_msginit},
+  {.submsg = &google_protobuf_EnumDescriptorProto_msginit},
+  {.submsg = &google_protobuf_FieldDescriptorProto_msginit},
+  {.submsg = &google_protobuf_FileOptions_msginit},
+  {.submsg = &google_protobuf_ServiceDescriptorProto_msginit},
+  {.submsg = &google_protobuf_SourceCodeInfo_msginit},
 };
 
-static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(36, 72), 0, 0, 12, _UPB_MODE_ARRAY},
-  {4, UPB_SIZE(40, 80), 0, 0, 11, _UPB_MODE_ARRAY},
-  {5, UPB_SIZE(44, 88), 0, 1, 11, _UPB_MODE_ARRAY},
-  {6, UPB_SIZE(48, 96), 0, 4, 11, _UPB_MODE_ARRAY},
-  {7, UPB_SIZE(52, 104), 0, 2, 11, _UPB_MODE_ARRAY},
-  {8, UPB_SIZE(28, 56), 3, 3, 11, _UPB_MODE_SCALAR},
-  {9, UPB_SIZE(32, 64), 4, 5, 11, _UPB_MODE_SCALAR},
-  {10, UPB_SIZE(56, 112), 0, 0, 5, _UPB_MODE_ARRAY},
-  {11, UPB_SIZE(60, 120), 0, 0, 5, _UPB_MODE_ARRAY},
-  {12, UPB_SIZE(20, 40), 5, 0, 12, _UPB_MODE_SCALAR},
+static const upb_MiniTable_Field google_protobuf_FileDescriptorProto__fields[12] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(36, 72), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(40, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(44, 88), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(48, 96), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {7, UPB_SIZE(52, 104), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {8, UPB_SIZE(28, 56), 3, 3, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {9, UPB_SIZE(32, 64), 4, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {10, UPB_SIZE(56, 112), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {11, UPB_SIZE(60, 120), 0, 0, 5, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {12, UPB_SIZE(20, 40), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
 };
 
-const upb_msglayout google_protobuf_FileDescriptorProto_msginit = {
+const upb_MiniTable google_protobuf_FileDescriptorProto_msginit = {
   &google_protobuf_FileDescriptorProto_submsgs[0],
   &google_protobuf_FileDescriptorProto__fields[0],
-  UPB_SIZE(64, 128), 12, false, 12, 255,
+  UPB_SIZE(64, 128), 12, upb_ExtMode_NonExtendable, 12, 255, 0,
 };
 
-static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[7] = {
+static const upb_MiniTable_Sub google_protobuf_DescriptorProto_submsgs[7] = {
+  {.submsg = &google_protobuf_DescriptorProto_msginit},
+  {.submsg = &google_protobuf_DescriptorProto_ExtensionRange_msginit},
+  {.submsg = &google_protobuf_DescriptorProto_ReservedRange_msginit},
+  {.submsg = &google_protobuf_EnumDescriptorProto_msginit},
+  {.submsg = &google_protobuf_FieldDescriptorProto_msginit},
+  {.submsg = &google_protobuf_MessageOptions_msginit},
+  {.submsg = &google_protobuf_OneofDescriptorProto_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_DescriptorProto__fields[10] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(16, 32), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(24, 48), 0, 3, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(28, 56), 0, 1, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(32, 64), 0, 4, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {7, UPB_SIZE(12, 24), 2, 5, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {8, UPB_SIZE(36, 72), 0, 6, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {9, UPB_SIZE(40, 80), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {10, UPB_SIZE(44, 88), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_DescriptorProto_msginit = {
+  &google_protobuf_DescriptorProto_submsgs[0],
+  &google_protobuf_DescriptorProto__fields[0],
+  UPB_SIZE(48, 96), 10, upb_ExtMode_NonExtendable, 10, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = {
+  {.submsg = &google_protobuf_ExtensionRangeOptions_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = {
+  {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(12, 16), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit = {
+  &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0],
+  &google_protobuf_DescriptorProto_ExtensionRange__fields[0],
+  UPB_SIZE(16, 24), 3, upb_ExtMode_NonExtendable, 3, 255, 0,
+};
+
+static const upb_MiniTable_Field google_protobuf_DescriptorProto_ReservedRange__fields[2] = {
+  {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit = {
+  NULL,
+  &google_protobuf_DescriptorProto_ReservedRange__fields[0],
+  UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_ExtensionRangeOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_ExtensionRangeOptions__fields[1] = {
+  {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit = {
+  &google_protobuf_ExtensionRangeOptions_submsgs[0],
+  &google_protobuf_ExtensionRangeOptions__fields[0],
+  UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_FieldDescriptorProto_submsgs[3] = {
+  {.submsg = &google_protobuf_FieldOptions_msginit},
+  {.subenum = &google_protobuf_FieldDescriptorProto_Label_enuminit},
+  {.subenum = &google_protobuf_FieldDescriptorProto_Type_enuminit},
+};
+
+static const upb_MiniTable_Field google_protobuf_FieldDescriptorProto__fields[11] = {
+  {1, UPB_SIZE(24, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(32, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(12, 12), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(4, 4), 4, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(40, 56), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {7, UPB_SIZE(48, 72), 7, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {8, UPB_SIZE(64, 104), 8, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {9, UPB_SIZE(16, 16), 9, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {10, UPB_SIZE(56, 88), 10, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {17, UPB_SIZE(20, 20), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit = {
+  &google_protobuf_FieldDescriptorProto_submsgs[0],
+  &google_protobuf_FieldDescriptorProto__fields[0],
+  UPB_SIZE(72, 112), 11, upb_ExtMode_NonExtendable, 10, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_OneofDescriptorProto_submsgs[1] = {
+  {.submsg = &google_protobuf_OneofOptions_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_OneofDescriptorProto__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(12, 24), 2, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit = {
+  &google_protobuf_OneofDescriptorProto_submsgs[0],
+  &google_protobuf_OneofDescriptorProto__fields[0],
+  UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_EnumDescriptorProto_submsgs[3] = {
+  {.submsg = &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit},
+  {.submsg = &google_protobuf_EnumOptions_msginit},
+  {.submsg = &google_protobuf_EnumValueDescriptorProto_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto__fields[5] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(16, 32), 0, 2, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(20, 40), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(24, 48), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit = {
+  &google_protobuf_EnumDescriptorProto_submsgs[0],
+  &google_protobuf_EnumDescriptorProto__fields[0],
+  UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 5, 255, 0,
+};
+
+static const upb_MiniTable_Field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = {
+  {1, UPB_SIZE(4, 4), 1, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(8, 8), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = {
+  NULL,
+  &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0],
+  UPB_SIZE(16, 16), 2, upb_ExtMode_NonExtendable, 2, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_EnumValueDescriptorProto_submsgs[1] = {
+  {.submsg = &google_protobuf_EnumValueOptions_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_EnumValueDescriptorProto__fields[3] = {
+  {1, UPB_SIZE(8, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(16, 24), 3, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit = {
+  &google_protobuf_EnumValueDescriptorProto_submsgs[0],
+  &google_protobuf_EnumValueDescriptorProto__fields[0],
+  UPB_SIZE(24, 32), 3, upb_ExtMode_NonExtendable, 3, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_ServiceDescriptorProto_submsgs[2] = {
+  {.submsg = &google_protobuf_MethodDescriptorProto_msginit},
+  {.submsg = &google_protobuf_ServiceOptions_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_ServiceDescriptorProto__fields[3] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(16, 32), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(12, 24), 2, 1, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit = {
+  &google_protobuf_ServiceDescriptorProto_submsgs[0],
+  &google_protobuf_ServiceDescriptorProto__fields[0],
+  UPB_SIZE(24, 48), 3, upb_ExtMode_NonExtendable, 3, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_MethodDescriptorProto_submsgs[1] = {
+  {.submsg = &google_protobuf_MethodOptions_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_MethodDescriptorProto__fields[6] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(20, 40), 3, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(28, 56), 4, 0, 11, kUpb_FieldMode_Scalar | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(1, 1), 5, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(2, 2), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit = {
+  &google_protobuf_MethodDescriptorProto_submsgs[0],
+  &google_protobuf_MethodDescriptorProto__fields[0],
+  UPB_SIZE(32, 64), 6, upb_ExtMode_NonExtendable, 6, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_FileOptions_submsgs[2] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+  {.subenum = &google_protobuf_FileOptions_OptimizeMode_enuminit},
+};
+
+static const upb_MiniTable_Field google_protobuf_FileOptions__fields[21] = {
+  {1, UPB_SIZE(20, 24), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {8, UPB_SIZE(28, 40), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {9, UPB_SIZE(4, 4), 3, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {10, UPB_SIZE(8, 8), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {11, UPB_SIZE(36, 56), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {16, UPB_SIZE(9, 9), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {17, UPB_SIZE(10, 10), 7, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {18, UPB_SIZE(11, 11), 8, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {20, UPB_SIZE(12, 12), 9, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {23, UPB_SIZE(13, 13), 10, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {27, UPB_SIZE(14, 14), 11, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {31, UPB_SIZE(15, 15), 12, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {36, UPB_SIZE(44, 72), 13, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {37, UPB_SIZE(52, 88), 14, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {39, UPB_SIZE(60, 104), 15, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {40, UPB_SIZE(68, 120), 16, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {41, UPB_SIZE(76, 136), 17, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {42, UPB_SIZE(16, 16), 18, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {44, UPB_SIZE(84, 152), 19, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {45, UPB_SIZE(92, 168), 20, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(100, 184), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_FileOptions_msginit = {
+  &google_protobuf_FileOptions_submsgs[0],
+  &google_protobuf_FileOptions__fields[0],
+  UPB_SIZE(104, 192), 21, upb_ExtMode_Extendable, 1, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_MessageOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_MessageOptions__fields[5] = {
+  {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(3, 3), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {7, UPB_SIZE(4, 4), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(8, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_MessageOptions_msginit = {
+  &google_protobuf_MessageOptions_submsgs[0],
+  &google_protobuf_MessageOptions__fields[0],
+  UPB_SIZE(16, 16), 5, upb_ExtMode_Extendable, 3, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_FieldOptions_submsgs[3] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+  {.subenum = &google_protobuf_FieldOptions_CType_enuminit},
+  {.subenum = &google_protobuf_FieldOptions_JSType_enuminit},
+};
+
+static const upb_MiniTable_Field google_protobuf_FieldOptions__fields[7] = {
+  {1, UPB_SIZE(4, 4), 1, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(12, 12), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(13, 13), 3, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(14, 14), 4, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(8, 8), 5, 2, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {10, UPB_SIZE(15, 15), 6, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(16, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_FieldOptions_msginit = {
+  &google_protobuf_FieldOptions_submsgs[0],
+  &google_protobuf_FieldOptions__fields[0],
+  UPB_SIZE(24, 24), 7, upb_ExtMode_Extendable, 3, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_OneofOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_OneofOptions__fields[1] = {
+  {999, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_OneofOptions_msginit = {
+  &google_protobuf_OneofOptions_submsgs[0],
+  &google_protobuf_OneofOptions__fields[0],
+  UPB_SIZE(8, 8), 1, upb_ExtMode_Extendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_EnumOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_EnumOptions__fields[3] = {
+  {2, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(2, 2), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_EnumOptions_msginit = {
+  &google_protobuf_EnumOptions_submsgs[0],
+  &google_protobuf_EnumOptions__fields[0],
+  UPB_SIZE(8, 16), 3, upb_ExtMode_Extendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_EnumValueOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_EnumValueOptions__fields[2] = {
+  {1, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_EnumValueOptions_msginit = {
+  &google_protobuf_EnumValueOptions_submsgs[0],
+  &google_protobuf_EnumValueOptions__fields[0],
+  UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 1, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_ServiceOptions_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_ServiceOptions__fields[2] = {
+  {33, UPB_SIZE(1, 1), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(4, 8), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_ServiceOptions_msginit = {
+  &google_protobuf_ServiceOptions_submsgs[0],
+  &google_protobuf_ServiceOptions__fields[0],
+  UPB_SIZE(8, 16), 2, upb_ExtMode_Extendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_MethodOptions_submsgs[2] = {
+  {.submsg = &google_protobuf_UninterpretedOption_msginit},
+  {.subenum = &google_protobuf_MethodOptions_IdempotencyLevel_enuminit},
+};
+
+static const upb_MiniTable_Field google_protobuf_MethodOptions__fields[3] = {
+  {33, UPB_SIZE(8, 8), 1, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+  {34, UPB_SIZE(4, 4), 2, 1, 14, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {999, UPB_SIZE(12, 16), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_MethodOptions_msginit = {
+  &google_protobuf_MethodOptions_submsgs[0],
+  &google_protobuf_MethodOptions__fields[0],
+  UPB_SIZE(16, 24), 3, upb_ExtMode_Extendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_UninterpretedOption_submsgs[1] = {
+  {.submsg = &google_protobuf_UninterpretedOption_NamePart_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_UninterpretedOption__fields[7] = {
+  {2, UPB_SIZE(56, 80), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(32, 32), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(8, 8), 2, 0, 4, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)},
+  {5, UPB_SIZE(16, 16), 3, 0, 3, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(24, 24), 4, 0, 1, kUpb_FieldMode_Scalar | (upb_FieldRep_8Byte << upb_FieldRep_Shift)},
+  {7, UPB_SIZE(40, 48), 5, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {8, UPB_SIZE(48, 64), 6, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_UninterpretedOption_msginit = {
+  &google_protobuf_UninterpretedOption_submsgs[0],
+  &google_protobuf_UninterpretedOption__fields[0],
+  UPB_SIZE(64, 96), 7, upb_ExtMode_NonExtendable, 0, 255, 0,
+};
+
+static const upb_MiniTable_Field google_protobuf_UninterpretedOption_NamePart__fields[2] = {
+  {1, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(1, 1), 2, 0, 8, kUpb_FieldMode_Scalar | (upb_FieldRep_1Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit = {
+  NULL,
+  &google_protobuf_UninterpretedOption_NamePart__fields[0],
+  UPB_SIZE(16, 32), 2, upb_ExtMode_NonExtendable, 2, 255, 2,
+};
+
+static const upb_MiniTable_Sub google_protobuf_SourceCodeInfo_submsgs[1] = {
+  {.submsg = &google_protobuf_SourceCodeInfo_Location_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_SourceCodeInfo__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_SourceCodeInfo_msginit = {
+  &google_protobuf_SourceCodeInfo_submsgs[0],
+  &google_protobuf_SourceCodeInfo__fields[0],
+  UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0,
+};
+
+static const upb_MiniTable_Field google_protobuf_SourceCodeInfo_Location__fields[5] = {
+  {1, UPB_SIZE(20, 40), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(24, 48), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(4, 8), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(12, 24), 2, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {6, UPB_SIZE(28, 56), 0, 0, 12, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit = {
+  NULL,
+  &google_protobuf_SourceCodeInfo_Location__fields[0],
+  UPB_SIZE(32, 64), 5, upb_ExtMode_NonExtendable, 4, 255, 0,
+};
+
+static const upb_MiniTable_Sub google_protobuf_GeneratedCodeInfo_submsgs[1] = {
+  {.submsg = &google_protobuf_GeneratedCodeInfo_Annotation_msginit},
+};
+
+static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo__fields[1] = {
+  {1, UPB_SIZE(0, 0), 0, 0, 11, kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit = {
+  &google_protobuf_GeneratedCodeInfo_submsgs[0],
+  &google_protobuf_GeneratedCodeInfo__fields[0],
+  UPB_SIZE(8, 8), 1, upb_ExtMode_NonExtendable, 1, 255, 0,
+};
+
+static const upb_MiniTable_Field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = {
+  {1, UPB_SIZE(20, 32), 0, 0, 5, kUpb_FieldMode_Array | upb_LabelFlags_IsPacked | (upb_FieldRep_Pointer << upb_FieldRep_Shift)},
+  {2, UPB_SIZE(12, 16), 1, 0, 12, kUpb_FieldMode_Scalar | (upb_FieldRep_StringView << upb_FieldRep_Shift)},
+  {3, UPB_SIZE(4, 4), 2, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+  {4, UPB_SIZE(8, 8), 3, 0, 5, kUpb_FieldMode_Scalar | (upb_FieldRep_4Byte << upb_FieldRep_Shift)},
+};
+
+const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit = {
+  NULL,
+  &google_protobuf_GeneratedCodeInfo_Annotation__fields[0],
+  UPB_SIZE(24, 48), 4, upb_ExtMode_NonExtendable, 4, 255, 0,
+};
+
+static const upb_MiniTable *messages_layout[27] = {
+  &google_protobuf_FileDescriptorSet_msginit,
+  &google_protobuf_FileDescriptorProto_msginit,
   &google_protobuf_DescriptorProto_msginit,
   &google_protobuf_DescriptorProto_ExtensionRange_msginit,
   &google_protobuf_DescriptorProto_ReservedRange_msginit,
-  &google_protobuf_EnumDescriptorProto_msginit,
-  &google_protobuf_FieldDescriptorProto_msginit,
-  &google_protobuf_MessageOptions_msginit,
-  &google_protobuf_OneofDescriptorProto_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(16, 32), 0, 4, 11, _UPB_MODE_ARRAY},
-  {3, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY},
-  {4, UPB_SIZE(24, 48), 0, 3, 11, _UPB_MODE_ARRAY},
-  {5, UPB_SIZE(28, 56), 0, 1, 11, _UPB_MODE_ARRAY},
-  {6, UPB_SIZE(32, 64), 0, 4, 11, _UPB_MODE_ARRAY},
-  {7, UPB_SIZE(12, 24), 2, 5, 11, _UPB_MODE_SCALAR},
-  {8, UPB_SIZE(36, 72), 0, 6, 11, _UPB_MODE_ARRAY},
-  {9, UPB_SIZE(40, 80), 0, 2, 11, _UPB_MODE_ARRAY},
-  {10, UPB_SIZE(44, 88), 0, 0, 12, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_DescriptorProto_msginit = {
-  &google_protobuf_DescriptorProto_submsgs[0],
-  &google_protobuf_DescriptorProto__fields[0],
-  UPB_SIZE(48, 96), 10, false, 10, 255,
-};
-
-static const upb_msglayout *const google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = {
   &google_protobuf_ExtensionRangeOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = {
-  {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(12, 16), 3, 0, 11, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = {
-  &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0],
-  &google_protobuf_DescriptorProto_ExtensionRange__fields[0],
-  UPB_SIZE(16, 24), 3, false, 3, 255,
-};
-
-static const upb_msglayout_field google_protobuf_DescriptorProto_ReservedRange__fields[2] = {
-  {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = {
-  NULL,
-  &google_protobuf_DescriptorProto_ReservedRange__fields[0],
-  UPB_SIZE(16, 16), 2, false, 2, 255,
-};
-
-static const upb_msglayout *const google_protobuf_ExtensionRangeOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_ExtensionRangeOptions__fields[1] = {
-  {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = {
-  &google_protobuf_ExtensionRangeOptions_submsgs[0],
-  &google_protobuf_ExtensionRangeOptions__fields[0],
-  UPB_SIZE(8, 8), 1, false, 0, 255,
-};
-
-static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1] = {
-  &google_protobuf_FieldOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = {
-  {1, UPB_SIZE(24, 24), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(32, 40), 2, 0, 12, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(12, 12), 3, 0, 5, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(4, 4), 4, 0, 14, _UPB_MODE_SCALAR},
-  {5, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR},
-  {6, UPB_SIZE(40, 56), 6, 0, 12, _UPB_MODE_SCALAR},
-  {7, UPB_SIZE(48, 72), 7, 0, 12, _UPB_MODE_SCALAR},
-  {8, UPB_SIZE(64, 104), 8, 0, 11, _UPB_MODE_SCALAR},
-  {9, UPB_SIZE(16, 16), 9, 0, 5, _UPB_MODE_SCALAR},
-  {10, UPB_SIZE(56, 88), 10, 0, 12, _UPB_MODE_SCALAR},
-  {17, UPB_SIZE(20, 20), 11, 0, 8, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = {
-  &google_protobuf_FieldDescriptorProto_submsgs[0],
-  &google_protobuf_FieldDescriptorProto__fields[0],
-  UPB_SIZE(72, 112), 11, false, 10, 255,
-};
-
-static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1] = {
-  &google_protobuf_OneofOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(12, 24), 2, 0, 11, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = {
-  &google_protobuf_OneofDescriptorProto_submsgs[0],
-  &google_protobuf_OneofDescriptorProto__fields[0],
-  UPB_SIZE(16, 32), 2, false, 2, 255,
-};
-
-static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] = {
+  &google_protobuf_FieldDescriptorProto_msginit,
+  &google_protobuf_OneofDescriptorProto_msginit,
+  &google_protobuf_EnumDescriptorProto_msginit,
   &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit,
-  &google_protobuf_EnumOptions_msginit,
   &google_protobuf_EnumValueDescriptorProto_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(16, 32), 0, 2, 11, _UPB_MODE_ARRAY},
-  {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(20, 40), 0, 0, 11, _UPB_MODE_ARRAY},
-  {5, UPB_SIZE(24, 48), 0, 0, 12, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = {
-  &google_protobuf_EnumDescriptorProto_submsgs[0],
-  &google_protobuf_EnumDescriptorProto__fields[0],
-  UPB_SIZE(32, 64), 5, false, 5, 255,
-};
-
-static const upb_msglayout_field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = {
-  {1, UPB_SIZE(4, 4), 1, 0, 5, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(8, 8), 2, 0, 5, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = {
-  NULL,
-  &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0],
-  UPB_SIZE(16, 16), 2, false, 2, 255,
-};
-
-static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_submsgs[1] = {
-  &google_protobuf_EnumValueOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = {
-  {1, UPB_SIZE(8, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(16, 24), 3, 0, 11, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = {
-  &google_protobuf_EnumValueDescriptorProto_submsgs[0],
-  &google_protobuf_EnumValueDescriptorProto__fields[0],
-  UPB_SIZE(24, 32), 3, false, 3, 255,
-};
-
-static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs[2] = {
+  &google_protobuf_ServiceDescriptorProto_msginit,
   &google_protobuf_MethodDescriptorProto_msginit,
+  &google_protobuf_FileOptions_msginit,
+  &google_protobuf_MessageOptions_msginit,
+  &google_protobuf_FieldOptions_msginit,
+  &google_protobuf_OneofOptions_msginit,
+  &google_protobuf_EnumOptions_msginit,
+  &google_protobuf_EnumValueOptions_msginit,
   &google_protobuf_ServiceOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(16, 32), 0, 0, 11, _UPB_MODE_ARRAY},
-  {3, UPB_SIZE(12, 24), 2, 1, 11, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = {
-  &google_protobuf_ServiceDescriptorProto_submsgs[0],
-  &google_protobuf_ServiceDescriptorProto__fields[0],
-  UPB_SIZE(24, 48), 3, false, 3, 255,
-};
-
-static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[1] = {
   &google_protobuf_MethodOptions_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(20, 40), 3, 0, 12, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(28, 56), 4, 0, 11, _UPB_MODE_SCALAR},
-  {5, UPB_SIZE(1, 1), 5, 0, 8, _UPB_MODE_SCALAR},
-  {6, UPB_SIZE(2, 2), 6, 0, 8, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = {
-  &google_protobuf_MethodDescriptorProto_submsgs[0],
-  &google_protobuf_MethodDescriptorProto__fields[0],
-  UPB_SIZE(32, 64), 6, false, 6, 255,
-};
-
-static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = {
   &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = {
-  {1, UPB_SIZE(20, 24), 1, 0, 12, _UPB_MODE_SCALAR},
-  {8, UPB_SIZE(28, 40), 2, 0, 12, _UPB_MODE_SCALAR},
-  {9, UPB_SIZE(4, 4), 3, 0, 14, _UPB_MODE_SCALAR},
-  {10, UPB_SIZE(8, 8), 4, 0, 8, _UPB_MODE_SCALAR},
-  {11, UPB_SIZE(36, 56), 5, 0, 12, _UPB_MODE_SCALAR},
-  {16, UPB_SIZE(9, 9), 6, 0, 8, _UPB_MODE_SCALAR},
-  {17, UPB_SIZE(10, 10), 7, 0, 8, _UPB_MODE_SCALAR},
-  {18, UPB_SIZE(11, 11), 8, 0, 8, _UPB_MODE_SCALAR},
-  {20, UPB_SIZE(12, 12), 9, 0, 8, _UPB_MODE_SCALAR},
-  {23, UPB_SIZE(13, 13), 10, 0, 8, _UPB_MODE_SCALAR},
-  {27, UPB_SIZE(14, 14), 11, 0, 8, _UPB_MODE_SCALAR},
-  {31, UPB_SIZE(15, 15), 12, 0, 8, _UPB_MODE_SCALAR},
-  {36, UPB_SIZE(44, 72), 13, 0, 12, _UPB_MODE_SCALAR},
-  {37, UPB_SIZE(52, 88), 14, 0, 12, _UPB_MODE_SCALAR},
-  {39, UPB_SIZE(60, 104), 15, 0, 12, _UPB_MODE_SCALAR},
-  {40, UPB_SIZE(68, 120), 16, 0, 12, _UPB_MODE_SCALAR},
-  {41, UPB_SIZE(76, 136), 17, 0, 12, _UPB_MODE_SCALAR},
-  {42, UPB_SIZE(16, 16), 18, 0, 8, _UPB_MODE_SCALAR},
-  {44, UPB_SIZE(84, 152), 19, 0, 12, _UPB_MODE_SCALAR},
-  {45, UPB_SIZE(92, 168), 20, 0, 12, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(100, 184), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_FileOptions_msginit = {
-  &google_protobuf_FileOptions_submsgs[0],
-  &google_protobuf_FileOptions__fields[0],
-  UPB_SIZE(104, 192), 21, false, 1, 255,
-};
-
-static const upb_msglayout *const google_protobuf_MessageOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = {
-  {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(3, 3), 3, 0, 8, _UPB_MODE_SCALAR},
-  {7, UPB_SIZE(4, 4), 4, 0, 8, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(8, 8), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_MessageOptions_msginit = {
-  &google_protobuf_MessageOptions_submsgs[0],
-  &google_protobuf_MessageOptions__fields[0],
-  UPB_SIZE(16, 16), 5, false, 3, 255,
-};
-
-static const upb_msglayout *const google_protobuf_FieldOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = {
-  {1, UPB_SIZE(4, 4), 1, 0, 14, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(12, 12), 2, 0, 8, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(13, 13), 3, 0, 8, _UPB_MODE_SCALAR},
-  {5, UPB_SIZE(14, 14), 4, 0, 8, _UPB_MODE_SCALAR},
-  {6, UPB_SIZE(8, 8), 5, 0, 14, _UPB_MODE_SCALAR},
-  {10, UPB_SIZE(15, 15), 6, 0, 8, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(16, 16), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_FieldOptions_msginit = {
-  &google_protobuf_FieldOptions_submsgs[0],
-  &google_protobuf_FieldOptions__fields[0],
-  UPB_SIZE(24, 24), 7, false, 3, 255,
-};
-
-static const upb_msglayout *const google_protobuf_OneofOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = {
-  {999, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_OneofOptions_msginit = {
-  &google_protobuf_OneofOptions_submsgs[0],
-  &google_protobuf_OneofOptions__fields[0],
-  UPB_SIZE(8, 8), 1, false, 0, 255,
-};
-
-static const upb_msglayout *const google_protobuf_EnumOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = {
-  {2, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(2, 2), 2, 0, 8, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_EnumOptions_msginit = {
-  &google_protobuf_EnumOptions_submsgs[0],
-  &google_protobuf_EnumOptions__fields[0],
-  UPB_SIZE(8, 16), 3, false, 0, 255,
-};
-
-static const upb_msglayout *const google_protobuf_EnumValueOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = {
-  {1, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_EnumValueOptions_msginit = {
-  &google_protobuf_EnumValueOptions_submsgs[0],
-  &google_protobuf_EnumValueOptions__fields[0],
-  UPB_SIZE(8, 16), 2, false, 1, 255,
-};
-
-static const upb_msglayout *const google_protobuf_ServiceOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = {
-  {33, UPB_SIZE(1, 1), 1, 0, 8, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(4, 8), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_ServiceOptions_msginit = {
-  &google_protobuf_ServiceOptions_submsgs[0],
-  &google_protobuf_ServiceOptions__fields[0],
-  UPB_SIZE(8, 16), 2, false, 0, 255,
-};
-
-static const upb_msglayout *const google_protobuf_MethodOptions_submsgs[1] = {
-  &google_protobuf_UninterpretedOption_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = {
-  {33, UPB_SIZE(8, 8), 1, 0, 8, _UPB_MODE_SCALAR},
-  {34, UPB_SIZE(4, 4), 2, 0, 14, _UPB_MODE_SCALAR},
-  {999, UPB_SIZE(12, 16), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_MethodOptions_msginit = {
-  &google_protobuf_MethodOptions_submsgs[0],
-  &google_protobuf_MethodOptions__fields[0],
-  UPB_SIZE(16, 24), 3, false, 0, 255,
-};
-
-static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] = {
   &google_protobuf_UninterpretedOption_NamePart_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = {
-  {2, UPB_SIZE(56, 80), 0, 0, 11, _UPB_MODE_ARRAY},
-  {3, UPB_SIZE(32, 32), 1, 0, 12, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(8, 8), 2, 0, 4, _UPB_MODE_SCALAR},
-  {5, UPB_SIZE(16, 16), 3, 0, 3, _UPB_MODE_SCALAR},
-  {6, UPB_SIZE(24, 24), 4, 0, 1, _UPB_MODE_SCALAR},
-  {7, UPB_SIZE(40, 48), 5, 0, 12, _UPB_MODE_SCALAR},
-  {8, UPB_SIZE(48, 64), 6, 0, 12, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_UninterpretedOption_msginit = {
-  &google_protobuf_UninterpretedOption_submsgs[0],
-  &google_protobuf_UninterpretedOption__fields[0],
-  UPB_SIZE(64, 96), 7, false, 0, 255,
-};
-
-static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = {
-  {1, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {2, UPB_SIZE(1, 1), 2, 0, 8, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = {
-  NULL,
-  &google_protobuf_UninterpretedOption_NamePart__fields[0],
-  UPB_SIZE(16, 32), 2, false, 2, 255,
-};
-
-static const upb_msglayout *const google_protobuf_SourceCodeInfo_submsgs[1] = {
+  &google_protobuf_SourceCodeInfo_msginit,
   &google_protobuf_SourceCodeInfo_Location_msginit,
-};
-
-static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_SourceCodeInfo_msginit = {
-  &google_protobuf_SourceCodeInfo_submsgs[0],
-  &google_protobuf_SourceCodeInfo__fields[0],
-  UPB_SIZE(8, 8), 1, false, 1, 255,
-};
-
-static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = {
-  {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED},
-  {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED},
-  {3, UPB_SIZE(4, 8), 1, 0, 12, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(12, 24), 2, 0, 12, _UPB_MODE_SCALAR},
-  {6, UPB_SIZE(28, 56), 0, 0, 12, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = {
-  NULL,
-  &google_protobuf_SourceCodeInfo_Location__fields[0],
-  UPB_SIZE(32, 64), 5, false, 4, 255,
-};
-
-static const upb_msglayout *const google_protobuf_GeneratedCodeInfo_submsgs[1] = {
+  &google_protobuf_GeneratedCodeInfo_msginit,
   &google_protobuf_GeneratedCodeInfo_Annotation_msginit,
 };
 
-static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = {
-  {1, UPB_SIZE(0, 0), 0, 0, 11, _UPB_MODE_ARRAY},
-};
-
-const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = {
-  &google_protobuf_GeneratedCodeInfo_submsgs[0],
-  &google_protobuf_GeneratedCodeInfo__fields[0],
-  UPB_SIZE(8, 8), 1, false, 1, 255,
-};
-
-static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = {
-  {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_MODE_ARRAY | _UPB_MODE_IS_PACKED},
-  {2, UPB_SIZE(12, 16), 1, 0, 12, _UPB_MODE_SCALAR},
-  {3, UPB_SIZE(4, 4), 2, 0, 5, _UPB_MODE_SCALAR},
-  {4, UPB_SIZE(8, 8), 3, 0, 5, _UPB_MODE_SCALAR},
-};
-
-const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = {
+const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit = {
   NULL,
-  &google_protobuf_GeneratedCodeInfo_Annotation__fields[0],
-  UPB_SIZE(24, 48), 4, false, 4, 255,
+  0x7fffeULL,
+  0,
+};
+
+const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit = {
+  NULL,
+  0xeULL,
+  0,
+};
+
+const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit = {
+  NULL,
+  0xeULL,
+  0,
+};
+
+const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit = {
+  NULL,
+  0x7ULL,
+  0,
+};
+
+const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit = {
+  NULL,
+  0x7ULL,
+  0,
+};
+
+const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit = {
+  NULL,
+  0x7ULL,
+  0,
+};
+
+static const upb_MiniTable_Enum *enums_layout[6] = {
+  &google_protobuf_FieldDescriptorProto_Type_enuminit,
+  &google_protobuf_FieldDescriptorProto_Label_enuminit,
+  &google_protobuf_FileOptions_OptimizeMode_enuminit,
+  &google_protobuf_FieldOptions_CType_enuminit,
+  &google_protobuf_FieldOptions_JSType_enuminit,
+  &google_protobuf_MethodOptions_IdempotencyLevel_enuminit,
+};
+
+const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout = {
+  messages_layout,
+  enums_layout,
+  NULL,
+  27,
+  6,
+  0,
 };
 
 
@@ -4469,143 +5145,240 @@
 
 typedef struct {
   size_t len;
-  char str[1];  /* Null-terminated string data follows. */
+  char str[1]; /* Null-terminated string data follows. */
 } str_t;
 
-struct upb_fielddef {
-  const upb_filedef *file;
-  const upb_msgdef *msgdef;
-  const char *full_name;
-  const char *json_name;
+/* The upb core does not generally have a concept of default instances. However
+ * for descriptor options we make an exception since the max size is known and
+ * modest (<200 bytes). All types can share a default instance since it is
+ * initialized to zeroes.
+ *
+ * We have to allocate an extra pointer for upb's internal metadata. */
+static const char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0};
+static const char* opt_default = &opt_default_buf[sizeof(void*)];
+
+struct upb_FieldDef {
+  const google_protobuf_FieldOptions* opts;
+  const upb_FileDef* file;
+  const upb_MessageDef* msgdef;
+  const char* full_name;
+  const char* json_name;
   union {
     int64_t sint;
     uint64_t uint;
     double dbl;
     float flt;
     bool boolean;
-    str_t *str;
+    str_t* str;
   } defaultval;
-  const upb_oneofdef *oneof;
   union {
-    const upb_msgdef *msgdef;
-    const upb_enumdef *enumdef;
-    const google_protobuf_FieldDescriptorProto *unresolved;
+    const upb_OneofDef* oneof;
+    const upb_MessageDef* extension_scope;
+  } scope;
+  union {
+    const upb_MessageDef* msgdef;
+    const upb_EnumDef* enumdef;
+    const google_protobuf_FieldDescriptorProto* unresolved;
   } sub;
   uint32_t number_;
   uint16_t index_;
-  uint16_t layout_index;
+  uint16_t layout_index; /* Index into msgdef->layout->fields or file->exts */
+  bool has_default;
   bool is_extension_;
-  bool lazy_;
   bool packed_;
   bool proto3_optional_;
-  upb_descriptortype_t type_;
-  upb_label_t label_;
+  bool has_json_name_;
+  upb_FieldType type_;
+  upb_Label label_;
 };
 
-struct upb_msgdef {
-  const upb_msglayout *layout;
-  const upb_filedef *file;
-  const char *full_name;
+struct upb_ExtensionRange {
+  const google_protobuf_ExtensionRangeOptions* opts;
+  int32_t start;
+  int32_t end;
+};
+
+struct upb_MessageDef {
+  const google_protobuf_MessageOptions* opts;
+  const upb_MiniTable* layout;
+  const upb_FileDef* file;
+  const upb_MessageDef* containing_type;
+  const char* full_name;
 
   /* Tables for looking up fields by number and name. */
   upb_inttable itof;
   upb_strtable ntof;
 
-  const upb_fielddef *fields;
-  const upb_oneofdef *oneofs;
+  /* All nested defs.
+   * MEM: We could save some space here by putting nested defs in a contiguous
+   * region and calculating counts from offsets or vice-versa. */
+  const upb_FieldDef* fields;
+  const upb_OneofDef* oneofs;
+  const upb_ExtensionRange* ext_ranges;
+  const upb_MessageDef* nested_msgs;
+  const upb_EnumDef* nested_enums;
+  const upb_FieldDef* nested_exts;
   int field_count;
-  int oneof_count;
   int real_oneof_count;
-
-  /* Is this a map-entry message? */
-  bool map_entry;
-  upb_wellknowntype_t well_known_type;
-
-  /* TODO(haberman): proper extension ranges (there can be multiple). */
+  int oneof_count;
+  int ext_range_count;
+  int nested_msg_count;
+  int nested_enum_count;
+  int nested_ext_count;
+  bool in_message_set;
+  upb_WellKnown well_known_type;
 };
 
-struct upb_enumdef {
-  const upb_filedef *file;
-  const char *full_name;
+struct upb_EnumDef {
+  const google_protobuf_EnumOptions* opts;
+  const upb_MiniTable_Enum* layout;  // Only for proto2.
+  const upb_FileDef* file;
+  const upb_MessageDef* containing_type;  // Could be merged with "file".
+  const char* full_name;
   upb_strtable ntoi;
   upb_inttable iton;
+  const upb_EnumValueDef* values;
+  int value_count;
   int32_t defaultval;
 };
 
-struct upb_oneofdef {
-  const upb_msgdef *parent;
-  const char *full_name;
+struct upb_EnumValueDef {
+  const google_protobuf_EnumValueOptions* opts;
+  const upb_EnumDef* parent;
+  const char* full_name;
+  int32_t number;
+};
+
+struct upb_OneofDef {
+  const google_protobuf_OneofOptions* opts;
+  const upb_MessageDef* parent;
+  const char* full_name;
   int field_count;
   bool synthetic;
-  const upb_fielddef **fields;
+  const upb_FieldDef** fields;
   upb_strtable ntof;
   upb_inttable itof;
 };
 
-struct upb_filedef {
-  const char *name;
-  const char *package;
-  const char *phpprefix;
-  const char *phpnamespace;
+struct upb_FileDef {
+  const google_protobuf_FileOptions* opts;
+  const char* name;
+  const char* package;
 
-  const upb_filedef **deps;
-  const upb_msgdef *msgs;
-  const upb_enumdef *enums;
-  const upb_fielddef *exts;
-  const upb_symtab *symtab;
+  const upb_FileDef** deps;
+  const int32_t* public_deps;
+  const int32_t* weak_deps;
+  const upb_MessageDef* top_lvl_msgs;
+  const upb_EnumDef* top_lvl_enums;
+  const upb_FieldDef* top_lvl_exts;
+  const upb_ServiceDef* services;
+  const upb_MiniTable_Extension** ext_layouts;
+  const upb_DefPool* symtab;
 
   int dep_count;
-  int msg_count;
-  int enum_count;
-  int ext_count;
-  upb_syntax_t syntax;
+  int public_dep_count;
+  int weak_dep_count;
+  int top_lvl_msg_count;
+  int top_lvl_enum_count;
+  int top_lvl_ext_count;
+  int service_count;
+  int ext_count; /* All exts in the file. */
+  upb_Syntax syntax;
 };
 
-struct upb_symtab {
-  upb_arena *arena;
+struct upb_MethodDef {
+  const google_protobuf_MethodOptions* opts;
+  upb_ServiceDef* service;
+  const char* full_name;
+  const upb_MessageDef* input_type;
+  const upb_MessageDef* output_type;
+  bool client_streaming;
+  bool server_streaming;
+};
+
+struct upb_ServiceDef {
+  const google_protobuf_ServiceOptions* opts;
+  const upb_FileDef* file;
+  const char* full_name;
+  upb_MethodDef* methods;
+  int method_count;
+  int index;
+};
+
+struct upb_DefPool {
+  upb_Arena* arena;
   upb_strtable syms;  /* full_name -> packed def ptr */
-  upb_strtable files;  /* file_name -> upb_filedef* */
+  upb_strtable files; /* file_name -> upb_FileDef* */
+  upb_inttable exts;  /* upb_MiniTable_Extension* -> upb_FieldDef* */
+  upb_ExtensionRegistry* extreg;
   size_t bytes_loaded;
 };
 
 /* Inside a symtab we store tagged pointers to specific def types. */
 typedef enum {
-  UPB_DEFTYPE_FIELD = 0,
+  UPB_DEFTYPE_MASK = 7,
 
   /* Only inside symtab table. */
+  UPB_DEFTYPE_EXT = 0,
   UPB_DEFTYPE_MSG = 1,
   UPB_DEFTYPE_ENUM = 2,
+  UPB_DEFTYPE_ENUMVAL = 3,
+  UPB_DEFTYPE_SERVICE = 4,
 
   /* Only inside message table. */
+  UPB_DEFTYPE_FIELD = 0,
   UPB_DEFTYPE_ONEOF = 1,
-  UPB_DEFTYPE_FIELD_JSONNAME = 2
+  UPB_DEFTYPE_FIELD_JSONNAME = 2,
+
+  /* Only inside file table. */
+  UPB_DEFTYPE_FILE = 0,
+  UPB_DEFTYPE_LAYOUT = 1
 } upb_deftype_t;
 
-static const void *unpack_def(upb_value v, upb_deftype_t type) {
+#define FIELD_TYPE_UNSPECIFIED 0
+
+static upb_deftype_t deftype(upb_value v) {
   uintptr_t num = (uintptr_t)upb_value_getconstptr(v);
-  return (num & 3) == type ? (const void*)(num & ~3) : NULL;
+  return num & UPB_DEFTYPE_MASK;
 }
 
-static upb_value pack_def(const void *ptr, upb_deftype_t type) {
-  uintptr_t num = (uintptr_t)ptr | type;
+static const void* unpack_def(upb_value v, upb_deftype_t type) {
+  uintptr_t num = (uintptr_t)upb_value_getconstptr(v);
+  return (num & UPB_DEFTYPE_MASK) == type
+             ? (const void*)(num & ~UPB_DEFTYPE_MASK)
+             : NULL;
+}
+
+static upb_value pack_def(const void* ptr, upb_deftype_t type) {
+  uintptr_t num = (uintptr_t)ptr;
+  UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0);
+  num |= type;
   return upb_value_constptr((const void*)num);
 }
 
 /* isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. */
-static bool upb_isbetween(char c, char low, char high) {
+static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) {
   return c >= low && c <= high;
 }
 
+static char upb_ascii_lower(char ch) {
+  // Per ASCII this will lower-case a letter.  If the result is a letter, the
+  // input was definitely a letter.  If the output is not a letter, this may
+  // have transformed the character unpredictably.
+  return ch | 0x20;
+}
+
 static bool upb_isletter(char c) {
-  return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+  char lower = upb_ascii_lower(c);
+  return upb_isbetween(lower, 'a', 'z') || c == '_';
 }
 
 static bool upb_isalphanum(char c) {
   return upb_isletter(c) || upb_isbetween(c, '0', '9');
 }
 
-static const char *shortdefname(const char *fullname) {
-  const char *p;
+static const char* shortdefname(const char* fullname) {
+  const char* p;
 
   if (fullname == NULL) {
     return NULL;
@@ -4620,371 +5393,417 @@
 
 /* All submessage fields are lower than all other fields.
  * Secondly, fields are increasing in order. */
-uint32_t field_rank(const upb_fielddef *f) {
-  uint32_t ret = upb_fielddef_number(f);
+uint32_t field_rank(const upb_FieldDef* f) {
+  uint32_t ret = upb_FieldDef_Number(f);
   const uint32_t high_bit = 1 << 30;
   UPB_ASSERT(ret < high_bit);
-  if (!upb_fielddef_issubmsg(f))
-    ret |= high_bit;
+  if (!upb_FieldDef_IsSubMessage(f)) ret |= high_bit;
   return ret;
 }
 
-int cmp_fields(const void *p1, const void *p2) {
-  const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
-  const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+int cmp_fields(const void* p1, const void* p2) {
+  const upb_FieldDef* f1 = *(upb_FieldDef* const*)p1;
+  const upb_FieldDef* f2 = *(upb_FieldDef* const*)p2;
   return field_rank(f1) - field_rank(f2);
 }
 
-static void upb_status_setoom(upb_status *status) {
-  upb_status_seterrmsg(status, "out of memory");
+static void upb_Status_setoom(upb_Status* status) {
+  upb_Status_SetErrorMessage(status, "out of memory");
 }
 
-static void assign_msg_wellknowntype(upb_msgdef *m) {
-  const char *name = upb_msgdef_fullname(m);
+static void assign_msg_wellknowntype(upb_MessageDef* m) {
+  const char* name = upb_MessageDef_FullName(m);
   if (name == NULL) {
-    m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED;
+    m->well_known_type = kUpb_WellKnown_Unspecified;
     return;
   }
   if (!strcmp(name, "google.protobuf.Any")) {
-    m->well_known_type = UPB_WELLKNOWN_ANY;
+    m->well_known_type = kUpb_WellKnown_Any;
   } else if (!strcmp(name, "google.protobuf.FieldMask")) {
-    m->well_known_type = UPB_WELLKNOWN_FIELDMASK;
+    m->well_known_type = kUpb_WellKnown_FieldMask;
   } else if (!strcmp(name, "google.protobuf.Duration")) {
-    m->well_known_type = UPB_WELLKNOWN_DURATION;
+    m->well_known_type = kUpb_WellKnown_Duration;
   } else if (!strcmp(name, "google.protobuf.Timestamp")) {
-    m->well_known_type = UPB_WELLKNOWN_TIMESTAMP;
+    m->well_known_type = kUpb_WellKnown_Timestamp;
   } else if (!strcmp(name, "google.protobuf.DoubleValue")) {
-    m->well_known_type = UPB_WELLKNOWN_DOUBLEVALUE;
+    m->well_known_type = kUpb_WellKnown_DoubleValue;
   } else if (!strcmp(name, "google.protobuf.FloatValue")) {
-    m->well_known_type = UPB_WELLKNOWN_FLOATVALUE;
+    m->well_known_type = kUpb_WellKnown_FloatValue;
   } else if (!strcmp(name, "google.protobuf.Int64Value")) {
-    m->well_known_type = UPB_WELLKNOWN_INT64VALUE;
+    m->well_known_type = kUpb_WellKnown_Int64Value;
   } else if (!strcmp(name, "google.protobuf.UInt64Value")) {
-    m->well_known_type = UPB_WELLKNOWN_UINT64VALUE;
+    m->well_known_type = kUpb_WellKnown_UInt64Value;
   } else if (!strcmp(name, "google.protobuf.Int32Value")) {
-    m->well_known_type = UPB_WELLKNOWN_INT32VALUE;
+    m->well_known_type = kUpb_WellKnown_Int32Value;
   } else if (!strcmp(name, "google.protobuf.UInt32Value")) {
-    m->well_known_type = UPB_WELLKNOWN_UINT32VALUE;
+    m->well_known_type = kUpb_WellKnown_UInt32Value;
   } else if (!strcmp(name, "google.protobuf.BoolValue")) {
-    m->well_known_type = UPB_WELLKNOWN_BOOLVALUE;
+    m->well_known_type = kUpb_WellKnown_BoolValue;
   } else if (!strcmp(name, "google.protobuf.StringValue")) {
-    m->well_known_type = UPB_WELLKNOWN_STRINGVALUE;
+    m->well_known_type = kUpb_WellKnown_StringValue;
   } else if (!strcmp(name, "google.protobuf.BytesValue")) {
-    m->well_known_type = UPB_WELLKNOWN_BYTESVALUE;
+    m->well_known_type = kUpb_WellKnown_BytesValue;
   } else if (!strcmp(name, "google.protobuf.Value")) {
-    m->well_known_type = UPB_WELLKNOWN_VALUE;
+    m->well_known_type = kUpb_WellKnown_Value;
   } else if (!strcmp(name, "google.protobuf.ListValue")) {
-    m->well_known_type = UPB_WELLKNOWN_LISTVALUE;
+    m->well_known_type = kUpb_WellKnown_ListValue;
   } else if (!strcmp(name, "google.protobuf.Struct")) {
-    m->well_known_type = UPB_WELLKNOWN_STRUCT;
+    m->well_known_type = kUpb_WellKnown_Struct;
   } else {
-    m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED;
+    m->well_known_type = kUpb_WellKnown_Unspecified;
   }
 }
 
+/* upb_EnumDef ****************************************************************/
 
-/* upb_enumdef ****************************************************************/
-
-const char *upb_enumdef_fullname(const upb_enumdef *e) {
-  return e->full_name;
+const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) {
+  return e->opts;
 }
 
-const char *upb_enumdef_name(const upb_enumdef *e) {
+bool upb_EnumDef_HasOptions(const upb_EnumDef* e) {
+  return e->opts != (void*)opt_default;
+}
+
+const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; }
+
+const char* upb_EnumDef_Name(const upb_EnumDef* e) {
   return shortdefname(e->full_name);
 }
 
-const upb_filedef *upb_enumdef_file(const upb_enumdef *e) {
-  return e->file;
+const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; }
+
+const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) {
+  return e->containing_type;
 }
 
-int32_t upb_enumdef_default(const upb_enumdef *e) {
-  UPB_ASSERT(upb_enumdef_iton(e, e->defaultval));
+int32_t upb_EnumDef_Default(const upb_EnumDef* e) {
+  UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval));
   return e->defaultval;
 }
 
-int upb_enumdef_numvals(const upb_enumdef *e) {
-  return (int)upb_strtable_count(&e->ntoi);
-}
+int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; }
 
-void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
-  /* We iterate over the ntoi table, to account for duplicate numbers. */
-  upb_strtable_begin(i, &e->ntoi);
-}
-
-void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
-bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
-
-bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
-                      size_t len, int32_t *num) {
+const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize(
+    const upb_EnumDef* def, const char* name, size_t len) {
   upb_value v;
-  if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
-    return false;
-  }
-  if (num) *num = upb_value_getint32(v);
-  return true;
+  return upb_strtable_lookup2(&def->ntoi, name, len, &v)
+             ? upb_value_getconstptr(v)
+             : NULL;
 }
 
-const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* def,
+                                                      int32_t num) {
   upb_value v;
-  return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL;
+  return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v)
+                                                  : NULL;
 }
 
-const char *upb_enum_iter_name(upb_enum_iter *iter) {
-  return upb_strtable_iter_key(iter).data;
+bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) {
+  // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect
+  // this to be faster (especially for small numbers).
+  return upb_MiniTable_Enum_CheckValue(e->layout, num);
 }
 
-int32_t upb_enum_iter_number(upb_enum_iter *iter) {
-  return upb_value_getint32(upb_strtable_iter_value(iter));
+const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) {
+  UPB_ASSERT(0 <= i && i < e->value_count);
+  return &e->values[i];
 }
 
+/* upb_EnumValueDef ***********************************************************/
 
-/* upb_fielddef ***************************************************************/
+const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options(
+    const upb_EnumValueDef* e) {
+  return e->opts;
+}
 
-const char *upb_fielddef_fullname(const upb_fielddef *f) {
+bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e) {
+  return e->opts != (void*)opt_default;
+}
+
+const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* ev) {
+  return ev->parent;
+}
+
+const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* ev) {
+  return ev->full_name;
+}
+
+const char* upb_EnumValueDef_Name(const upb_EnumValueDef* ev) {
+  return shortdefname(ev->full_name);
+}
+
+int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* ev) {
+  return ev->number;
+}
+
+uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* ev) {
+  // Compute index in our parent's array.
+  return ev - ev->parent->values;
+}
+
+/* upb_ExtensionRange
+ * ***************************************************************/
+
+const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options(
+    const upb_ExtensionRange* r) {
+  return r->opts;
+}
+
+bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) {
+  return r->opts != (void*)opt_default;
+}
+
+int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* e) {
+  return e->start;
+}
+
+int32_t upb_ExtensionRange_End(const upb_ExtensionRange* e) { return e->end; }
+
+/* upb_FieldDef ***************************************************************/
+
+const google_protobuf_FieldOptions* upb_FieldDef_Options(
+    const upb_FieldDef* f) {
+  return f->opts;
+}
+
+bool upb_FieldDef_HasOptions(const upb_FieldDef* f) {
+  return f->opts != (void*)opt_default;
+}
+
+const char* upb_FieldDef_FullName(const upb_FieldDef* f) {
   return f->full_name;
 }
 
-upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+upb_CType upb_FieldDef_CType(const upb_FieldDef* f) {
   switch (f->type_) {
-    case UPB_DESCRIPTOR_TYPE_DOUBLE:
-      return UPB_TYPE_DOUBLE;
-    case UPB_DESCRIPTOR_TYPE_FLOAT:
-      return UPB_TYPE_FLOAT;
-    case UPB_DESCRIPTOR_TYPE_INT64:
-    case UPB_DESCRIPTOR_TYPE_SINT64:
-    case UPB_DESCRIPTOR_TYPE_SFIXED64:
-      return UPB_TYPE_INT64;
-    case UPB_DESCRIPTOR_TYPE_INT32:
-    case UPB_DESCRIPTOR_TYPE_SFIXED32:
-    case UPB_DESCRIPTOR_TYPE_SINT32:
-      return UPB_TYPE_INT32;
-    case UPB_DESCRIPTOR_TYPE_UINT64:
-    case UPB_DESCRIPTOR_TYPE_FIXED64:
-      return UPB_TYPE_UINT64;
-    case UPB_DESCRIPTOR_TYPE_UINT32:
-    case UPB_DESCRIPTOR_TYPE_FIXED32:
-      return UPB_TYPE_UINT32;
-    case UPB_DESCRIPTOR_TYPE_ENUM:
-      return UPB_TYPE_ENUM;
-    case UPB_DESCRIPTOR_TYPE_BOOL:
-      return UPB_TYPE_BOOL;
-    case UPB_DESCRIPTOR_TYPE_STRING:
-      return UPB_TYPE_STRING;
-    case UPB_DESCRIPTOR_TYPE_BYTES:
-      return UPB_TYPE_BYTES;
-    case UPB_DESCRIPTOR_TYPE_GROUP:
-    case UPB_DESCRIPTOR_TYPE_MESSAGE:
-      return UPB_TYPE_MESSAGE;
+    case kUpb_FieldType_Double:
+      return kUpb_CType_Double;
+    case kUpb_FieldType_Float:
+      return kUpb_CType_Float;
+    case kUpb_FieldType_Int64:
+    case kUpb_FieldType_SInt64:
+    case kUpb_FieldType_SFixed64:
+      return kUpb_CType_Int64;
+    case kUpb_FieldType_Int32:
+    case kUpb_FieldType_SFixed32:
+    case kUpb_FieldType_SInt32:
+      return kUpb_CType_Int32;
+    case kUpb_FieldType_UInt64:
+    case kUpb_FieldType_Fixed64:
+      return kUpb_CType_UInt64;
+    case kUpb_FieldType_UInt32:
+    case kUpb_FieldType_Fixed32:
+      return kUpb_CType_UInt32;
+    case kUpb_FieldType_Enum:
+      return kUpb_CType_Enum;
+    case kUpb_FieldType_Bool:
+      return kUpb_CType_Bool;
+    case kUpb_FieldType_String:
+      return kUpb_CType_String;
+    case kUpb_FieldType_Bytes:
+      return kUpb_CType_Bytes;
+    case kUpb_FieldType_Group:
+    case kUpb_FieldType_Message:
+      return kUpb_CType_Message;
   }
   UPB_UNREACHABLE();
 }
 
-upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
-  return f->type_;
-}
+upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; }
 
-uint32_t upb_fielddef_index(const upb_fielddef *f) {
-  return f->index_;
-}
+uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; }
 
-upb_label_t upb_fielddef_label(const upb_fielddef *f) {
-  return f->label_;
-}
+upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; }
 
-uint32_t upb_fielddef_number(const upb_fielddef *f) {
-  return f->number_;
-}
+uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; }
 
-bool upb_fielddef_isextension(const upb_fielddef *f) {
+bool upb_FieldDef_IsExtension(const upb_FieldDef* f) {
   return f->is_extension_;
 }
 
-bool upb_fielddef_lazy(const upb_fielddef *f) {
-  return f->lazy_;
-}
+bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { return f->packed_; }
 
-bool upb_fielddef_packed(const upb_fielddef *f) {
-  return f->packed_;
-}
-
-const char *upb_fielddef_name(const upb_fielddef *f) {
+const char* upb_FieldDef_Name(const upb_FieldDef* f) {
   return shortdefname(f->full_name);
 }
 
-const char *upb_fielddef_jsonname(const upb_fielddef *f) {
+const char* upb_FieldDef_JsonName(const upb_FieldDef* f) {
   return f->json_name;
 }
 
-const upb_filedef *upb_fielddef_file(const upb_fielddef *f) {
-  return f->file;
+bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) {
+  return f->has_json_name_;
 }
 
-const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; }
+
+const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) {
   return f->msgdef;
 }
 
-const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
-  return f->oneof;
+const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) {
+  return f->is_extension_ ? f->scope.extension_scope : NULL;
 }
 
-const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) {
-  if (!f->oneof || upb_oneofdef_issynthetic(f->oneof)) return NULL;
-  return f->oneof;
+const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) {
+  return f->is_extension_ ? NULL : f->scope.oneof;
 }
 
-upb_msgval upb_fielddef_default(const upb_fielddef *f) {
-  UPB_ASSERT(!upb_fielddef_issubmsg(f));
-  upb_msgval ret;
-  if (upb_fielddef_isstring(f)) {
-    str_t *str = f->defaultval.str;
-    if (str) {
-      ret.str_val.data = str->str;
-      ret.str_val.size = str->len;
-    } else {
-      ret.str_val.size = 0;
+const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) {
+  const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f);
+  if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL;
+  return oneof;
+}
+
+upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) {
+  UPB_ASSERT(!upb_FieldDef_IsSubMessage(f));
+  upb_MessageValue ret;
+
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Bool:
+      return (upb_MessageValue){.bool_val = f->defaultval.boolean};
+    case kUpb_CType_Int64:
+      return (upb_MessageValue){.int64_val = f->defaultval.sint};
+    case kUpb_CType_UInt64:
+      return (upb_MessageValue){.uint64_val = f->defaultval.uint};
+    case kUpb_CType_Enum:
+    case kUpb_CType_Int32:
+      return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint};
+    case kUpb_CType_UInt32:
+      return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint};
+    case kUpb_CType_Float:
+      return (upb_MessageValue){.float_val = f->defaultval.flt};
+    case kUpb_CType_Double:
+      return (upb_MessageValue){.double_val = f->defaultval.dbl};
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes: {
+      str_t* str = f->defaultval.str;
+      if (str) {
+        return (upb_MessageValue){
+            .str_val = (upb_StringView){.data = str->str, .size = str->len}};
+      } else {
+        return (upb_MessageValue){
+            .str_val = (upb_StringView){.data = NULL, .size = 0}};
+      }
     }
-  } else {
-    memcpy(&ret, &f->defaultval, 8);
+    default:
+      UPB_UNREACHABLE();
   }
+
   return ret;
 }
 
-static void chkdefaulttype(const upb_fielddef *f, int ctype) {
-  UPB_UNUSED(f);
-  UPB_UNUSED(ctype);
+const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_Message ? f->sub.msgdef : NULL;
 }
 
-int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_INT64);
-  return f->defaultval.sint;
+const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_Enum ? f->sub.enumdef : NULL;
 }
 
-int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_INT32);
-  return (int32_t)f->defaultval.sint;
-}
-
-uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_UINT64);
-  return f->defaultval.uint;
-}
-
-uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_UINT32);
-  return (uint32_t)f->defaultval.uint;
-}
-
-bool upb_fielddef_defaultbool(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_BOOL);
-  return f->defaultval.boolean;
-}
-
-float upb_fielddef_defaultfloat(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_FLOAT);
-  return f->defaultval.flt;
-}
-
-double upb_fielddef_defaultdouble(const upb_fielddef *f) {
-  chkdefaulttype(f, UPB_TYPE_DOUBLE);
-  return f->defaultval.dbl;
-}
-
-const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
-  str_t *str = f->defaultval.str;
-  UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING ||
-         upb_fielddef_type(f) == UPB_TYPE_BYTES ||
-         upb_fielddef_type(f) == UPB_TYPE_ENUM);
-  if (str) {
-    if (len) *len = str->len;
-    return str->str;
-  } else {
-    if (len) *len = 0;
-    return NULL;
-  }
-}
-
-const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
-  return upb_fielddef_type(f) == UPB_TYPE_MESSAGE ? f->sub.msgdef : NULL;
-}
-
-const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
-  return upb_fielddef_type(f) == UPB_TYPE_ENUM ? f->sub.enumdef : NULL;
-}
-
-const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) {
+const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f) {
+  UPB_ASSERT(!upb_FieldDef_IsExtension(f));
   return &f->msgdef->layout->fields[f->layout_index];
 }
 
-bool upb_fielddef_issubmsg(const upb_fielddef *f) {
-  return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable(
+    const upb_FieldDef* f) {
+  UPB_ASSERT(upb_FieldDef_IsExtension(f));
+  return f->file->ext_layouts[f->layout_index];
 }
 
-bool upb_fielddef_isstring(const upb_fielddef *f) {
-  return upb_fielddef_type(f) == UPB_TYPE_STRING ||
-         upb_fielddef_type(f) == UPB_TYPE_BYTES;
+bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) {
+  return f->proto3_optional_;
 }
 
-bool upb_fielddef_isseq(const upb_fielddef *f) {
-  return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_Message;
 }
 
-bool upb_fielddef_isprimitive(const upb_fielddef *f) {
-  return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+bool upb_FieldDef_IsString(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_String ||
+         upb_FieldDef_CType(f) == kUpb_CType_Bytes;
 }
 
-bool upb_fielddef_ismap(const upb_fielddef *f) {
-  return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
-         upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) {
+  return upb_FieldDef_Label(f) == kUpb_Label_Repeated;
 }
 
-bool upb_fielddef_hassubdef(const upb_fielddef *f) {
-  return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) {
+  return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f);
 }
 
-bool upb_fielddef_haspresence(const upb_fielddef *f) {
-  if (upb_fielddef_isseq(f)) return false;
-  return upb_fielddef_issubmsg(f) || upb_fielddef_containingoneof(f) ||
-         f->file->syntax == UPB_SYNTAX_PROTO2;
+bool upb_FieldDef_IsMap(const upb_FieldDef* f) {
+  return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) &&
+         upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f));
+}
+
+bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; }
+
+bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) {
+  return upb_FieldDef_IsSubMessage(f) ||
+         upb_FieldDef_CType(f) == kUpb_CType_Enum;
+}
+
+bool upb_FieldDef_HasPresence(const upb_FieldDef* f) {
+  if (upb_FieldDef_IsRepeated(f)) return false;
+  return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_ContainingOneof(f) ||
+         f->file->syntax == kUpb_Syntax_Proto2;
 }
 
 static bool between(int32_t x, int32_t low, int32_t high) {
   return x >= low && x <= high;
 }
 
-bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
-bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
-bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
 
-bool upb_fielddef_checkdescriptortype(int32_t type) {
+bool upb_FieldDef_checkdescriptortype(int32_t type) {
   return between(type, 1, 18);
 }
 
-/* upb_msgdef *****************************************************************/
+/* upb_MessageDef
+ * *****************************************************************/
 
-const char *upb_msgdef_fullname(const upb_msgdef *m) {
+const google_protobuf_MessageOptions* upb_MessageDef_Options(
+    const upb_MessageDef* m) {
+  return m->opts;
+}
+
+bool upb_MessageDef_HasOptions(const upb_MessageDef* m) {
+  return m->opts != (void*)opt_default;
+}
+
+const char* upb_MessageDef_FullName(const upb_MessageDef* m) {
   return m->full_name;
 }
 
-const upb_filedef *upb_msgdef_file(const upb_msgdef *m) {
+const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) {
   return m->file;
 }
 
-const char *upb_msgdef_name(const upb_msgdef *m) {
+const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) {
+  return m->containing_type;
+}
+
+const char* upb_MessageDef_Name(const upb_MessageDef* m) {
   return shortdefname(m->full_name);
 }
 
-upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) {
+upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m) {
   return m->file->syntax;
 }
 
-const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+const upb_FieldDef* upb_MessageDef_FindFieldByNumberWithSize(
+    const upb_MessageDef* m, uint32_t i) {
   upb_value val;
   return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val)
                                                 : NULL;
 }
 
-const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
-                                    size_t len) {
+const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len) {
   upb_value val;
 
   if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
@@ -4994,8 +5813,8 @@
   return unpack_def(val, UPB_DEFTYPE_FIELD);
 }
 
-const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
-                                    size_t len) {
+const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len) {
   upb_value val;
 
   if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
@@ -5005,23 +5824,27 @@
   return unpack_def(val, UPB_DEFTYPE_ONEOF);
 }
 
-bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
-                           const upb_fielddef **f, const upb_oneofdef **o) {
+bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m,
+                                       const char* name, size_t len,
+                                       const upb_FieldDef** out_f,
+                                       const upb_OneofDef** out_o) {
   upb_value val;
 
   if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
     return false;
   }
 
-  *o = unpack_def(val, UPB_DEFTYPE_ONEOF);
-  *f = unpack_def(val, UPB_DEFTYPE_FIELD);
-  return *o || *f;  /* False if this was a JSON name. */
+  const upb_FieldDef* f = unpack_def(val, UPB_DEFTYPE_FIELD);
+  const upb_OneofDef* o = unpack_def(val, UPB_DEFTYPE_ONEOF);
+  if (out_f) *out_f = f;
+  if (out_o) *out_o = o;
+  return f || o; /* False if this was a JSON name. */
 }
 
-const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m,
-                                              const char *name, size_t len) {
+const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len) {
   upb_value val;
-  const upb_fielddef* f;
+  const upb_FieldDef* f;
 
   if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
     return NULL;
@@ -5033,293 +5856,463 @@
   return f;
 }
 
-int upb_msgdef_numfields(const upb_msgdef *m) {
-  return m->field_count;
-}
+int upb_MessageDef_numfields(const upb_MessageDef* m) { return m->field_count; }
 
-int upb_msgdef_numoneofs(const upb_msgdef *m) {
-  return m->oneof_count;
-}
+int upb_MessageDef_numoneofs(const upb_MessageDef* m) { return m->oneof_count; }
 
-int upb_msgdef_numrealoneofs(const upb_msgdef *m) {
+int upb_MessageDef_numrealoneofs(const upb_MessageDef* m) {
   return m->real_oneof_count;
 }
 
-int upb_msgdef_fieldcount(const upb_msgdef *m) {
+int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) {
+  return m->ext_range_count;
+}
+
+int upb_MessageDef_FieldCount(const upb_MessageDef* m) {
   return m->field_count;
 }
 
-int upb_msgdef_oneofcount(const upb_msgdef *m) {
+int upb_MessageDef_OneofCount(const upb_MessageDef* m) {
   return m->oneof_count;
 }
 
-int upb_msgdef_realoneofcount(const upb_msgdef *m) {
+int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) {
+  return m->nested_msg_count;
+}
+
+int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) {
+  return m->nested_enum_count;
+}
+
+int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) {
+  return m->nested_ext_count;
+}
+
+int upb_MessageDef_realoneofcount(const upb_MessageDef* m) {
   return m->real_oneof_count;
 }
 
-const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) {
+const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) {
   return m->layout;
 }
 
-const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i) {
-  UPB_ASSERT(i >= 0 && i < m->field_count);
+const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m,
+                                                        int i) {
+  UPB_ASSERT(0 <= i && i < m->ext_range_count);
+  return &m->ext_ranges[i];
+}
+
+const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) {
+  UPB_ASSERT(0 <= i && i < m->field_count);
   return &m->fields[i];
 }
 
-const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i) {
-  UPB_ASSERT(i >= 0 && i < m->oneof_count);
+const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) {
+  UPB_ASSERT(0 <= i && i < m->oneof_count);
   return &m->oneofs[i];
 }
 
-bool upb_msgdef_mapentry(const upb_msgdef *m) {
-  return m->map_entry;
+const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m,
+                                                   int i) {
+  UPB_ASSERT(0 <= i && i < m->nested_msg_count);
+  return &m->nested_msgs[i];
 }
 
-upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m) {
+const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) {
+  UPB_ASSERT(0 <= i && i < m->nested_enum_count);
+  return &m->nested_enums[i];
+}
+
+const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m,
+                                                   int i) {
+  UPB_ASSERT(0 <= i && i < m->nested_ext_count);
+  return &m->nested_exts[i];
+}
+
+upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) {
   return m->well_known_type;
 }
 
-bool upb_msgdef_isnumberwrapper(const upb_msgdef *m) {
-  upb_wellknowntype_t type = upb_msgdef_wellknowntype(m);
-  return type >= UPB_WELLKNOWN_DOUBLEVALUE &&
-         type <= UPB_WELLKNOWN_UINT32VALUE;
+/* upb_OneofDef ***************************************************************/
+
+const google_protobuf_OneofOptions* upb_OneofDef_Options(
+    const upb_OneofDef* o) {
+  return o->opts;
 }
 
-bool upb_msgdef_iswrapper(const upb_msgdef *m) {
-  upb_wellknowntype_t type = upb_msgdef_wellknowntype(m);
-  return type >= UPB_WELLKNOWN_DOUBLEVALUE &&
-         type <= UPB_WELLKNOWN_BOOLVALUE;
+bool upb_OneofDef_HasOptions(const upb_OneofDef* o) {
+  return o->opts != (void*)opt_default;
 }
 
-void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
-  upb_inttable_begin(iter, &m->itof);
-}
-
-void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
-
-bool upb_msg_field_done(const upb_msg_field_iter *iter) {
-  return upb_inttable_done(iter);
-}
-
-upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
-  return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter));
-}
-
-void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
-  upb_inttable_iter_setdone(iter);
-}
-
-bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1,
-                                const upb_msg_field_iter * iter2) {
-  return upb_inttable_iter_isequal(iter1, iter2);
-}
-
-void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
-  upb_strtable_begin(iter, &m->ntof);
-  /* We need to skip past any initial fields. */
-  while (!upb_strtable_done(iter) &&
-         !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)) {
-    upb_strtable_next(iter);
-  }
-}
-
-void upb_msg_oneof_next(upb_msg_oneof_iter *iter) {
-  /* We need to skip past fields to return only oneofs. */
-  do {
-    upb_strtable_next(iter);
-  } while (!upb_strtable_done(iter) &&
-           !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF));
-}
-
-bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
-  return upb_strtable_done(iter);
-}
-
-const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
-  return unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF);
-}
-
-void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
-  upb_strtable_iter_setdone(iter);
-}
-
-bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1,
-                                const upb_msg_oneof_iter *iter2) {
-  return upb_strtable_iter_isequal(iter1, iter2);
-}
-
-/* upb_oneofdef ***************************************************************/
-
-const char *upb_oneofdef_name(const upb_oneofdef *o) {
+const char* upb_OneofDef_Name(const upb_OneofDef* o) {
   return shortdefname(o->full_name);
 }
 
-const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) {
   return o->parent;
 }
 
-int upb_oneofdef_fieldcount(const upb_oneofdef *o) {
-  return o->field_count;
-}
+int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; }
 
-const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i) {
+const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) {
   UPB_ASSERT(i < o->field_count);
   return o->fields[i];
 }
 
-int upb_oneofdef_numfields(const upb_oneofdef *o) {
-  return o->field_count;
-}
+int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; }
 
-uint32_t upb_oneofdef_index(const upb_oneofdef *o) {
+uint32_t upb_OneofDef_Index(const upb_OneofDef* o) {
+  // Compute index in our parent's array.
   return o - o->parent->oneofs;
 }
 
-bool upb_oneofdef_issynthetic(const upb_oneofdef *o) {
-  return o->synthetic;
-}
+bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; }
 
-const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
-                                      const char *name, size_t length) {
+const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o,
+                                                    const char* name,
+                                                    size_t length) {
   upb_value val;
-  return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
-      upb_value_getptr(val) : NULL;
+  return upb_strtable_lookup2(&o->ntof, name, length, &val)
+             ? upb_value_getptr(val)
+             : NULL;
 }
 
-const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o,
+                                              uint32_t num) {
   upb_value val;
   return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val)
                                                   : NULL;
 }
 
-void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
-  upb_inttable_begin(iter, &o->itof);
+/* upb_FileDef ****************************************************************/
+
+const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) {
+  return f->opts;
 }
 
-void upb_oneof_next(upb_oneof_iter *iter) {
-  upb_inttable_next(iter);
+bool upb_FileDef_HasOptions(const upb_FileDef* f) {
+  return f->opts != (void*)opt_default;
 }
 
-bool upb_oneof_done(upb_oneof_iter *iter) {
-  return upb_inttable_done(iter);
+const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; }
+
+const char* upb_FileDef_Package(const upb_FileDef* f) { return f->package; }
+
+upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; }
+
+int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) {
+  return f->top_lvl_msg_count;
 }
 
-upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
-  return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter));
+int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; }
+
+int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) {
+  return f->public_dep_count;
 }
 
-void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
-  upb_inttable_iter_setdone(iter);
+int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) {
+  return f->weak_dep_count;
 }
 
-/* upb_filedef ****************************************************************/
-
-const char *upb_filedef_name(const upb_filedef *f) {
-  return f->name;
+const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) {
+  return f->public_deps;
 }
 
-const char *upb_filedef_package(const upb_filedef *f) {
-  return f->package;
+const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) {
+  return f->weak_deps;
 }
 
-const char *upb_filedef_phpprefix(const upb_filedef *f) {
-  return f->phpprefix;
+int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) {
+  return f->top_lvl_enum_count;
 }
 
-const char *upb_filedef_phpnamespace(const upb_filedef *f) {
-  return f->phpnamespace;
+int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) {
+  return f->top_lvl_ext_count;
 }
 
-upb_syntax_t upb_filedef_syntax(const upb_filedef *f) {
-  return f->syntax;
+int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; }
+
+const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->dep_count);
+  return f->deps[i];
 }
 
-int upb_filedef_msgcount(const upb_filedef *f) {
-  return f->msg_count;
+const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->public_dep_count);
+  return f->deps[f->public_deps[i]];
 }
 
-int upb_filedef_depcount(const upb_filedef *f) {
-  return f->dep_count;
+const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->public_dep_count);
+  return f->deps[f->weak_deps[i]];
 }
 
-int upb_filedef_enumcount(const upb_filedef *f) {
-  return f->enum_count;
+const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count);
+  return &f->top_lvl_msgs[i];
 }
 
-const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i) {
-  return i < 0 || i >= f->dep_count ? NULL : f->deps[i];
+const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count);
+  return &f->top_lvl_enums[i];
 }
 
-const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i) {
-  return i < 0 || i >= f->msg_count ? NULL : &f->msgs[i];
+const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count);
+  return &f->top_lvl_exts[i];
 }
 
-const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i) {
-  return i < 0 || i >= f->enum_count ? NULL : &f->enums[i];
+const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) {
+  UPB_ASSERT(0 <= i && i < f->service_count);
+  return &f->services[i];
 }
 
-const upb_symtab *upb_filedef_symtab(const upb_filedef *f) {
-  return f->symtab;
+const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; }
+
+/* upb_MethodDef **************************************************************/
+
+const google_protobuf_MethodOptions* upb_MethodDef_Options(
+    const upb_MethodDef* m) {
+  return m->opts;
 }
 
-void upb_symtab_free(upb_symtab *s) {
-  upb_arena_free(s->arena);
+bool upb_MethodDef_HasOptions(const upb_MethodDef* m) {
+  return m->opts != (void*)opt_default;
+}
+
+const char* upb_MethodDef_FullName(const upb_MethodDef* m) {
+  return m->full_name;
+}
+
+const char* upb_MethodDef_Name(const upb_MethodDef* m) {
+  return shortdefname(m->full_name);
+}
+
+const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) {
+  return m->service;
+}
+
+const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) {
+  return m->input_type;
+}
+
+const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) {
+  return m->output_type;
+}
+
+bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) {
+  return m->client_streaming;
+}
+
+bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) {
+  return m->server_streaming;
+}
+
+/* upb_ServiceDef *************************************************************/
+
+const google_protobuf_ServiceOptions* upb_ServiceDef_Options(
+    const upb_ServiceDef* s) {
+  return s->opts;
+}
+
+bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) {
+  return s->opts != (void*)opt_default;
+}
+
+const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) {
+  return s->full_name;
+}
+
+const char* upb_ServiceDef_Name(const upb_ServiceDef* s) {
+  return shortdefname(s->full_name);
+}
+
+int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; }
+
+const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) {
+  return s->file;
+}
+
+int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) {
+  return s->method_count;
+}
+
+const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) {
+  return i < 0 || i >= s->method_count ? NULL : &s->methods[i];
+}
+
+const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s,
+                                                     const char* name) {
+  for (int i = 0; i < s->method_count; i++) {
+    if (strcmp(name, upb_MethodDef_Name(&s->methods[i])) == 0) {
+      return &s->methods[i];
+    }
+  }
+  return NULL;
+}
+
+/* upb_DefPool ****************************************************************/
+
+void upb_DefPool_Free(upb_DefPool* s) {
+  upb_Arena_Free(s->arena);
   upb_gfree(s);
 }
 
-upb_symtab *upb_symtab_new(void) {
-  upb_symtab *s = upb_gmalloc(sizeof(*s));
+upb_DefPool* upb_DefPool_New(void) {
+  upb_DefPool* s = upb_gmalloc(sizeof(*s));
 
   if (!s) {
     return NULL;
   }
 
-  s->arena = upb_arena_new();
+  s->arena = upb_Arena_New();
   s->bytes_loaded = 0;
 
   if (!upb_strtable_init(&s->syms, 32, s->arena) ||
-      !upb_strtable_init(&s->files, 4, s->arena)) {
-    upb_arena_free(s->arena);
-    upb_gfree(s);
-    s = NULL;
+      !upb_strtable_init(&s->files, 4, s->arena) ||
+      !upb_inttable_init(&s->exts, s->arena)) {
+    goto err;
   }
+
+  s->extreg = upb_ExtensionRegistry_New(s->arena);
+  if (!s->extreg) goto err;
   return s;
+
+err:
+  upb_Arena_Free(s->arena);
+  upb_gfree(s);
+  return NULL;
 }
 
-const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+static const void* symtab_lookup(const upb_DefPool* s, const char* sym,
+                                 upb_deftype_t type) {
   upb_value v;
-  return upb_strtable_lookup(&s->syms, sym, &v) ?
-      unpack_def(v, UPB_DEFTYPE_MSG) : NULL;
+  return upb_strtable_lookup(&s->syms, sym, &v) ? unpack_def(v, type) : NULL;
 }
 
-const upb_msgdef *upb_symtab_lookupmsg2(const upb_symtab *s, const char *sym,
-                                        size_t len) {
+static const void* symtab_lookup2(const upb_DefPool* s, const char* sym,
+                                  size_t size, upb_deftype_t type) {
   upb_value v;
-  return upb_strtable_lookup2(&s->syms, sym, len, &v) ?
-      unpack_def(v, UPB_DEFTYPE_MSG) : NULL;
+  return upb_strtable_lookup2(&s->syms, sym, size, &v) ? unpack_def(v, type)
+                                                       : NULL;
 }
 
-const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s,
+                                                    const char* sym) {
+  return symtab_lookup(s, sym, UPB_DEFTYPE_MSG);
+}
+
+const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize(
+    const upb_DefPool* s, const char* sym, size_t len) {
+  return symtab_lookup2(s, sym, len, UPB_DEFTYPE_MSG);
+}
+
+const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s,
+                                              const char* sym) {
+  return symtab_lookup(s, sym, UPB_DEFTYPE_ENUM);
+}
+
+const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s,
+                                                      const char* sym) {
+  return symtab_lookup(s, sym, UPB_DEFTYPE_ENUMVAL);
+}
+
+const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s,
+                                              const char* name) {
   upb_value v;
-  return upb_strtable_lookup(&s->syms, sym, &v) ?
-      unpack_def(v, UPB_DEFTYPE_ENUM) : NULL;
+  return upb_strtable_lookup(&s->files, name, &v)
+             ? unpack_def(v, UPB_DEFTYPE_FILE)
+             : NULL;
 }
 
-const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) {
+const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s,
+                                                      const char* name,
+                                                      size_t len) {
   upb_value v;
-  return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v)
-                                                  : NULL;
+  return upb_strtable_lookup2(&s->files, name, len, &v)
+             ? unpack_def(v, UPB_DEFTYPE_FILE)
+             : NULL;
 }
 
-const upb_filedef *upb_symtab_lookupfile2(
-    const upb_symtab *s, const char *name, size_t len) {
+const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize(
+    const upb_DefPool* s, const char* name, size_t size) {
   upb_value v;
-  return upb_strtable_lookup2(&s->files, name, len, &v) ?
-      upb_value_getconstptr(v) : NULL;
+  if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL;
+
+  switch (deftype(v)) {
+    case UPB_DEFTYPE_FIELD:
+      return unpack_def(v, UPB_DEFTYPE_FIELD);
+    case UPB_DEFTYPE_MSG: {
+      const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG);
+      return m->in_message_set ? &m->nested_exts[0] : NULL;
+    }
+    default:
+      break;
+  }
+
+  return NULL;
 }
 
-int upb_symtab_filecount(const upb_symtab *s) {
-  return (int)upb_strtable_count(&s->files);
+const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s,
+                                                    const char* sym) {
+  return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym));
+}
+
+const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s,
+                                                    const char* name) {
+  return symtab_lookup(s, name, UPB_DEFTYPE_SERVICE);
+}
+
+const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize(
+    const upb_DefPool* s, const char* name, size_t size) {
+  return symtab_lookup2(s, name, size, UPB_DEFTYPE_SERVICE);
+}
+
+const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s,
+                                                        const char* name) {
+  upb_value v;
+  // TODO(haberman): non-extension fields and oneofs.
+  if (upb_strtable_lookup(&s->syms, name, &v)) {
+    switch (deftype(v)) {
+      case UPB_DEFTYPE_EXT: {
+        const upb_FieldDef* f = unpack_def(v, UPB_DEFTYPE_EXT);
+        return upb_FieldDef_File(f);
+      }
+      case UPB_DEFTYPE_MSG: {
+        const upb_MessageDef* m = unpack_def(v, UPB_DEFTYPE_MSG);
+        return upb_MessageDef_File(m);
+      }
+      case UPB_DEFTYPE_ENUM: {
+        const upb_EnumDef* e = unpack_def(v, UPB_DEFTYPE_ENUM);
+        return upb_EnumDef_File(e);
+      }
+      case UPB_DEFTYPE_ENUMVAL: {
+        const upb_EnumValueDef* ev = unpack_def(v, UPB_DEFTYPE_ENUMVAL);
+        return upb_EnumDef_File(upb_EnumValueDef_Enum(ev));
+      }
+      case UPB_DEFTYPE_SERVICE: {
+        const upb_ServiceDef* service = unpack_def(v, UPB_DEFTYPE_SERVICE);
+        return upb_ServiceDef_File(service);
+      }
+      default:
+        UPB_UNREACHABLE();
+    }
+  }
+
+  const char* last_dot = strrchr(name, '.');
+  if (last_dot) {
+    const upb_MessageDef* parent =
+        upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name);
+    if (parent) {
+      const char* shortname = last_dot + 1;
+      if (upb_MessageDef_FindByNameWithSize(parent, shortname,
+                                            strlen(shortname), NULL, NULL)) {
+        return upb_MessageDef_File(parent);
+      }
+    }
+  }
+
+  return NULL;
 }
 
 /* Code to build defs from descriptor protos. *********************************/
@@ -5329,40 +6322,61 @@
  * this code is used to directly build defs from Ruby (for example) we do need
  * to validate important constraints like uniqueness of names and numbers. */
 
-#define CHK_OOM(x) if (!(x)) { symtab_oomerr(ctx); }
+#define CHK_OOM(x)      \
+  if (!(x)) {           \
+    symtab_oomerr(ctx); \
+  }
 
 typedef struct {
-  upb_symtab *symtab;
-  upb_filedef *file;              /* File we are building. */
-  upb_arena *arena;               /* Allocate defs here. */
-  const upb_msglayout **layouts;  /* NULL if we should build layouts. */
-  upb_status *status;             /* Record errors here. */
-  jmp_buf err;                    /* longjmp() on error. */
+  upb_DefPool* symtab;
+  upb_FileDef* file;                /* File we are building. */
+  upb_Arena* arena;                 /* Allocate defs here. */
+  upb_Arena* tmp_arena;             /* For temporary allocations. */
+  const upb_MiniTable_File* layout; /* NULL if we should build layouts. */
+  int enum_count;                   /* Count of enums built so far. */
+  int msg_count;                    /* Count of messages built so far. */
+  int ext_count;                    /* Count of extensions built so far. */
+  upb_Status* status;               /* Record errors here. */
+  jmp_buf err;                      /* longjmp() on error. */
 } symtab_addctx;
 
-UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3)
-static void symtab_errf(symtab_addctx *ctx, const char *fmt, ...) {
+UPB_NORETURN UPB_NOINLINE UPB_PRINTF(2, 3) static void symtab_errf(
+    symtab_addctx* ctx, const char* fmt, ...) {
   va_list argp;
   va_start(argp, fmt);
-  upb_status_vseterrf(ctx->status, fmt, argp);
+  upb_Status_VSetErrorFormat(ctx->status, fmt, argp);
   va_end(argp);
   UPB_LONGJMP(ctx->err, 1);
 }
 
-UPB_NORETURN UPB_NOINLINE
-static void symtab_oomerr(symtab_addctx *ctx) {
-  upb_status_setoom(ctx->status);
+UPB_NORETURN UPB_NOINLINE static void symtab_oomerr(symtab_addctx* ctx) {
+  upb_Status_setoom(ctx->status);
   UPB_LONGJMP(ctx->err, 1);
 }
 
-void *symtab_alloc(symtab_addctx *ctx, size_t bytes) {
-  void *ret = upb_arena_malloc(ctx->arena, bytes);
+void* symtab_alloc(symtab_addctx* ctx, size_t bytes) {
+  if (bytes == 0) return NULL;
+  void* ret = upb_Arena_Malloc(ctx->arena, bytes);
   if (!ret) symtab_oomerr(ctx);
   return ret;
 }
 
-static void check_ident(symtab_addctx *ctx, upb_strview name, bool full) {
-  const char *str = name.data;
+// We want to copy the options verbatim into the destination options proto.
+// We use serialize+parse as our deep copy.
+#define SET_OPTIONS(target, desc_type, options_type, proto)                   \
+  if (google_protobuf_##desc_type##_has_options(proto)) {                     \
+    size_t size;                                                              \
+    char* pb = google_protobuf_##options_type##_serialize(                    \
+        google_protobuf_##desc_type##_options(proto), ctx->tmp_arena, &size); \
+    CHK_OOM(pb);                                                              \
+    target = google_protobuf_##options_type##_parse(pb, size, ctx->arena);    \
+    CHK_OOM(target);                                                          \
+  } else {                                                                    \
+    target = (const google_protobuf_##options_type*)opt_default;              \
+  }
+
+static void check_ident(symtab_addctx* ctx, upb_StringView name, bool full) {
+  const char* str = name.data;
   size_t len = name.size;
   bool start = true;
   size_t i;
@@ -5393,158 +6407,223 @@
   }
 }
 
-static size_t div_round_up(size_t n, size_t d) {
-  return (n + d - 1) / d;
-}
+static size_t div_round_up(size_t n, size_t d) { return (n + d - 1) / d; }
 
-static size_t upb_msgval_sizeof(upb_fieldtype_t type) {
+static size_t upb_MessageValue_sizeof(upb_CType type) {
   switch (type) {
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_Double:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt64:
       return 8;
-    case UPB_TYPE_ENUM:
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_FLOAT:
+    case kUpb_CType_Enum:
+    case kUpb_CType_Int32:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_Float:
       return 4;
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       return 1;
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       return sizeof(void*);
-    case UPB_TYPE_BYTES:
-    case UPB_TYPE_STRING:
-      return sizeof(upb_strview);
+    case kUpb_CType_Bytes:
+    case kUpb_CType_String:
+      return sizeof(upb_StringView);
   }
   UPB_UNREACHABLE();
 }
 
-static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) {
-  if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) {
-    upb_map_entry ent;
+static uint8_t upb_msg_fielddefsize(const upb_FieldDef* f) {
+  if (upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f))) {
+    upb_MapEntry ent;
     UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v));
     return sizeof(ent.k);
-  } else if (upb_fielddef_isseq(f)) {
+  } else if (upb_FieldDef_IsRepeated(f)) {
     return sizeof(void*);
   } else {
-    return upb_msgval_sizeof(upb_fielddef_type(f));
+    return upb_MessageValue_sizeof(upb_FieldDef_CType(f));
   }
 }
 
-static uint32_t upb_msglayout_place(upb_msglayout *l, size_t size) {
-  uint32_t ret;
+static uint32_t upb_MiniTable_place(symtab_addctx* ctx, upb_MiniTable* l,
+                                    size_t size, const upb_MessageDef* m) {
+  size_t ofs = UPB_ALIGN_UP(l->size, size);
+  size_t next = ofs + size;
 
-  l->size = UPB_ALIGN_UP(l->size, size);
-  ret = l->size;
-  l->size += size;
-  return ret;
+  if (next > UINT16_MAX) {
+    symtab_errf(ctx, "size of message %s exceeded max size of %zu bytes",
+                upb_MessageDef_FullName(m), (size_t)UINT16_MAX);
+  }
+
+  l->size = next;
+  return ofs;
 }
 
-static int field_number_cmp(const void *p1, const void *p2) {
-  const upb_msglayout_field *f1 = p1;
-  const upb_msglayout_field *f2 = p2;
+static int field_number_cmp(const void* p1, const void* p2) {
+  const upb_MiniTable_Field* f1 = p1;
+  const upb_MiniTable_Field* f2 = p2;
   return f1->number - f2->number;
 }
 
-static void assign_layout_indices(const upb_msgdef *m, upb_msglayout *l,
-                                  upb_msglayout_field *fields) {
+static void assign_layout_indices(const upb_MessageDef* m, upb_MiniTable* l,
+                                  upb_MiniTable_Field* fields) {
   int i;
-  int n = upb_msgdef_numfields(m);
+  int n = upb_MessageDef_numfields(m);
   int dense_below = 0;
   for (i = 0; i < n; i++) {
-    upb_fielddef *f = (upb_fielddef*)upb_msgdef_itof(m, fields[i].number);
+    upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_FindFieldByNumberWithSize(
+        m, fields[i].number);
     UPB_ASSERT(f);
     f->layout_index = i;
     if (i < UINT8_MAX && fields[i].number == i + 1 &&
-        (i == 0 || fields[i-1].number == i)) {
+        (i == 0 || fields[i - 1].number == i)) {
       dense_below = i + 1;
     }
   }
   l->dense_below = dense_below;
 }
 
-static void fill_fieldlayout(upb_msglayout_field *field, const upb_fielddef *f) {
-  field->number = upb_fielddef_number(f);
-  field->descriptortype = upb_fielddef_descriptortype(f);
-
-  if (field->descriptortype == UPB_DTYPE_STRING &&
-      f->file->syntax == UPB_SYNTAX_PROTO2) {
-    /* See TableDescriptorType() in upbc/generator.cc for details and
-     * rationale. */
-    field->descriptortype = UPB_DTYPE_BYTES;
+static uint8_t map_descriptortype(const upb_FieldDef* f) {
+  uint8_t type = upb_FieldDef_Type(f);
+  /* See TableDescriptorType() in upbc/generator.cc for details and
+   * rationale of these exceptions. */
+  if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) {
+    return kUpb_FieldType_Bytes;
+  } else if (type == kUpb_FieldType_Enum &&
+             f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3) {
+    return kUpb_FieldType_Int32;
   }
+  return type;
+}
 
-  if (upb_fielddef_ismap(f)) {
-    field->mode = _UPB_MODE_MAP;
-  } else if (upb_fielddef_isseq(f)) {
-    field->mode = _UPB_MODE_ARRAY;
+static bool IsProto2Enum(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_Enum &&
+         f->sub.enumdef->file->syntax == kUpb_Syntax_Proto2;
+}
+
+static void fill_fieldlayout(upb_MiniTable_Field* field,
+                             const upb_FieldDef* f) {
+  field->number = upb_FieldDef_Number(f);
+  field->descriptortype = map_descriptortype(f);
+
+  if (upb_FieldDef_IsMap(f)) {
+    field->mode =
+        kUpb_FieldMode_Map | (upb_FieldRep_Pointer << upb_FieldRep_Shift);
+  } else if (upb_FieldDef_IsRepeated(f)) {
+    field->mode =
+        kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift);
   } else {
-    field->mode = _UPB_MODE_SCALAR;
+    /* Maps descriptor type -> elem_size_lg2.  */
+    static const uint8_t sizes[] = {
+        -1,                      /* invalid descriptor type */
+        upb_FieldRep_8Byte,      /* DOUBLE */
+        upb_FieldRep_4Byte,      /* FLOAT */
+        upb_FieldRep_8Byte,      /* INT64 */
+        upb_FieldRep_8Byte,      /* UINT64 */
+        upb_FieldRep_4Byte,      /* INT32 */
+        upb_FieldRep_8Byte,      /* FIXED64 */
+        upb_FieldRep_4Byte,      /* FIXED32 */
+        upb_FieldRep_1Byte,      /* BOOL */
+        upb_FieldRep_StringView, /* STRING */
+        upb_FieldRep_Pointer,    /* GROUP */
+        upb_FieldRep_Pointer,    /* MESSAGE */
+        upb_FieldRep_StringView, /* BYTES */
+        upb_FieldRep_4Byte,      /* UINT32 */
+        upb_FieldRep_4Byte,      /* ENUM */
+        upb_FieldRep_4Byte,      /* SFIXED32 */
+        upb_FieldRep_8Byte,      /* SFIXED64 */
+        upb_FieldRep_4Byte,      /* SINT32 */
+        upb_FieldRep_8Byte,      /* SINT64 */
+    };
+    field->mode = kUpb_FieldMode_Scalar |
+                  (sizes[field->descriptortype] << upb_FieldRep_Shift);
   }
 
-  if (upb_fielddef_packed(f)) {
-    field->mode |= _UPB_MODE_IS_PACKED;
+  if (upb_FieldDef_IsPacked(f)) {
+    field->mode |= upb_LabelFlags_IsPacked;
+  }
+
+  if (upb_FieldDef_IsExtension(f)) {
+    field->mode |= upb_LabelFlags_IsExtension;
   }
 }
 
 /* This function is the dynamic equivalent of message_layout.{cc,h} in upbc.
  * It computes a dynamic layout for all of the fields in |m|. */
-static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) {
-  upb_msglayout *l = (upb_msglayout*)m->layout;
-  upb_msg_field_iter it;
-  upb_msg_oneof_iter oit;
-  size_t hasbit;
-  size_t field_count = upb_msgdef_numfields(m);
-  size_t submsg_count = 0;
-  const upb_msglayout **submsgs;
-  upb_msglayout_field *fields;
+static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) {
+  upb_MiniTable* l = (upb_MiniTable*)m->layout;
+  size_t field_count = upb_MessageDef_numfields(m);
+  size_t sublayout_count = 0;
+  upb_MiniTable_Sub* subs;
+  upb_MiniTable_Field* fields;
 
-  memset(l, 0, sizeof(*l) + sizeof(_upb_fasttable_entry));
+  memset(l, 0, sizeof(*l) + sizeof(_upb_FastTable_Entry));
 
   /* Count sub-messages. */
   for (size_t i = 0; i < field_count; i++) {
-    if (upb_fielddef_issubmsg(&m->fields[i])) {
-      submsg_count++;
+    const upb_FieldDef* f = &m->fields[i];
+    if (upb_FieldDef_IsSubMessage(f)) {
+      sublayout_count++;
+    } else if (IsProto2Enum(f)) {
+      sublayout_count++;
     }
   }
 
   fields = symtab_alloc(ctx, field_count * sizeof(*fields));
-  submsgs = symtab_alloc(ctx, submsg_count * sizeof(*submsgs));
+  subs = symtab_alloc(ctx, sublayout_count * sizeof(*subs));
 
-  l->field_count = upb_msgdef_numfields(m);
+  l->field_count = upb_MessageDef_numfields(m);
   l->fields = fields;
-  l->submsgs = submsgs;
+  l->subs = subs;
   l->table_mask = 0;
+  l->required_count = 0;
+
+  if (upb_MessageDef_ExtensionRangeCount(m) > 0) {
+    if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) {
+      l->ext = upb_ExtMode_IsMessageSet;
+    } else {
+      l->ext = upb_ExtMode_Extendable;
+    }
+  } else {
+    l->ext = upb_ExtMode_NonExtendable;
+  }
 
   /* TODO(haberman): initialize fast tables so that reflection-based parsing
    * can get the same speeds as linked-in types. */
   l->fasttable[0].field_parser = &fastdecode_generic;
   l->fasttable[0].field_data = 0;
 
-  if (upb_msgdef_mapentry(m)) {
+  if (upb_MessageDef_IsMapEntry(m)) {
     /* TODO(haberman): refactor this method so this special case is more
      * elegant. */
-    const upb_fielddef *key = upb_msgdef_itof(m, 1);
-    const upb_fielddef *val = upb_msgdef_itof(m, 2);
+    const upb_FieldDef* key = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+    const upb_FieldDef* val = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
     fields[0].number = 1;
     fields[1].number = 2;
-    fields[0].mode = _UPB_MODE_SCALAR;
-    fields[1].mode = _UPB_MODE_SCALAR;
+    fields[0].mode = kUpb_FieldMode_Scalar;
+    fields[1].mode = kUpb_FieldMode_Scalar;
     fields[0].presence = 0;
     fields[1].presence = 0;
-    fields[0].descriptortype = upb_fielddef_descriptortype(key);
-    fields[1].descriptortype = upb_fielddef_descriptortype(val);
+    fields[0].descriptortype = map_descriptortype(key);
+    fields[1].descriptortype = map_descriptortype(val);
     fields[0].offset = 0;
-    fields[1].offset = sizeof(upb_strview);
+    fields[1].offset = sizeof(upb_StringView);
     fields[1].submsg_index = 0;
 
-    if (upb_fielddef_type(val) == UPB_TYPE_MESSAGE) {
-      submsgs[0] = upb_fielddef_msgsubdef(val)->layout;
+    if (upb_FieldDef_CType(val) == kUpb_CType_Message) {
+      subs[0].submsg = upb_FieldDef_MessageSubDef(val)->layout;
+    } else if (IsProto2Enum(val)) {
+      subs[0].subenum = upb_FieldDef_EnumSubDef(val)->layout;
     }
 
+    upb_FieldDef* fielddefs = (upb_FieldDef*)&m->fields[0];
+    UPB_ASSERT(fielddefs[0].number_ == 1);
+    UPB_ASSERT(fielddefs[1].number_ == 2);
+    fielddefs[0].layout_index = 0;
+    fielddefs[1].layout_index = 1;
+
     l->field_count = 2;
-    l->size = 2 * sizeof(upb_strview);
+    l->size = 2 * sizeof(upb_StringView);
     l->size = UPB_ALIGN_UP(l->size, 8);
+    l->dense_below = 2;
     return;
   }
 
@@ -5557,23 +6636,44 @@
    * OPT: There is a lot of room for optimization here to minimize the size.
    */
 
+  /* Assign hasbits for required fields first. */
+  size_t hasbit = 0;
+
+  for (int i = 0; i < m->field_count; i++) {
+    const upb_FieldDef* f = &m->fields[i];
+    upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)];
+    if (upb_FieldDef_Label(f) == kUpb_Label_Required) {
+      field->presence = ++hasbit;
+      if (hasbit >= 63) {
+        symtab_errf(ctx, "Message with >=63 required fields: %s",
+                    upb_MessageDef_FullName(m));
+      }
+      l->required_count++;
+    }
+  }
+
   /* Allocate hasbits and set basic field attributes. */
-  submsg_count = 0;
-  for (upb_msg_field_begin(&it, m), hasbit = 0;
-       !upb_msg_field_done(&it);
-       upb_msg_field_next(&it)) {
-    upb_fielddef* f = upb_msg_iter_field(&it);
-    upb_msglayout_field *field = &fields[upb_fielddef_index(f)];
+  sublayout_count = 0;
+  for (int i = 0; i < m->field_count; i++) {
+    const upb_FieldDef* f = &m->fields[i];
+    upb_MiniTable_Field* field = &fields[upb_FieldDef_Index(f)];
 
     fill_fieldlayout(field, f);
 
-    if (upb_fielddef_issubmsg(f)) {
-      const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
-      field->submsg_index = submsg_count++;
-      submsgs[field->submsg_index] = subm->layout;
+    if (upb_FieldDef_IsSubMessage(f)) {
+      field->submsg_index = sublayout_count++;
+      subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout;
+    } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum &&
+               f->file->syntax == kUpb_Syntax_Proto2) {
+      field->submsg_index = sublayout_count++;
+      subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout;
+      UPB_ASSERT(subs[field->submsg_index].subenum);
     }
 
-    if (upb_fielddef_haspresence(f) && !upb_fielddef_realcontainingoneof(f)) {
+    if (upb_FieldDef_Label(f) == kUpb_Label_Required) {
+      /* Hasbit was already assigned. */
+    } else if (upb_FieldDef_HasPresence(f) &&
+               !upb_FieldDef_RealContainingOneof(f)) {
       /* We don't use hasbit 0, so that 0 can indicate "no presence" in the
        * table. This wastes one hasbit, but we don't worry about it for now. */
       field->presence = ++hasbit;
@@ -5583,55 +6683,47 @@
   }
 
   /* Account for space used by hasbits. */
-  l->size = div_round_up(hasbit, 8);
+  l->size = div_round_up(hasbit + 1, 8);
 
   /* Allocate non-oneof fields. */
-  for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
-       upb_msg_field_next(&it)) {
-    const upb_fielddef* f = upb_msg_iter_field(&it);
+  for (int i = 0; i < m->field_count; i++) {
+    const upb_FieldDef* f = &m->fields[i];
     size_t field_size = upb_msg_fielddefsize(f);
-    size_t index = upb_fielddef_index(f);
+    size_t index = upb_FieldDef_Index(f);
 
-    if (upb_fielddef_realcontainingoneof(f)) {
+    if (upb_FieldDef_RealContainingOneof(f)) {
       /* Oneofs are handled separately below. */
       continue;
     }
 
-    fields[index].offset = upb_msglayout_place(l, field_size);
+    fields[index].offset = upb_MiniTable_place(ctx, l, field_size, m);
   }
 
   /* Allocate oneof fields.  Each oneof field consists of a uint32 for the case
    * and space for the actual data. */
-  for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit);
-       upb_msg_oneof_next(&oit)) {
-    const upb_oneofdef* o = upb_msg_iter_oneof(&oit);
-    upb_oneof_iter fit;
-
-    size_t case_size = sizeof(uint32_t);  /* Could potentially optimize this. */
+  for (int i = 0; i < m->oneof_count; i++) {
+    const upb_OneofDef* o = &m->oneofs[i];
+    size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */
     size_t field_size = 0;
     uint32_t case_offset;
     uint32_t data_offset;
 
-    if (upb_oneofdef_issynthetic(o)) continue;
+    if (upb_OneofDef_IsSynthetic(o)) continue;
 
     /* Calculate field size: the max of all field sizes. */
-    for (upb_oneof_begin(&fit, o);
-         !upb_oneof_done(&fit);
-         upb_oneof_next(&fit)) {
-      const upb_fielddef* f = upb_oneof_iter_field(&fit);
+    for (int j = 0; j < o->field_count; j++) {
+      const upb_FieldDef* f = o->fields[j];
       field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f));
     }
 
     /* Align and allocate case offset. */
-    case_offset = upb_msglayout_place(l, case_size);
-    data_offset = upb_msglayout_place(l, field_size);
+    case_offset = upb_MiniTable_place(ctx, l, case_size, m);
+    data_offset = upb_MiniTable_place(ctx, l, field_size, m);
 
-    for (upb_oneof_begin(&fit, o);
-         !upb_oneof_done(&fit);
-         upb_oneof_next(&fit)) {
-      const upb_fielddef* f = upb_oneof_iter_field(&fit);
-      fields[upb_fielddef_index(f)].offset = data_offset;
-      fields[upb_fielddef_index(f)].presence = ~case_offset;
+    for (int i = 0; i < o->field_count; i++) {
+      const upb_FieldDef* f = o->fields[i];
+      fields[upb_FieldDef_Index(f)].offset = data_offset;
+      fields[upb_FieldDef_Index(f)].presence = ~case_offset;
     }
   }
 
@@ -5640,28 +6732,30 @@
   l->size = UPB_ALIGN_UP(l->size, 8);
 
   /* Sort fields by number. */
-  qsort(fields, upb_msgdef_numfields(m), sizeof(*fields), field_number_cmp);
+  qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), field_number_cmp);
   assign_layout_indices(m, l, fields);
 }
 
-static char *strviewdup(symtab_addctx *ctx, upb_strview view) {
-  return upb_strdup2(view.data, view.size, ctx->arena);
+static char* strviewdup(symtab_addctx* ctx, upb_StringView view) {
+  char* ret = upb_strdup2(view.data, view.size, ctx->arena);
+  CHK_OOM(ret);
+  return ret;
 }
 
-static bool streql2(const char *a, size_t n, const char *b) {
+static bool streql2(const char* a, size_t n, const char* b) {
   return n == strlen(b) && memcmp(a, b, n) == 0;
 }
 
-static bool streql_view(upb_strview view, const char *b) {
+static bool streql_view(upb_StringView view, const char* b) {
   return streql2(view.data, view.size, b);
 }
 
-static const char *makefullname(symtab_addctx *ctx, const char *prefix,
-                                upb_strview name) {
+static const char* makefullname(symtab_addctx* ctx, const char* prefix,
+                                upb_StringView name) {
   if (prefix) {
     /* ret = prefix + '.' + name; */
     size_t n = strlen(prefix);
-    char *ret = symtab_alloc(ctx, n + name.size + 2);
+    char* ret = symtab_alloc(ctx, n + name.size + 2);
     strcpy(ret, prefix);
     ret[n] = '.';
     memcpy(&ret[n + 1], name.data, name.size);
@@ -5672,33 +6766,33 @@
   }
 }
 
-static void finalize_oneofs(symtab_addctx *ctx, upb_msgdef *m) {
+static void finalize_oneofs(symtab_addctx* ctx, upb_MessageDef* m) {
   int i;
   int synthetic_count = 0;
-  upb_oneofdef *mutable_oneofs = (upb_oneofdef*)m->oneofs;
+  upb_OneofDef* mutable_oneofs = (upb_OneofDef*)m->oneofs;
 
   for (i = 0; i < m->oneof_count; i++) {
-    upb_oneofdef *o = &mutable_oneofs[i];
+    upb_OneofDef* o = &mutable_oneofs[i];
 
     if (o->synthetic && o->field_count != 1) {
       symtab_errf(ctx, "Synthetic oneofs must have one field, not %d: %s",
-                  o->field_count, upb_oneofdef_name(o));
+                  o->field_count, upb_OneofDef_Name(o));
     }
 
     if (o->synthetic) {
       synthetic_count++;
     } else if (synthetic_count != 0) {
       symtab_errf(ctx, "Synthetic oneofs must be after all other oneofs: %s",
-                  upb_oneofdef_name(o));
+                  upb_OneofDef_Name(o));
     }
 
-    o->fields = symtab_alloc(ctx, sizeof(upb_fielddef *) * o->field_count);
+    o->fields = symtab_alloc(ctx, sizeof(upb_FieldDef*) * o->field_count);
     o->field_count = 0;
   }
 
   for (i = 0; i < m->field_count; i++) {
-    const upb_fielddef *f = &m->fields[i];
-    upb_oneofdef *o = (upb_oneofdef*)f->oneof;
+    const upb_FieldDef* f = &m->fields[i];
+    upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f);
     if (o) {
       o->fields[o->field_count++] = f;
     }
@@ -5707,14 +6801,16 @@
   m->real_oneof_count = m->oneof_count - synthetic_count;
 }
 
-size_t getjsonname(const char *name, char *buf, size_t len) {
+size_t getjsonname(const char* name, char* buf, size_t len) {
   size_t src, dst = 0;
   bool ucase_next = false;
 
-#define WRITE(byte) \
-  ++dst; \
-  if (dst < len) buf[dst - 1] = byte; \
-  else if (dst == len) buf[dst - 1] = '\0'
+#define WRITE(byte)      \
+  ++dst;                 \
+  if (dst < len)         \
+    buf[dst - 1] = byte; \
+  else if (dst == len)   \
+  buf[dst - 1] = '\0'
 
   if (!name) {
     WRITE('\0');
@@ -5745,14 +6841,19 @@
 #undef WRITE
 }
 
-static char* makejsonname(symtab_addctx *ctx, const char* name) {
+static char* makejsonname(symtab_addctx* ctx, const char* name) {
   size_t size = getjsonname(name, NULL, 0);
   char* json_name = symtab_alloc(ctx, size);
   getjsonname(name, json_name, size);
   return json_name;
 }
 
-static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) {
+/* Adds a symbol |v| to the symtab, which must be a def pointer previously
+ * packed with pack_def().  The def's pointer to upb_FileDef* must be set before
+ * adding, so we know which entries to remove if building this file fails. */
+static void symtab_add(symtab_addctx* ctx, const char* name, upb_value v) {
+  // TODO: table should support an operation "tryinsert" to avoid the double
+  // lookup.
   if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) {
     symtab_errf(ctx, "duplicate symbol '%s'", name);
   }
@@ -5761,83 +6862,264 @@
                               ctx->symtab->arena));
 }
 
+static bool remove_component(char* base, size_t* len) {
+  if (*len == 0) return false;
+
+  for (size_t i = *len - 1; i > 0; i--) {
+    if (base[i] == '.') {
+      *len = i;
+      return true;
+    }
+  }
+
+  *len = 0;
+  return true;
+}
+
 /* Given a symbol and the base symbol inside which it is defined, find the
  * symbol's definition in t. */
-static const void *symtab_resolve(symtab_addctx *ctx, const upb_fielddef *f,
-                                  const char *base, upb_strview sym,
-                                  upb_deftype_t type) {
-  const upb_strtable *t = &ctx->symtab->syms;
-  if(sym.size == 0) goto notfound;
-  if(sym.data[0] == '.') {
+static const void* symtab_resolveany(symtab_addctx* ctx,
+                                     const char* from_name_dbg,
+                                     const char* base, upb_StringView sym,
+                                     upb_deftype_t* type) {
+  const upb_strtable* t = &ctx->symtab->syms;
+  if (sym.size == 0) goto notfound;
+  upb_value v;
+  if (sym.data[0] == '.') {
     /* Symbols starting with '.' are absolute, so we do a single lookup.
      * Slice to omit the leading '.' */
-    upb_value v;
     if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) {
       goto notfound;
     }
-
-    const void *ret = unpack_def(v, type);
-    if (!ret) {
-      symtab_errf(ctx, "type mismatch when resolving field %s, name %s",
-                  f->full_name, sym.data);
-    }
-    return ret;
   } else {
-    /* Remove components from base until we find an entry or run out.
-     * TODO: This branch is totally broken, but currently not used. */
-    (void)base;
-    UPB_ASSERT(false);
-    goto notfound;
+    /* Remove components from base until we find an entry or run out. */
+    size_t baselen = strlen(base);
+    char* tmp = malloc(sym.size + strlen(base) + 1);
+    while (1) {
+      char* p = tmp;
+      if (baselen) {
+        memcpy(p, base, baselen);
+        p[baselen] = '.';
+        p += baselen + 1;
+      }
+      memcpy(p, sym.data, sym.size);
+      p += sym.size;
+      if (upb_strtable_lookup2(t, tmp, p - tmp, &v)) {
+        break;
+      }
+      if (!remove_component(tmp, &baselen)) {
+        free(tmp);
+        goto notfound;
+      }
+    }
+    free(tmp);
   }
 
+  *type = deftype(v);
+  return unpack_def(v, *type);
+
 notfound:
-  symtab_errf(ctx, "couldn't resolve name '" UPB_STRVIEW_FORMAT "'",
-              UPB_STRVIEW_ARGS(sym));
+  symtab_errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'",
+              UPB_STRINGVIEW_ARGS(sym));
+}
+
+static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg,
+                                  const char* base, upb_StringView sym,
+                                  upb_deftype_t type) {
+  upb_deftype_t found_type;
+  const void* ret =
+      symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type);
+  if (ret && found_type != type) {
+    symtab_errf(
+        ctx,
+        "type mismatch when resolving %s: couldn't find name %s with type=%d",
+        from_name_dbg, sym.data, (int)type);
+  }
+  return ret;
 }
 
 static void create_oneofdef(
-    symtab_addctx *ctx, upb_msgdef *m,
-    const google_protobuf_OneofDescriptorProto *oneof_proto) {
-  upb_oneofdef *o;
-  upb_strview name = google_protobuf_OneofDescriptorProto_name(oneof_proto);
+    symtab_addctx* ctx, upb_MessageDef* m,
+    const google_protobuf_OneofDescriptorProto* oneof_proto,
+    const upb_OneofDef* _o) {
+  upb_OneofDef* o = (upb_OneofDef*)_o;
+  upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto);
   upb_value v;
 
-  o = (upb_oneofdef*)&m->oneofs[m->oneof_count++];
   o->parent = m;
   o->full_name = makefullname(ctx, m->full_name, name);
   o->field_count = 0;
   o->synthetic = false;
 
+  SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto);
+
   v = pack_def(o, UPB_DEFTYPE_ONEOF);
-  symtab_add(ctx, o->full_name, v);
   CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena));
 
   CHK_OOM(upb_inttable_init(&o->itof, ctx->arena));
   CHK_OOM(upb_strtable_init(&o->ntof, 4, ctx->arena));
 }
 
-static str_t *newstr(symtab_addctx *ctx, const char *data, size_t len) {
-  str_t *ret = symtab_alloc(ctx, sizeof(*ret) + len);
-  if (!ret) return NULL;
+static str_t* newstr(symtab_addctx* ctx, const char* data, size_t len) {
+  str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len);
+  CHK_OOM(ret);
   ret->len = len;
   if (len) memcpy(ret->str, data, len);
   ret->str[len] = '\0';
   return ret;
 }
 
-static void parse_default(symtab_addctx *ctx, const char *str, size_t len,
-                          upb_fielddef *f) {
-  char *end;
+static bool upb_DefPool_TryGetChar(const char** src, const char* end,
+                                   char* ch) {
+  if (*src == end) return false;
+  *ch = **src;
+  *src += 1;
+  return true;
+}
+
+static char upb_DefPool_TryGetHexDigit(symtab_addctx* ctx,
+                                       const upb_FieldDef* f, const char** src,
+                                       const char* end) {
+  char ch;
+  if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1;
+  if ('0' <= ch && ch <= '9') {
+    return ch - '0';
+  }
+  ch = upb_ascii_lower(ch);
+  if ('a' <= ch && ch <= 'f') {
+    return ch - 'a' + 0xa;
+  }
+  *src -= 1;  // Char wasn't actually a hex digit.
+  return -1;
+}
+
+static char upb_DefPool_ParseHexEscape(symtab_addctx* ctx,
+                                       const upb_FieldDef* f, const char** src,
+                                       const char* end) {
+  char hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end);
+  if (hex_digit < 0) {
+    symtab_errf(ctx,
+                "\\x cannot be followed by non-hex digit in field '%s' default",
+                upb_FieldDef_FullName(f));
+    return 0;
+  }
+  unsigned int ret = hex_digit;
+  while ((hex_digit = upb_DefPool_TryGetHexDigit(ctx, f, src, end)) >= 0) {
+    ret = (ret << 4) | hex_digit;
+  }
+  if (ret > 0xff) {
+    symtab_errf(ctx, "Value of hex escape in field %s exceeds 8 bits",
+                upb_FieldDef_FullName(f));
+    return 0;
+  }
+  return ret;
+}
+
+char upb_DefPool_TryGetOctalDigit(const char** src, const char* end) {
+  char ch;
+  if (!upb_DefPool_TryGetChar(src, end, &ch)) return -1;
+  if ('0' <= ch && ch <= '7') {
+    return ch - '0';
+  }
+  *src -= 1;  // Char wasn't actually an octal digit.
+  return -1;
+}
+
+static char upb_DefPool_ParseOctalEscape(symtab_addctx* ctx,
+                                         const upb_FieldDef* f,
+                                         const char** src, const char* end) {
+  char ch = 0;
+  for (int i = 0; i < 3; i++) {
+    char digit;
+    if ((digit = upb_DefPool_TryGetOctalDigit(src, end)) >= 0) {
+      ch = (ch << 3) | digit;
+    }
+  }
+  return ch;
+}
+
+static char upb_DefPool_ParseEscape(symtab_addctx* ctx, const upb_FieldDef* f,
+                                    const char** src, const char* end) {
+  char ch;
+  if (!upb_DefPool_TryGetChar(src, end, &ch)) {
+    symtab_errf(ctx, "unterminated escape sequence in field %s",
+                upb_FieldDef_FullName(f));
+    return 0;
+  }
+  switch (ch) {
+    case 'a':
+      return '\a';
+    case 'b':
+      return '\b';
+    case 'f':
+      return '\f';
+    case 'n':
+      return '\n';
+    case 'r':
+      return '\r';
+    case 't':
+      return '\t';
+    case 'v':
+      return '\v';
+    case '\\':
+      return '\\';
+    case '\'':
+      return '\'';
+    case '\"':
+      return '\"';
+    case '?':
+      return '\?';
+    case 'x':
+    case 'X':
+      return upb_DefPool_ParseHexEscape(ctx, f, src, end);
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+      *src -= 1;
+      return upb_DefPool_ParseOctalEscape(ctx, f, src, end);
+  }
+  symtab_errf(ctx, "Unknown escape sequence: \\%c", ch);
+}
+
+static str_t* unescape(symtab_addctx* ctx, const upb_FieldDef* f,
+                       const char* data, size_t len) {
+  // Size here is an upper bound; escape sequences could ultimately shrink it.
+  str_t* ret = symtab_alloc(ctx, sizeof(*ret) + len);
+  char* dst = &ret->str[0];
+  const char* src = data;
+  const char* end = data + len;
+
+  while (src < end) {
+    if (*src == '\\') {
+      src++;
+      *dst++ = upb_DefPool_ParseEscape(ctx, f, &src, end);
+    } else {
+      *dst++ = *src++;
+    }
+  }
+
+  ret->len = dst - &ret->str[0];
+  return ret;
+}
+
+static void parse_default(symtab_addctx* ctx, const char* str, size_t len,
+                          upb_FieldDef* f) {
+  char* end;
   char nullz[64];
   errno = 0;
 
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_UINT64:
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_FLOAT:
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Int32:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_UInt64:
+    case kUpb_CType_Double:
+    case kUpb_CType_Float:
       /* Standard C number parsing functions expect null-terminated strings. */
       if (len >= sizeof(nullz) - 1) {
         symtab_errf(ctx, "Default too long: %.*s", (int)len, str);
@@ -5850,8 +7132,8 @@
       break;
   }
 
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_INT32: {
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Int32: {
       long val = strtol(str, &end, 0);
       if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) {
         goto invalid;
@@ -5859,16 +7141,17 @@
       f->defaultval.sint = val;
       break;
     }
-    case UPB_TYPE_ENUM: {
-      const upb_enumdef *e = f->sub.enumdef;
-      int32_t val;
-      if (!upb_enumdef_ntoi(e, str, len, &val)) {
+    case kUpb_CType_Enum: {
+      const upb_EnumDef* e = f->sub.enumdef;
+      const upb_EnumValueDef* ev =
+          upb_EnumDef_FindValueByNameWithSize(e, str, len);
+      if (!ev) {
         goto invalid;
       }
-      f->defaultval.sint = val;
+      f->defaultval.sint = ev->number;
       break;
     }
-    case UPB_TYPE_INT64: {
+    case kUpb_CType_Int64: {
       long long val = strtoll(str, &end, 0);
       if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) {
         goto invalid;
@@ -5876,7 +7159,7 @@
       f->defaultval.sint = val;
       break;
     }
-    case UPB_TYPE_UINT32: {
+    case kUpb_CType_UInt32: {
       unsigned long val = strtoul(str, &end, 0);
       if (val > UINT32_MAX || errno == ERANGE || *end) {
         goto invalid;
@@ -5884,7 +7167,7 @@
       f->defaultval.uint = val;
       break;
     }
-    case UPB_TYPE_UINT64: {
+    case kUpb_CType_UInt64: {
       unsigned long long val = strtoull(str, &end, 0);
       if (val > UINT64_MAX || errno == ERANGE || *end) {
         goto invalid;
@@ -5892,7 +7175,7 @@
       f->defaultval.uint = val;
       break;
     }
-    case UPB_TYPE_DOUBLE: {
+    case kUpb_CType_Double: {
       double val = strtod(str, &end);
       if (errno == ERANGE || *end) {
         goto invalid;
@@ -5900,7 +7183,7 @@
       f->defaultval.dbl = val;
       break;
     }
-    case UPB_TYPE_FLOAT: {
+    case kUpb_CType_Float: {
       float val = strtof(str, &end);
       if (errno == ERANGE || *end) {
         goto invalid;
@@ -5908,75 +7191,78 @@
       f->defaultval.flt = val;
       break;
     }
-    case UPB_TYPE_BOOL: {
+    case kUpb_CType_Bool: {
       if (streql2(str, len, "false")) {
         f->defaultval.boolean = false;
       } else if (streql2(str, len, "true")) {
         f->defaultval.boolean = true;
       } else {
+        goto invalid;
       }
       break;
     }
-    case UPB_TYPE_STRING:
+    case kUpb_CType_String:
       f->defaultval.str = newstr(ctx, str, len);
       break;
-    case UPB_TYPE_BYTES:
-      /* XXX: need to interpret the C-escaped value. */
-      f->defaultval.str = newstr(ctx, str, len);
+    case kUpb_CType_Bytes:
+      f->defaultval.str = unescape(ctx, f, str, len);
       break;
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       /* Should not have a default value. */
       symtab_errf(ctx, "Message should not have a default (%s)",
-                  upb_fielddef_fullname(f));
+                  upb_FieldDef_FullName(f));
   }
 
   return;
 
 invalid:
-  symtab_errf(ctx, "Invalid default '%.*s' for field %s", (int)len, str,
-              upb_fielddef_fullname(f));
+  symtab_errf(ctx, "Invalid default '%.*s' for field %s of type %d", (int)len,
+              str, upb_FieldDef_FullName(f), (int)upb_FieldDef_Type(f));
 }
 
-static void set_default_default(symtab_addctx *ctx, upb_fielddef *f) {
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_ENUM:
+static void set_default_default(symtab_addctx* ctx, upb_FieldDef* f) {
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Int32:
+    case kUpb_CType_Int64:
       f->defaultval.sint = 0;
       break;
-    case UPB_TYPE_UINT64:
-    case UPB_TYPE_UINT32:
+    case kUpb_CType_UInt64:
+    case kUpb_CType_UInt32:
       f->defaultval.uint = 0;
       break;
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_FLOAT:
+    case kUpb_CType_Double:
+    case kUpb_CType_Float:
       f->defaultval.dbl = 0;
       break;
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       f->defaultval.str = newstr(ctx, NULL, 0);
       break;
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       f->defaultval.boolean = false;
       break;
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Enum:
+      f->defaultval.sint = f->sub.enumdef->values[0].number;
+    case kUpb_CType_Message:
       break;
   }
 }
 
 static void create_fielddef(
-    symtab_addctx *ctx, const char *prefix, upb_msgdef *m,
-    const google_protobuf_FieldDescriptorProto *field_proto) {
-  upb_fielddef *f;
-  const google_protobuf_FieldOptions *options;
-  upb_strview name;
-  const char *full_name;
-  const char *json_name;
-  const char *shortname;
-  uint32_t field_number;
+    symtab_addctx* ctx, const char* prefix, upb_MessageDef* m,
+    const google_protobuf_FieldDescriptorProto* field_proto,
+    const upb_FieldDef* _f, bool is_extension) {
+  upb_FieldDef* f = (upb_FieldDef*)_f;
+  upb_StringView name;
+  const char* full_name;
+  const char* json_name;
+  const char* shortname;
+  int32_t field_number;
+
+  f->file = ctx->file; /* Must happen prior to symtab_add(). */
 
   if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) {
-    symtab_errf(ctx, "field has no name (%s)", upb_msgdef_fullname(m));
+    symtab_errf(ctx, "field has no name (%s)", upb_MessageDef_FullName(m));
   }
 
   name = google_protobuf_FieldDescriptorProto_name(field_proto);
@@ -5987,57 +7273,94 @@
   if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) {
     json_name = strviewdup(
         ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto));
+    f->has_json_name_ = true;
   } else {
     json_name = makejsonname(ctx, shortname);
+    f->has_json_name_ = false;
   }
 
   field_number = google_protobuf_FieldDescriptorProto_number(field_proto);
 
-  if (field_number == 0 || field_number > UPB_MAX_FIELDNUMBER) {
-    symtab_errf(ctx, "invalid field number (%u)", field_number);
+  f->full_name = full_name;
+  f->json_name = json_name;
+  f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto);
+  f->number_ = field_number;
+  f->scope.oneof = NULL;
+  f->proto3_optional_ =
+      google_protobuf_FieldDescriptorProto_proto3_optional(field_proto);
+
+  bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto);
+  bool has_type_name =
+      google_protobuf_FieldDescriptorProto_has_type_name(field_proto);
+
+  f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto);
+
+  if (has_type) {
+    switch (f->type_) {
+      case kUpb_FieldType_Message:
+      case kUpb_FieldType_Group:
+      case kUpb_FieldType_Enum:
+        if (!has_type_name) {
+          symtab_errf(ctx, "field of type %d requires type name (%s)",
+                      (int)f->type_, full_name);
+        }
+        break;
+      default:
+        if (has_type_name) {
+          symtab_errf(ctx, "invalid type for field with type_name set (%s, %d)",
+                      full_name, (int)f->type_);
+        }
+    }
+  } else if (has_type_name) {
+    f->type_ =
+        FIELD_TYPE_UNSPECIFIED;  // We'll fill this in in resolve_fielddef().
   }
 
-  if (m) {
+  if (!is_extension) {
     /* direct message field. */
-    upb_value v, field_v, json_v;
+    upb_value v, field_v, json_v, existing_v;
     size_t json_size;
 
-    f = (upb_fielddef*)&m->fields[m->field_count];
-    f->index_ = m->field_count++;
+    if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) {
+      symtab_errf(ctx, "invalid field number (%u)", field_number);
+    }
+
+    f->index_ = f - m->fields;
     f->msgdef = m;
     f->is_extension_ = false;
 
-    if (upb_strtable_lookup(&m->ntof, shortname, NULL)) {
-      symtab_errf(ctx, "duplicate field name (%s)", shortname);
-    }
-
-    if (upb_strtable_lookup(&m->ntof, json_name, NULL)) {
-      symtab_errf(ctx, "duplicate json_name (%s)", json_name);
-    }
-
-    if (upb_inttable_lookup(&m->itof, field_number, NULL)) {
-      symtab_errf(ctx, "duplicate field number (%u)", field_number);
-    }
-
     field_v = pack_def(f, UPB_DEFTYPE_FIELD);
     json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME);
     v = upb_value_constptr(f);
     json_size = strlen(json_name);
 
-    CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v,
-                                ctx->arena));
-    CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena));
-
-    if (strcmp(shortname, json_name) != 0) {
-      upb_strtable_insert(&m->ntof, json_name, json_size, json_v, ctx->arena);
+    if (upb_strtable_lookup(&m->ntof, shortname, &existing_v)) {
+      symtab_errf(ctx, "duplicate field name (%s)", shortname);
     }
 
-    if (ctx->layouts) {
-      const upb_msglayout_field *fields = m->layout->fields;
+    CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, field_v,
+                                ctx->arena));
+
+    if (strcmp(shortname, json_name) != 0) {
+      if (upb_strtable_lookup(&m->ntof, json_name, &v)) {
+        symtab_errf(ctx, "duplicate json_name (%s)", json_name);
+      } else {
+        CHK_OOM(upb_strtable_insert(&m->ntof, json_name, json_size, json_v,
+                                    ctx->arena));
+      }
+    }
+
+    if (upb_inttable_lookup(&m->itof, field_number, NULL)) {
+      symtab_errf(ctx, "duplicate field number (%u)", field_number);
+    }
+
+    CHK_OOM(upb_inttable_insert(&m->itof, field_number, v, ctx->arena));
+
+    if (ctx->layout) {
+      const upb_MiniTable_Field* fields = m->layout->fields;
       int count = m->layout->field_count;
       bool found = false;
-      int i;
-      for (i = 0; i < count; i++) {
+      for (int i = 0; i < count; i++) {
         if (fields[i].number == field_number) {
           f->layout_index = i;
           found = true;
@@ -6048,37 +7371,42 @@
     }
   } else {
     /* extension field. */
-    f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count++];
     f->is_extension_ = true;
-    symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_FIELD));
+    f->scope.extension_scope = m;
+    symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_EXT));
+    f->layout_index = ctx->ext_count++;
+    if (ctx->layout) {
+      UPB_ASSERT(ctx->file->ext_layouts[f->layout_index]->field.number ==
+                 field_number);
+    }
   }
 
-  f->full_name = full_name;
-  f->json_name = json_name;
-  f->file = ctx->file;
-  f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto);
-  f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto);
-  f->number_ = field_number;
-  f->oneof = NULL;
-  f->proto3_optional_ =
-      google_protobuf_FieldDescriptorProto_proto3_optional(field_proto);
+  if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) {
+    symtab_errf(ctx, "invalid type for field %s (%d)", f->full_name, f->type_);
+  }
+
+  if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) {
+    symtab_errf(ctx, "invalid label for field %s (%d)", f->full_name,
+                f->label_);
+  }
 
   /* We can't resolve the subdef or (in the case of extensions) the containing
    * message yet, because it may not have been defined yet.  We stash a pointer
    * to the field_proto until later when we can properly resolve it. */
   f->sub.unresolved = field_proto;
 
-  if (f->label_ == UPB_LABEL_REQUIRED && f->file->syntax == UPB_SYNTAX_PROTO3) {
+  if (f->label_ == kUpb_Label_Required &&
+      f->file->syntax == kUpb_Syntax_Proto3) {
     symtab_errf(ctx, "proto3 fields cannot be required (%s)", f->full_name);
   }
 
   if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) {
     int oneof_index =
         google_protobuf_FieldDescriptorProto_oneof_index(field_proto);
-    upb_oneofdef *oneof;
+    upb_OneofDef* oneof;
     upb_value v = upb_value_constptr(f);
 
-    if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+    if (upb_FieldDef_Label(f) != kUpb_Label_Optional) {
       symtab_errf(ctx, "fields in oneof must have OPTIONAL label (%s)",
                   f->full_name);
     }
@@ -6092,8 +7420,8 @@
       symtab_errf(ctx, "oneof_index out of range (%s)", f->full_name);
     }
 
-    oneof = (upb_oneofdef *)&m->oneofs[oneof_index];
-    f->oneof = oneof;
+    oneof = (upb_OneofDef*)&m->oneofs[oneof_index];
+    f->scope.oneof = oneof;
 
     oneof->field_count++;
     if (f->proto3_optional_) {
@@ -6103,43 +7431,166 @@
     CHK_OOM(
         upb_strtable_insert(&oneof->ntof, name.data, name.size, v, ctx->arena));
   } else {
-    f->oneof = NULL;
     if (f->proto3_optional_) {
       symtab_errf(ctx, "field with proto3_optional was not in a oneof (%s)",
                   f->full_name);
     }
   }
 
-  options = google_protobuf_FieldDescriptorProto_has_options(field_proto) ?
-    google_protobuf_FieldDescriptorProto_options(field_proto) : NULL;
+  SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto);
 
-  if (options && google_protobuf_FieldOptions_has_packed(options)) {
-    f->packed_ = google_protobuf_FieldOptions_packed(options);
+  if (google_protobuf_FieldOptions_has_packed(f->opts)) {
+    f->packed_ = google_protobuf_FieldOptions_packed(f->opts);
   } else {
     /* Repeated fields default to packed for proto3 only. */
-    f->packed_ = upb_fielddef_isprimitive(f) &&
-        f->label_ == UPB_LABEL_REPEATED && f->file->syntax == UPB_SYNTAX_PROTO3;
+    f->packed_ = upb_FieldDef_IsPrimitive(f) &&
+                 f->label_ == kUpb_Label_Repeated &&
+                 f->file->syntax == kUpb_Syntax_Proto3;
+  }
+}
+
+static void create_service(
+    symtab_addctx* ctx, const google_protobuf_ServiceDescriptorProto* svc_proto,
+    const upb_ServiceDef* _s) {
+  upb_ServiceDef* s = (upb_ServiceDef*)_s;
+  upb_StringView name;
+  const google_protobuf_MethodDescriptorProto* const* methods;
+  size_t i, n;
+
+  s->file = ctx->file; /* Must happen prior to symtab_add. */
+
+  name = google_protobuf_ServiceDescriptorProto_name(svc_proto);
+  check_ident(ctx, name, false);
+  s->full_name = makefullname(ctx, ctx->file->package, name);
+  symtab_add(ctx, s->full_name, pack_def(s, UPB_DEFTYPE_SERVICE));
+
+  methods = google_protobuf_ServiceDescriptorProto_method(svc_proto, &n);
+
+  s->method_count = n;
+  s->methods = symtab_alloc(ctx, sizeof(*s->methods) * n);
+
+  SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, svc_proto);
+
+  for (i = 0; i < n; i++) {
+    const google_protobuf_MethodDescriptorProto* method_proto = methods[i];
+    upb_MethodDef* m = (upb_MethodDef*)&s->methods[i];
+    upb_StringView name =
+        google_protobuf_MethodDescriptorProto_name(method_proto);
+
+    m->service = s;
+    m->full_name = makefullname(ctx, s->full_name, name);
+    m->client_streaming =
+        google_protobuf_MethodDescriptorProto_client_streaming(method_proto);
+    m->server_streaming =
+        google_protobuf_MethodDescriptorProto_server_streaming(method_proto);
+    m->input_type = symtab_resolve(
+        ctx, m->full_name, m->full_name,
+        google_protobuf_MethodDescriptorProto_input_type(method_proto),
+        UPB_DEFTYPE_MSG);
+    m->output_type = symtab_resolve(
+        ctx, m->full_name, m->full_name,
+        google_protobuf_MethodDescriptorProto_output_type(method_proto),
+        UPB_DEFTYPE_MSG);
+
+    SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, method_proto);
+  }
+}
+
+static int count_bits_debug(uint64_t x) {
+  // For assertions only, speed does not matter.
+  int n = 0;
+  while (x) {
+    if (x & 1) n++;
+    x >>= 1;
+  }
+  return n;
+}
+
+upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx,
+                                      const upb_EnumDef* e) {
+  int n = 0;
+  uint64_t mask = 0;
+
+  for (int i = 0; i < e->value_count; i++) {
+    uint32_t val = (uint32_t)e->values[i].number;
+    if (val < 64) {
+      mask |= 1 << val;
+    } else {
+      n++;
+    }
   }
 
-  if (options) {
-    f->lazy_ = google_protobuf_FieldOptions_lazy(options);
-  } else {
-    f->lazy_ = false;
+  int32_t* values = symtab_alloc(ctx, sizeof(*values) * n);
+
+  if (n) {
+    int32_t* p = values;
+
+    // Add values outside the bitmask range to the list, as described in the
+    // comments for upb_MiniTable_Enum.
+    for (int i = 0; i < e->value_count; i++) {
+      int32_t val = e->values[i].number;
+      if ((uint32_t)val >= 64) {
+        *p++ = val;
+      }
+    }
+    UPB_ASSERT(p == values + n);
+  }
+
+  UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask));
+
+  upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout));
+  layout->value_count = n;
+  layout->mask = mask;
+  layout->values = values;
+
+  return layout;
+}
+
+static void create_enumvaldef(
+    symtab_addctx* ctx, const char* prefix,
+    const google_protobuf_EnumValueDescriptorProto* val_proto, upb_EnumDef* e,
+    int i) {
+  upb_EnumValueDef* val = (upb_EnumValueDef*)&e->values[i];
+  upb_StringView name =
+      google_protobuf_EnumValueDescriptorProto_name(val_proto);
+  upb_value v = upb_value_constptr(val);
+
+  val->parent = e; /* Must happen prior to symtab_add(). */
+  val->full_name = makefullname(ctx, prefix, name);
+  val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto);
+  symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL));
+
+  SET_OPTIONS(val->opts, EnumValueDescriptorProto, EnumValueOptions, val_proto);
+
+  if (i == 0 && e->file->syntax == kUpb_Syntax_Proto3 && val->number != 0) {
+    symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)",
+                e->full_name);
+  }
+
+  CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena));
+
+  // Multiple enumerators can have the same number, first one wins.
+  if (!upb_inttable_lookup(&e->iton, val->number, NULL)) {
+    CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena));
   }
 }
 
 static void create_enumdef(
-    symtab_addctx *ctx, const char *prefix,
-    const google_protobuf_EnumDescriptorProto *enum_proto) {
-  upb_enumdef *e;
-  const google_protobuf_EnumValueDescriptorProto *const *values;
-  upb_strview name;
+    symtab_addctx* ctx, const char* prefix,
+    const google_protobuf_EnumDescriptorProto* enum_proto,
+    const upb_MessageDef* containing_type, const upb_EnumDef* _e) {
+  upb_EnumDef* e = (upb_EnumDef*)_e;
+  ;
+  const google_protobuf_EnumValueDescriptorProto* const* values;
+  upb_StringView name;
   size_t i, n;
 
+  e->file = ctx->file; /* Must happen prior to symtab_add() */
+  e->containing_type = containing_type;
+
   name = google_protobuf_EnumDescriptorProto_name(enum_proto);
   check_ident(ctx, name, false);
 
-  e = (upb_enumdef*)&ctx->file->enums[ctx->file->enum_count++];
   e->full_name = makefullname(ctx, prefix, name);
   symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM));
 
@@ -6147,225 +7598,374 @@
   CHK_OOM(upb_strtable_init(&e->ntoi, n, ctx->arena));
   CHK_OOM(upb_inttable_init(&e->iton, ctx->arena));
 
-  e->file = ctx->file;
   e->defaultval = 0;
+  e->value_count = n;
+  e->values = symtab_alloc(ctx, sizeof(*e->values) * n);
 
   if (n == 0) {
     symtab_errf(ctx, "enums must contain at least one value (%s)",
                 e->full_name);
   }
 
+  SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto);
+
   for (i = 0; i < n; i++) {
-    const google_protobuf_EnumValueDescriptorProto *value = values[i];
-    upb_strview name = google_protobuf_EnumValueDescriptorProto_name(value);
-    char *name2 = strviewdup(ctx, name);
-    int32_t num = google_protobuf_EnumValueDescriptorProto_number(value);
-    upb_value v = upb_value_int32(num);
-
-    if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && num != 0) {
-      symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)",
-                  e->full_name);
-    }
-
-    if (upb_strtable_lookup(&e->ntoi, name2, NULL)) {
-      symtab_errf(ctx, "duplicate enum label '%s'", name2);
-    }
-
-    CHK_OOM(name2)
-    CHK_OOM(upb_strtable_insert(&e->ntoi, name2, strlen(name2), v, ctx->arena));
-
-    if (!upb_inttable_lookup(&e->iton, num, NULL)) {
-      upb_value v = upb_value_cstr(name2);
-      CHK_OOM(upb_inttable_insert(&e->iton, num, v, ctx->arena));
-    }
+    create_enumvaldef(ctx, prefix, values[i], e, i);
   }
 
   upb_inttable_compact(&e->iton, ctx->arena);
+
+  if (e->file->syntax == kUpb_Syntax_Proto2) {
+    if (ctx->layout) {
+      UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count);
+      e->layout = ctx->layout->enums[ctx->enum_count++];
+      UPB_ASSERT(n ==
+                 e->layout->value_count + count_bits_debug(e->layout->mask));
+    } else {
+      e->layout = create_enumlayout(ctx, e);
+    }
+  } else {
+    e->layout = NULL;
+  }
 }
 
-static void create_msgdef(symtab_addctx *ctx, const char *prefix,
-                          const google_protobuf_DescriptorProto *msg_proto) {
-  upb_msgdef *m;
-  const google_protobuf_MessageOptions *options;
-  const google_protobuf_OneofDescriptorProto *const *oneofs;
-  const google_protobuf_FieldDescriptorProto *const *fields;
-  const google_protobuf_EnumDescriptorProto *const *enums;
-  const google_protobuf_DescriptorProto *const *msgs;
-  size_t i, n_oneof, n_field, n;
-  upb_strview name;
+static void msgdef_create_nested(
+    symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto,
+    upb_MessageDef* m);
+
+static void create_msgdef(symtab_addctx* ctx, const char* prefix,
+                          const google_protobuf_DescriptorProto* msg_proto,
+                          const upb_MessageDef* containing_type,
+                          const upb_MessageDef* _m) {
+  upb_MessageDef* m = (upb_MessageDef*)_m;
+  const google_protobuf_OneofDescriptorProto* const* oneofs;
+  const google_protobuf_FieldDescriptorProto* const* fields;
+  const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges;
+  size_t i, n_oneof, n_field, n_ext_range;
+  upb_StringView name;
+
+  m->file = ctx->file; /* Must happen prior to symtab_add(). */
+  m->containing_type = containing_type;
 
   name = google_protobuf_DescriptorProto_name(msg_proto);
   check_ident(ctx, name, false);
 
-  m = (upb_msgdef*)&ctx->file->msgs[ctx->file->msg_count++];
   m->full_name = makefullname(ctx, prefix, name);
   symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG));
 
   oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof);
   fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field);
+  ext_ranges =
+      google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range);
 
   CHK_OOM(upb_inttable_init(&m->itof, ctx->arena));
   CHK_OOM(upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena));
 
-  m->file = ctx->file;
-  m->map_entry = false;
-
-  options = google_protobuf_DescriptorProto_options(msg_proto);
-
-  if (options) {
-    m->map_entry = google_protobuf_MessageOptions_map_entry(options);
-  }
-
-  if (ctx->layouts) {
-    m->layout = *ctx->layouts;
-    ctx->layouts++;
+  if (ctx->layout) {
+    /* create_fielddef() below depends on this being set. */
+    UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count);
+    m->layout = ctx->layout->msgs[ctx->msg_count++];
+    UPB_ASSERT(n_field == m->layout->field_count);
   } else {
     /* Allocate now (to allow cross-linking), populate later. */
-    m->layout = symtab_alloc(
-        ctx, sizeof(*m->layout) + sizeof(_upb_fasttable_entry));
+    m->layout =
+        symtab_alloc(ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry));
   }
 
-  m->oneof_count = 0;
+  SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto);
+
+  m->oneof_count = n_oneof;
   m->oneofs = symtab_alloc(ctx, sizeof(*m->oneofs) * n_oneof);
   for (i = 0; i < n_oneof; i++) {
-    create_oneofdef(ctx, m, oneofs[i]);
+    create_oneofdef(ctx, m, oneofs[i], &m->oneofs[i]);
   }
 
-  m->field_count = 0;
+  m->field_count = n_field;
   m->fields = symtab_alloc(ctx, sizeof(*m->fields) * n_field);
   for (i = 0; i < n_field; i++) {
-    create_fielddef(ctx, m->full_name, m, fields[i]);
+    create_fielddef(ctx, m->full_name, m, fields[i], &m->fields[i],
+                    /* is_extension= */ false);
+  }
+
+  m->ext_range_count = n_ext_range;
+  m->ext_ranges = symtab_alloc(ctx, sizeof(*m->ext_ranges) * n_ext_range);
+  for (i = 0; i < n_ext_range; i++) {
+    const google_protobuf_DescriptorProto_ExtensionRange* r = ext_ranges[i];
+    upb_ExtensionRange* r_def = (upb_ExtensionRange*)&m->ext_ranges[i];
+    int32_t start = google_protobuf_DescriptorProto_ExtensionRange_start(r);
+    int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(r);
+    int32_t max =
+        google_protobuf_MessageOptions_message_set_wire_format(m->opts)
+            ? INT32_MAX
+            : kUpb_MaxFieldNumber + 1;
+
+    // A full validation would also check that each range is disjoint, and that
+    // none of the fields overlap with the extension ranges, but we are just
+    // sanity checking here.
+    if (start < 1 || end <= start || end > max) {
+      symtab_errf(ctx, "Extension range (%d, %d) is invalid, message=%s\n",
+                  (int)start, (int)end, m->full_name);
+    }
+
+    r_def->start = start;
+    r_def->end = end;
+    SET_OPTIONS(r_def->opts, DescriptorProto_ExtensionRange,
+                ExtensionRangeOptions, r);
   }
 
   finalize_oneofs(ctx, m);
   assign_msg_wellknowntype(m);
   upb_inttable_compact(&m->itof, ctx->arena);
+  msgdef_create_nested(ctx, msg_proto, m);
+}
 
-  /* This message is built.  Now build nested messages and enums. */
+static void msgdef_create_nested(
+    symtab_addctx* ctx, const google_protobuf_DescriptorProto* msg_proto,
+    upb_MessageDef* m) {
+  size_t n;
 
-  enums = google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
-  for (i = 0; i < n; i++) {
-    create_enumdef(ctx, m->full_name, enums[i]);
+  const google_protobuf_EnumDescriptorProto* const* enums =
+      google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
+  m->nested_enum_count = n;
+  m->nested_enums = symtab_alloc(ctx, sizeof(*m->nested_enums) * n);
+  for (size_t i = 0; i < n; i++) {
+    m->nested_enum_count = i + 1;
+    create_enumdef(ctx, m->full_name, enums[i], m, &m->nested_enums[i]);
   }
 
-  msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
-  for (i = 0; i < n; i++) {
-    create_msgdef(ctx, m->full_name, msgs[i]);
+  const google_protobuf_FieldDescriptorProto* const* exts =
+      google_protobuf_DescriptorProto_extension(msg_proto, &n);
+  m->nested_ext_count = n;
+  m->nested_exts = symtab_alloc(ctx, sizeof(*m->nested_exts) * n);
+  for (size_t i = 0; i < n; i++) {
+    create_fielddef(ctx, m->full_name, m, exts[i], &m->nested_exts[i],
+                    /* is_extension= */ true);
+    ((upb_FieldDef*)&m->nested_exts[i])->index_ = i;
+  }
+
+  const google_protobuf_DescriptorProto* const* msgs =
+      google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
+  m->nested_msg_count = n;
+  m->nested_msgs = symtab_alloc(ctx, sizeof(*m->nested_msgs) * n);
+  for (size_t i = 0; i < n; i++) {
+    create_msgdef(ctx, m->full_name, msgs[i], m, &m->nested_msgs[i]);
   }
 }
 
-static void count_types_in_msg(const google_protobuf_DescriptorProto *msg_proto,
-                               upb_filedef *file) {
-  const google_protobuf_DescriptorProto *const *msgs;
-  size_t i, n;
-
-  file->msg_count++;
-
-  msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
-  for (i = 0; i < n; i++) {
-    count_types_in_msg(msgs[i], file);
-  }
-
-  google_protobuf_DescriptorProto_enum_type(msg_proto, &n);
-  file->enum_count += n;
-
-  google_protobuf_DescriptorProto_extension(msg_proto, &n);
-  file->ext_count += n;
-}
-
-static void count_types_in_file(
-    const google_protobuf_FileDescriptorProto *file_proto,
-    upb_filedef *file) {
-  const google_protobuf_DescriptorProto *const *msgs;
-  size_t i, n;
-
-  msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
-  for (i = 0; i < n; i++) {
-    count_types_in_msg(msgs[i], file);
-  }
-
-  google_protobuf_FileDescriptorProto_enum_type(file_proto, &n);
-  file->enum_count += n;
-
-  google_protobuf_FileDescriptorProto_extension(file_proto, &n);
-  file->ext_count += n;
-}
-
-static void resolve_fielddef(symtab_addctx *ctx, const char *prefix,
-                             upb_fielddef *f) {
-  upb_strview name;
-  const google_protobuf_FieldDescriptorProto *field_proto = f->sub.unresolved;
-
-  if (f->is_extension_) {
-    if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) {
-      symtab_errf(ctx, "extension for field '%s' had no extendee",
-                  f->full_name);
+static void resolve_subdef(symtab_addctx* ctx, const char* prefix,
+                           upb_FieldDef* f) {
+  const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved;
+  upb_StringView name =
+      google_protobuf_FieldDescriptorProto_type_name(field_proto);
+  bool has_name =
+      google_protobuf_FieldDescriptorProto_has_type_name(field_proto);
+  switch ((int)f->type_) {
+    case FIELD_TYPE_UNSPECIFIED: {
+      // Type was not specified and must be inferred.
+      UPB_ASSERT(has_name);
+      upb_deftype_t type;
+      const void* def =
+          symtab_resolveany(ctx, f->full_name, prefix, name, &type);
+      switch (type) {
+        case UPB_DEFTYPE_ENUM:
+          f->sub.enumdef = def;
+          f->type_ = kUpb_FieldType_Enum;
+          break;
+        case UPB_DEFTYPE_MSG:
+          f->sub.msgdef = def;
+          f->type_ = kUpb_FieldType_Message;  // It appears there is no way of
+                                              // this being a group.
+          break;
+        default:
+          symtab_errf(ctx, "Couldn't resolve type name for field %s",
+                      f->full_name);
+      }
     }
+    case kUpb_FieldType_Message:
+    case kUpb_FieldType_Group:
+      UPB_ASSERT(has_name);
+      f->sub.msgdef =
+          symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG);
+      break;
+    case kUpb_FieldType_Enum:
+      UPB_ASSERT(has_name);
+      f->sub.enumdef =
+          symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_ENUM);
+      break;
+    default:
+      // No resolution necessary.
+      break;
+  }
+}
 
-    name = google_protobuf_FieldDescriptorProto_extendee(field_proto);
-    f->msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG);
+static void resolve_extension(
+    symtab_addctx* ctx, const char* prefix, upb_FieldDef* f,
+    const google_protobuf_FieldDescriptorProto* field_proto) {
+  if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) {
+    symtab_errf(ctx, "extension for field '%s' had no extendee", f->full_name);
   }
 
-  if ((upb_fielddef_issubmsg(f) || f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) &&
-      !google_protobuf_FieldDescriptorProto_has_type_name(field_proto)) {
-    symtab_errf(ctx, "field '%s' is missing type name", f->full_name);
+  upb_StringView name =
+      google_protobuf_FieldDescriptorProto_extendee(field_proto);
+  const upb_MessageDef* m =
+      symtab_resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG);
+  f->msgdef = m;
+
+  bool found = false;
+
+  for (int i = 0, n = m->ext_range_count; i < n; i++) {
+    const upb_ExtensionRange* r = &m->ext_ranges[i];
+    if (r->start <= f->number_ && f->number_ < r->end) {
+      found = true;
+      break;
+    }
   }
 
-  name = google_protobuf_FieldDescriptorProto_type_name(field_proto);
-
-  if (upb_fielddef_issubmsg(f)) {
-    f->sub.msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG);
-  } else if (f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) {
-    f->sub.enumdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_ENUM);
+  if (!found) {
+    symtab_errf(ctx,
+                "field number %u in extension %s has no extension range in "
+                "message %s",
+                (unsigned)f->number_, f->full_name, f->msgdef->full_name);
   }
 
-  /* Have to delay resolving of the default value until now because of the enum
-   * case, since enum defaults are specified with a label. */
+  const upb_MiniTable_Extension* ext = ctx->file->ext_layouts[f->layout_index];
+  if (ctx->layout) {
+    UPB_ASSERT(upb_FieldDef_Number(f) == ext->field.number);
+  } else {
+    upb_MiniTable_Extension* mut_ext = (upb_MiniTable_Extension*)ext;
+    fill_fieldlayout(&mut_ext->field, f);
+    mut_ext->field.presence = 0;
+    mut_ext->field.offset = 0;
+    mut_ext->field.submsg_index = 0;
+    mut_ext->extendee = f->msgdef->layout;
+    mut_ext->sub.submsg = f->sub.msgdef->layout;
+  }
+
+  CHK_OOM(upb_inttable_insert(&ctx->symtab->exts, (uintptr_t)ext,
+                              upb_value_constptr(f), ctx->arena));
+}
+
+static void resolve_default(
+    symtab_addctx* ctx, upb_FieldDef* f,
+    const google_protobuf_FieldDescriptorProto* field_proto) {
+  // Have to delay resolving of the default value until now because of the enum
+  // case, since enum defaults are specified with a label.
   if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) {
-    upb_strview defaultval =
+    upb_StringView defaultval =
         google_protobuf_FieldDescriptorProto_default_value(field_proto);
 
-    if (f->file->syntax == UPB_SYNTAX_PROTO3) {
+    if (f->file->syntax == kUpb_Syntax_Proto3) {
       symtab_errf(ctx, "proto3 fields cannot have explicit defaults (%s)",
                   f->full_name);
     }
 
-    if (upb_fielddef_issubmsg(f)) {
+    if (upb_FieldDef_IsSubMessage(f)) {
       symtab_errf(ctx, "message fields cannot have explicit defaults (%s)",
                   f->full_name);
     }
 
     parse_default(ctx, defaultval.data, defaultval.size, f);
+    f->has_default = true;
   } else {
     set_default_default(ctx, f);
+    f->has_default = false;
   }
 }
 
+static void resolve_fielddef(symtab_addctx* ctx, const char* prefix,
+                             upb_FieldDef* f) {
+  // We have to stash this away since resolve_subdef() may overwrite it.
+  const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved;
+
+  resolve_subdef(ctx, prefix, f);
+  resolve_default(ctx, f, field_proto);
+
+  if (f->is_extension_) {
+    resolve_extension(ctx, prefix, f, field_proto);
+  }
+}
+
+static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) {
+  for (int i = 0; i < m->field_count; i++) {
+    resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]);
+  }
+
+  for (int i = 0; i < m->nested_ext_count; i++) {
+    resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->nested_exts[i]);
+  }
+
+  if (!ctx->layout) make_layout(ctx, m);
+
+  m->in_message_set = false;
+  if (m->nested_ext_count == 1) {
+    const upb_FieldDef* ext = &m->nested_exts[0];
+    if (ext->type_ == kUpb_FieldType_Message &&
+        ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m &&
+        google_protobuf_MessageOptions_message_set_wire_format(
+            ext->msgdef->opts)) {
+      m->in_message_set = true;
+    }
+  }
+
+  for (int i = 0; i < m->nested_msg_count; i++) {
+    resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]);
+  }
+}
+
+static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) {
+  size_t n;
+  google_protobuf_DescriptorProto_extension(msg_proto, &n);
+  int ext_count = n;
+
+  const google_protobuf_DescriptorProto* const* nested_msgs =
+      google_protobuf_DescriptorProto_nested_type(msg_proto, &n);
+  for (size_t i = 0; i < n; i++) {
+    ext_count += count_exts_in_msg(nested_msgs[i]);
+  }
+
+  return ext_count;
+}
+
 static void build_filedef(
-    symtab_addctx *ctx, upb_filedef *file,
-    const google_protobuf_FileDescriptorProto *file_proto) {
-  const google_protobuf_FileOptions *file_options_proto;
-  const google_protobuf_DescriptorProto *const *msgs;
-  const google_protobuf_EnumDescriptorProto *const *enums;
-  const google_protobuf_FieldDescriptorProto *const *exts;
-  const upb_strview* strs;
+    symtab_addctx* ctx, upb_FileDef* file,
+    const google_protobuf_FileDescriptorProto* file_proto) {
+  const google_protobuf_DescriptorProto* const* msgs;
+  const google_protobuf_EnumDescriptorProto* const* enums;
+  const google_protobuf_FieldDescriptorProto* const* exts;
+  const google_protobuf_ServiceDescriptorProto* const* services;
+  const upb_StringView* strs;
+  const int32_t* public_deps;
+  const int32_t* weak_deps;
   size_t i, n;
 
   file->symtab = ctx->symtab;
 
-  /* One pass to count and allocate. */
-  file->msg_count = 0;
-  file->enum_count = 0;
-  file->ext_count = 0;
-  count_types_in_file(file_proto, file);
-  file->msgs = symtab_alloc(ctx, sizeof(*file->msgs) * file->msg_count);
-  file->enums = symtab_alloc(ctx, sizeof(*file->enums) * file->enum_count);
-  file->exts = symtab_alloc(ctx, sizeof(*file->exts) * file->ext_count);
+  /* Count all extensions in the file, to build a flat array of layouts. */
+  google_protobuf_FileDescriptorProto_extension(file_proto, &n);
+  int ext_count = n;
+  msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
+  for (int i = 0; i < n; i++) {
+    ext_count += count_exts_in_msg(msgs[i]);
+  }
+  file->ext_count = ext_count;
 
-  /* In the second pass we increment these as defs are added. */
-  file->msg_count = 0;
-  file->enum_count = 0;
-  file->ext_count = 0;
+  if (ctx->layout) {
+    /* We are using the ext layouts that were passed in. */
+    file->ext_layouts = ctx->layout->exts;
+    if (ctx->layout->ext_count != file->ext_count) {
+      symtab_errf(ctx, "Extension count did not match layout (%d vs %d)",
+                  ctx->layout->ext_count, file->ext_count);
+    }
+  } else {
+    /* We are building ext layouts from scratch. */
+    file->ext_layouts =
+        symtab_alloc(ctx, sizeof(*file->ext_layouts) * file->ext_count);
+    upb_MiniTable_Extension* ext =
+        symtab_alloc(ctx, sizeof(*ext) * file->ext_count);
+    for (int i = 0; i < file->ext_count; i++) {
+      file->ext_layouts[i] = &ext[i];
+    }
+  }
 
   if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) {
     symtab_errf(ctx, "File has no name");
@@ -6373,11 +7973,9 @@
 
   file->name =
       strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto));
-  file->phpprefix = NULL;
-  file->phpnamespace = NULL;
 
   if (google_protobuf_FileDescriptorProto_has_package(file_proto)) {
-    upb_strview package =
+    upb_StringView package =
         google_protobuf_FileDescriptorProto_package(file_proto);
     check_ident(ctx, package, true);
     file->package = strviewdup(ctx, package);
@@ -6386,133 +7984,189 @@
   }
 
   if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) {
-    upb_strview syntax =
+    upb_StringView syntax =
         google_protobuf_FileDescriptorProto_syntax(file_proto);
 
     if (streql_view(syntax, "proto2")) {
-      file->syntax = UPB_SYNTAX_PROTO2;
+      file->syntax = kUpb_Syntax_Proto2;
     } else if (streql_view(syntax, "proto3")) {
-      file->syntax = UPB_SYNTAX_PROTO3;
+      file->syntax = kUpb_Syntax_Proto3;
     } else {
-      symtab_errf(ctx, "Invalid syntax '" UPB_STRVIEW_FORMAT "'",
-                  UPB_STRVIEW_ARGS(syntax));
+      symtab_errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'",
+                  UPB_STRINGVIEW_ARGS(syntax));
     }
   } else {
-    file->syntax = UPB_SYNTAX_PROTO2;
+    file->syntax = kUpb_Syntax_Proto2;
   }
 
   /* Read options. */
-  file_options_proto = google_protobuf_FileDescriptorProto_options(file_proto);
-  if (file_options_proto) {
-    if (google_protobuf_FileOptions_has_php_class_prefix(file_options_proto)) {
-      file->phpprefix = strviewdup(
-          ctx,
-          google_protobuf_FileOptions_php_class_prefix(file_options_proto));
-    }
-    if (google_protobuf_FileOptions_has_php_namespace(file_options_proto)) {
-      file->phpnamespace = strviewdup(
-          ctx, google_protobuf_FileOptions_php_namespace(file_options_proto));
-    }
-  }
+  SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto);
 
   /* Verify dependencies. */
   strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n);
+  file->dep_count = n;
   file->deps = symtab_alloc(ctx, sizeof(*file->deps) * n);
 
   for (i = 0; i < n; i++) {
-    upb_strview dep_name = strs[i];
-    upb_value v;
-    if (!upb_strtable_lookup2(&ctx->symtab->files, dep_name.data,
-                              dep_name.size, &v)) {
+    upb_StringView str = strs[i];
+    file->deps[i] =
+        upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size);
+    if (!file->deps[i]) {
       symtab_errf(ctx,
-                  "Depends on file '" UPB_STRVIEW_FORMAT
+                  "Depends on file '" UPB_STRINGVIEW_FORMAT
                   "', but it has not been loaded",
-                  UPB_STRVIEW_ARGS(dep_name));
+                  UPB_STRINGVIEW_ARGS(str));
     }
-    file->deps[i] = upb_value_getconstptr(v);
   }
 
-  /* Create messages. */
-  msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
+  public_deps =
+      google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n);
+  file->public_dep_count = n;
+  file->public_deps = symtab_alloc(ctx, sizeof(*file->public_deps) * n);
+  int32_t* mutable_public_deps = (int32_t*)file->public_deps;
   for (i = 0; i < n; i++) {
-    create_msgdef(ctx, file->package, msgs[i]);
+    if (public_deps[i] >= file->dep_count) {
+      symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]);
+    }
+    mutable_public_deps[i] = public_deps[i];
+  }
+
+  weak_deps =
+      google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n);
+  file->weak_dep_count = n;
+  file->weak_deps = symtab_alloc(ctx, sizeof(*file->weak_deps) * n);
+  int32_t* mutable_weak_deps = (int32_t*)file->weak_deps;
+  for (i = 0; i < n; i++) {
+    if (weak_deps[i] >= file->dep_count) {
+      symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]);
+    }
+    mutable_weak_deps[i] = weak_deps[i];
   }
 
   /* Create enums. */
   enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n);
+  file->top_lvl_enum_count = n;
+  file->top_lvl_enums = symtab_alloc(ctx, sizeof(*file->top_lvl_enums) * n);
   for (i = 0; i < n; i++) {
-    create_enumdef(ctx, file->package, enums[i]);
+    create_enumdef(ctx, file->package, enums[i], NULL, &file->top_lvl_enums[i]);
   }
 
   /* Create extensions. */
   exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n);
-  file->exts = symtab_alloc(ctx, sizeof(*file->exts) * n);
+  file->top_lvl_ext_count = n;
+  file->top_lvl_exts = symtab_alloc(ctx, sizeof(*file->top_lvl_exts) * n);
   for (i = 0; i < n; i++) {
-    create_fielddef(ctx, file->package, NULL, exts[i]);
+    create_fielddef(ctx, file->package, NULL, exts[i], &file->top_lvl_exts[i],
+                    /* is_extension= */ true);
+    ((upb_FieldDef*)&file->top_lvl_exts[i])->index_ = i;
+  }
+
+  /* Create messages. */
+  msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n);
+  file->top_lvl_msg_count = n;
+  file->top_lvl_msgs = symtab_alloc(ctx, sizeof(*file->top_lvl_msgs) * n);
+  for (i = 0; i < n; i++) {
+    create_msgdef(ctx, file->package, msgs[i], NULL, &file->top_lvl_msgs[i]);
+  }
+
+  /* Create services. */
+  services = google_protobuf_FileDescriptorProto_service(file_proto, &n);
+  file->service_count = n;
+  file->services = symtab_alloc(ctx, sizeof(*file->services) * n);
+  for (i = 0; i < n; i++) {
+    create_service(ctx, services[i], &file->services[i]);
+    ((upb_ServiceDef*)&file->services[i])->index = i;
   }
 
   /* Now that all names are in the table, build layouts and resolve refs. */
-  for (i = 0; i < (size_t)file->ext_count; i++) {
-    resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i]);
+  for (i = 0; i < (size_t)file->top_lvl_ext_count; i++) {
+    resolve_fielddef(ctx, file->package, (upb_FieldDef*)&file->top_lvl_exts[i]);
   }
 
-  for (i = 0; i < (size_t)file->msg_count; i++) {
-    const upb_msgdef *m = &file->msgs[i];
-    int j;
-    for (j = 0; j < m->field_count; j++) {
-      resolve_fielddef(ctx, m->full_name, (upb_fielddef*)&m->fields[j]);
-    }
+  for (i = 0; i < (size_t)file->top_lvl_msg_count; i++) {
+    resolve_msgdef(ctx, (upb_MessageDef*)&file->top_lvl_msgs[i]);
   }
 
-  if (!ctx->layouts) {
-    for (i = 0; i < (size_t)file->msg_count; i++) {
-      const upb_msgdef *m = &file->msgs[i];
-      make_layout(ctx, m);
-    }
+  if (file->ext_count) {
+    CHK_OOM(_upb_extreg_add(ctx->symtab->extreg, file->ext_layouts,
+                            file->ext_count));
   }
 }
 
-static void remove_filedef(upb_symtab *s, upb_filedef *file) {
-  int i;
-  for (i = 0; i < file->msg_count; i++) {
-    const char *name = file->msgs[i].full_name;
-    upb_strtable_remove(&s->syms, name, strlen(name), NULL);
-  }
-  for (i = 0; i < file->enum_count; i++) {
-    const char *name = file->enums[i].full_name;
-    upb_strtable_remove(&s->syms, name, strlen(name), NULL);
-  }
-  for (i = 0; i < file->ext_count; i++) {
-    const char *name = file->exts[i].full_name;
-    upb_strtable_remove(&s->syms, name, strlen(name), NULL);
+static void remove_filedef(upb_DefPool* s, upb_FileDef* file) {
+  intptr_t iter = UPB_INTTABLE_BEGIN;
+  upb_StringView key;
+  upb_value val;
+  while (upb_strtable_next2(&s->syms, &key, &val, &iter)) {
+    const upb_FileDef* f;
+    switch (deftype(val)) {
+      case UPB_DEFTYPE_EXT:
+        f = upb_FieldDef_File(unpack_def(val, UPB_DEFTYPE_EXT));
+        break;
+      case UPB_DEFTYPE_MSG:
+        f = upb_MessageDef_File(unpack_def(val, UPB_DEFTYPE_MSG));
+        break;
+      case UPB_DEFTYPE_ENUM:
+        f = upb_EnumDef_File(unpack_def(val, UPB_DEFTYPE_ENUM));
+        break;
+      case UPB_DEFTYPE_ENUMVAL:
+        f = upb_EnumDef_File(
+            upb_EnumValueDef_Enum(unpack_def(val, UPB_DEFTYPE_ENUMVAL)));
+        break;
+      case UPB_DEFTYPE_SERVICE:
+        f = upb_ServiceDef_File(unpack_def(val, UPB_DEFTYPE_SERVICE));
+        break;
+      default:
+        UPB_UNREACHABLE();
+    }
+
+    if (f == file) upb_strtable_removeiter(&s->syms, &iter);
   }
 }
 
-static const upb_filedef *_upb_symtab_addfile(
-    upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto,
-    const upb_msglayout **layouts, upb_status *status) {
+static const upb_FileDef* _upb_DefPool_AddFile(
+    upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto,
+    const upb_MiniTable_File* layout, upb_Status* status) {
   symtab_addctx ctx;
-  upb_strview name = google_protobuf_FileDescriptorProto_name(file_proto);
+  upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto);
+  upb_value v;
 
-  if (upb_strtable_lookup2(&s->files, name.data, name.size, NULL)) {
-    upb_status_seterrf(status, "duplicate file name (%.*s)",
-                       UPB_STRVIEW_ARGS(name));
-    return NULL;
+  if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) {
+    if (unpack_def(v, UPB_DEFTYPE_FILE)) {
+      upb_Status_SetErrorFormat(status, "duplicate file name (%.*s)",
+                                UPB_STRINGVIEW_ARGS(name));
+      return NULL;
+    }
+    const upb_MiniTable_File* registered = unpack_def(v, UPB_DEFTYPE_LAYOUT);
+    UPB_ASSERT(registered);
+    if (layout && layout != registered) {
+      upb_Status_SetErrorFormat(
+          status, "tried to build with a different layout (filename=%.*s)",
+          UPB_STRINGVIEW_ARGS(name));
+      return NULL;
+    }
+    layout = registered;
   }
 
   ctx.symtab = s;
-  ctx.layouts = layouts;
+  ctx.layout = layout;
+  ctx.msg_count = 0;
+  ctx.enum_count = 0;
+  ctx.ext_count = 0;
   ctx.status = status;
   ctx.file = NULL;
-  ctx.arena = upb_arena_new();
+  ctx.arena = upb_Arena_New();
+  ctx.tmp_arena = upb_Arena_New();
 
-  if (!ctx.arena) {
-    upb_status_setoom(status);
+  if (!ctx.arena || !ctx.tmp_arena) {
+    if (ctx.arena) upb_Arena_Free(ctx.arena);
+    if (ctx.tmp_arena) upb_Arena_Free(ctx.tmp_arena);
+    upb_Status_setoom(status);
     return NULL;
   }
 
   if (UPB_UNLIKELY(UPB_SETJMP(ctx.err))) {
-    UPB_ASSERT(!upb_ok(status));
+    UPB_ASSERT(!upb_Status_IsOk(status));
     if (ctx.file) {
       remove_filedef(s, ctx.file);
       ctx.file = NULL;
@@ -6521,51 +8175,52 @@
     ctx.file = symtab_alloc(&ctx, sizeof(*ctx.file));
     build_filedef(&ctx, ctx.file, file_proto);
     upb_strtable_insert(&s->files, name.data, name.size,
-                        upb_value_constptr(ctx.file), ctx.arena);
-    UPB_ASSERT(upb_ok(status));
-    upb_arena_fuse(s->arena, ctx.arena);
+                        pack_def(ctx.file, UPB_DEFTYPE_FILE), ctx.arena);
+    UPB_ASSERT(upb_Status_IsOk(status));
+    upb_Arena_Fuse(s->arena, ctx.arena);
   }
 
-  upb_arena_free(ctx.arena);
+  upb_Arena_Free(ctx.arena);
+  upb_Arena_Free(ctx.tmp_arena);
   return ctx.file;
 }
 
-const upb_filedef *upb_symtab_addfile(
-    upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto,
-    upb_status *status) {
-  return _upb_symtab_addfile(s, file_proto, NULL, status);
+const upb_FileDef* upb_DefPool_AddFile(
+    upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto,
+    upb_Status* status) {
+  return _upb_DefPool_AddFile(s, file_proto, NULL, status);
 }
 
 /* Include here since we want most of this file to be stdio-free. */
 #include <stdio.h>
 
-bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) {
+bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) {
   /* Since this function should never fail (it would indicate a bug in upb) we
    * print errors to stderr instead of returning error status to the user. */
-  upb_def_init **deps = init->deps;
-  google_protobuf_FileDescriptorProto *file;
-  upb_arena *arena;
-  upb_status status;
+  _upb_DefPool_Init** deps = init->deps;
+  google_protobuf_FileDescriptorProto* file;
+  upb_Arena* arena;
+  upb_Status status;
 
-  upb_status_clear(&status);
+  upb_Status_Clear(&status);
 
-  if (upb_strtable_lookup(&s->files, init->filename, NULL)) {
+  if (upb_DefPool_FindFileByName(s, init->filename)) {
     return true;
   }
 
-  arena = upb_arena_new();
+  arena = upb_Arena_New();
 
   for (; *deps; deps++) {
-    if (!_upb_symtab_loaddefinit(s, *deps)) goto err;
+    if (!_upb_DefPool_LoadDefInit(s, *deps)) goto err;
   }
 
   file = google_protobuf_FileDescriptorProto_parse_ex(
-      init->descriptor.data, init->descriptor.size, NULL, UPB_DECODE_ALIAS,
-      arena);
+      init->descriptor.data, init->descriptor.size, NULL,
+      kUpb_DecodeOption_AliasString, arena);
   s->bytes_loaded += init->descriptor.size;
 
   if (!file) {
-    upb_status_seterrf(
+    upb_Status_SetErrorFormat(
         &status,
         "Failed to parse compiled-in descriptor for file '%s'. This should "
         "never happen.",
@@ -6573,24 +8228,80 @@
     goto err;
   }
 
-  if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err;
+  if (!_upb_DefPool_AddFile(s, file, init->layout, &status)) {
+    goto err;
+  }
 
-  upb_arena_free(arena);
+  upb_Arena_Free(arena);
   return true;
 
 err:
-  fprintf(stderr, "Error loading compiled-in descriptor: %s\n",
-          upb_status_errmsg(&status));
-  upb_arena_free(arena);
+  fprintf(stderr,
+          "Error loading compiled-in descriptor for file '%s' (this should "
+          "never happen): %s\n",
+          init->filename, upb_Status_ErrorMessage(&status));
+  upb_Arena_Free(arena);
   return false;
 }
 
-size_t _upb_symtab_bytesloaded(const upb_symtab *s) {
+size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) {
   return s->bytes_loaded;
 }
 
-upb_arena *_upb_symtab_arena(const upb_symtab *s) {
-  return s->arena;
+upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; }
+
+const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable(
+    const upb_DefPool* s, const upb_MiniTable_Extension* ext) {
+  upb_value v;
+  bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v);
+  UPB_ASSERT(ok);
+  return upb_value_getconstptr(v);
+}
+
+const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s,
+                                                      const upb_MessageDef* m,
+                                                      int32_t fieldnum) {
+  const upb_MiniTable* l = upb_MessageDef_MiniTable(m);
+  const upb_MiniTable_Extension* ext = _upb_extreg_get(s->extreg, l, fieldnum);
+  return ext ? _upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL;
+}
+
+bool _upb_DefPool_registerlayout(upb_DefPool* s, const char* filename,
+                                 const upb_MiniTable_File* file) {
+  if (upb_DefPool_FindFileByName(s, filename)) return false;
+  upb_value v = pack_def(file, UPB_DEFTYPE_LAYOUT);
+  return upb_strtable_insert(&s->files, filename, strlen(filename), v,
+                             s->arena);
+}
+
+const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry(
+    const upb_DefPool* s) {
+  return s->extreg;
+}
+
+const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s,
+                                                  const upb_MessageDef* m,
+                                                  size_t* count) {
+  size_t n = 0;
+  intptr_t iter = UPB_INTTABLE_BEGIN;
+  uintptr_t key;
+  upb_value val;
+  // This is O(all exts) instead of O(exts for m).  If we need this to be
+  // efficient we may need to make extreg into a two-level table, or have a
+  // second per-message index.
+  while (upb_inttable_next2(&s->exts, &key, &val, &iter)) {
+    const upb_FieldDef* f = upb_value_getconstptr(val);
+    if (upb_FieldDef_ContainingType(f) == m) n++;
+  }
+  const upb_FieldDef** exts = malloc(n * sizeof(*exts));
+  iter = UPB_INTTABLE_BEGIN;
+  size_t i = 0;
+  while (upb_inttable_next2(&s->exts, &key, &val, &iter)) {
+    const upb_FieldDef* f = upb_value_getconstptr(val);
+    if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f;
+  }
+  *count = n;
+  return exts;
 }
 
 #undef CHK_OOM
@@ -6600,199 +8311,234 @@
 #include <string.h>
 
 
-static size_t get_field_size(const upb_msglayout_field *f) {
+static size_t get_field_size(const upb_MiniTable_Field* f) {
   static unsigned char sizes[] = {
-    0,/* 0 */
-    8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */
-    4, /* UPB_DESCRIPTOR_TYPE_FLOAT */
-    8, /* UPB_DESCRIPTOR_TYPE_INT64 */
-    8, /* UPB_DESCRIPTOR_TYPE_UINT64 */
-    4, /* UPB_DESCRIPTOR_TYPE_INT32 */
-    8, /* UPB_DESCRIPTOR_TYPE_FIXED64 */
-    4, /* UPB_DESCRIPTOR_TYPE_FIXED32 */
-    1, /* UPB_DESCRIPTOR_TYPE_BOOL */
-    sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING */
-    sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP */
-    sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE */
-    sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES */
-    4, /* UPB_DESCRIPTOR_TYPE_UINT32 */
-    4, /* UPB_DESCRIPTOR_TYPE_ENUM */
-    4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 */
-    8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 */
-    4, /* UPB_DESCRIPTOR_TYPE_SINT32 */
-    8, /* UPB_DESCRIPTOR_TYPE_SINT64 */
+      0,                      /* 0 */
+      8,                      /* kUpb_FieldType_Double */
+      4,                      /* kUpb_FieldType_Float */
+      8,                      /* kUpb_FieldType_Int64 */
+      8,                      /* kUpb_FieldType_UInt64 */
+      4,                      /* kUpb_FieldType_Int32 */
+      8,                      /* kUpb_FieldType_Fixed64 */
+      4,                      /* kUpb_FieldType_Fixed32 */
+      1,                      /* kUpb_FieldType_Bool */
+      sizeof(upb_StringView), /* kUpb_FieldType_String */
+      sizeof(void*),          /* kUpb_FieldType_Group */
+      sizeof(void*),          /* kUpb_FieldType_Message */
+      sizeof(upb_StringView), /* kUpb_FieldType_Bytes */
+      4,                      /* kUpb_FieldType_UInt32 */
+      4,                      /* kUpb_FieldType_Enum */
+      4,                      /* kUpb_FieldType_SFixed32 */
+      8,                      /* kUpb_FieldType_SFixed64 */
+      4,                      /* kUpb_FieldType_SInt32 */
+      8,                      /* kUpb_FieldType_SInt64 */
   };
-  return _upb_repeated_or_map(f) ? sizeof(void *) : sizes[f->descriptortype];
+  return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype];
 }
 
 /* Strings/bytes are special-cased in maps. */
-static char _upb_fieldtype_to_mapsize[12] = {
-  0,
-  1,  /* UPB_TYPE_BOOL */
-  4,  /* UPB_TYPE_FLOAT */
-  4,  /* UPB_TYPE_INT32 */
-  4,  /* UPB_TYPE_UINT32 */
-  4,  /* UPB_TYPE_ENUM */
-  sizeof(void*),  /* UPB_TYPE_MESSAGE */
-  8,  /* UPB_TYPE_DOUBLE */
-  8,  /* UPB_TYPE_INT64 */
-  8,  /* UPB_TYPE_UINT64 */
-  0,  /* UPB_TYPE_STRING */
-  0,  /* UPB_TYPE_BYTES */
+static char _upb_CTypeo_mapsize[12] = {
+    0,
+    1,             /* kUpb_CType_Bool */
+    4,             /* kUpb_CType_Float */
+    4,             /* kUpb_CType_Int32 */
+    4,             /* kUpb_CType_UInt32 */
+    4,             /* kUpb_CType_Enum */
+    sizeof(void*), /* kUpb_CType_Message */
+    8,             /* kUpb_CType_Double */
+    8,             /* kUpb_CType_Int64 */
+    8,             /* kUpb_CType_UInt64 */
+    0,             /* kUpb_CType_String */
+    0,             /* kUpb_CType_Bytes */
 };
 
-static const char _upb_fieldtype_to_sizelg2[12] = {
-  0,
-  0,  /* UPB_TYPE_BOOL */
-  2,  /* UPB_TYPE_FLOAT */
-  2,  /* UPB_TYPE_INT32 */
-  2,  /* UPB_TYPE_UINT32 */
-  2,  /* UPB_TYPE_ENUM */
-  UPB_SIZE(2, 3),  /* UPB_TYPE_MESSAGE */
-  3,  /* UPB_TYPE_DOUBLE */
-  3,  /* UPB_TYPE_INT64 */
-  3,  /* UPB_TYPE_UINT64 */
-  UPB_SIZE(3, 4),  /* UPB_TYPE_STRING */
-  UPB_SIZE(3, 4),  /* UPB_TYPE_BYTES */
+static const char _upb_CTypeo_sizelg2[12] = {
+    0,
+    0,              /* kUpb_CType_Bool */
+    2,              /* kUpb_CType_Float */
+    2,              /* kUpb_CType_Int32 */
+    2,              /* kUpb_CType_UInt32 */
+    2,              /* kUpb_CType_Enum */
+    UPB_SIZE(2, 3), /* kUpb_CType_Message */
+    3,              /* kUpb_CType_Double */
+    3,              /* kUpb_CType_Int64 */
+    3,              /* kUpb_CType_UInt64 */
+    UPB_SIZE(3, 4), /* kUpb_CType_String */
+    UPB_SIZE(3, 4), /* kUpb_CType_Bytes */
 };
 
-/** upb_msg *******************************************************************/
+/** upb_Message
+ * *******************************************************************/
 
-upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) {
-  return _upb_msg_new(upb_msgdef_layout(m), a);
+upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a) {
+  return _upb_Message_New(upb_MessageDef_MiniTable(m), a);
 }
 
-static bool in_oneof(const upb_msglayout_field *field) {
+static bool in_oneof(const upb_MiniTable_Field* field) {
   return field->presence < 0;
 }
 
-static upb_msgval _upb_msg_getraw(const upb_msg *msg, const upb_fielddef *f) {
-  const upb_msglayout_field *field = upb_fielddef_layout(f);
-  const char *mem = UPB_PTR_AT(msg, field->offset, char);
-  upb_msgval val = {0};
+static upb_MessageValue _upb_Message_Getraw(const upb_Message* msg,
+                                            const upb_FieldDef* f) {
+  const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f);
+  const char* mem = UPB_PTR_AT(msg, field->offset, char);
+  upb_MessageValue val = {0};
   memcpy(&val, mem, get_field_size(field));
   return val;
 }
 
-bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) {
-  const upb_msglayout_field *field = upb_fielddef_layout(f);
-  if (in_oneof(field)) {
-    return _upb_getoneofcase_field(msg, field) == field->number;
-  } else if (field->presence > 0) {
-    return _upb_hasbit_field(msg, field);
+bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f) {
+  assert(upb_FieldDef_HasPresence(f));
+  if (upb_FieldDef_IsExtension(f)) {
+    const upb_MiniTable_Extension* ext = _upb_FieldDef_ExtensionMiniTable(f);
+    return _upb_Message_Getext(msg, ext) != NULL;
   } else {
-    UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE ||
-               field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP);
-    return _upb_msg_getraw(msg, f).msg_val != NULL;
+    const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f);
+    if (in_oneof(field)) {
+      return _upb_getoneofcase_field(msg, field) == field->number;
+    } else if (field->presence > 0) {
+      return _upb_hasbit_field(msg, field);
+    } else {
+      UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message ||
+                 field->descriptortype == kUpb_FieldType_Group);
+      return _upb_Message_Getraw(msg, f).msg_val != NULL;
+    }
   }
 }
 
-const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg,
-                                       const upb_oneofdef *o) {
-  const upb_fielddef *f = upb_oneofdef_field(o, 0);
-  if (upb_oneofdef_issynthetic(o)) {
-    UPB_ASSERT(upb_oneofdef_fieldcount(o) == 1);
-    return upb_msg_has(msg, f) ? f : NULL;
+const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg,
+                                           const upb_OneofDef* o) {
+  const upb_FieldDef* f = upb_OneofDef_Field(o, 0);
+  if (upb_OneofDef_IsSynthetic(o)) {
+    UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1);
+    return upb_Message_Has(msg, f) ? f : NULL;
   } else {
-    const upb_msglayout_field *field = upb_fielddef_layout(f);
+    const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f);
     uint32_t oneof_case = _upb_getoneofcase_field(msg, field);
-    f = oneof_case ? upb_oneofdef_itof(o, oneof_case) : NULL;
+    f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL;
     UPB_ASSERT((f != NULL) == (oneof_case != 0));
     return f;
   }
 }
 
-upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) {
-  if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
-    return _upb_msg_getraw(msg, f);
-  } else {
-    return upb_fielddef_default(f);
+upb_MessageValue upb_Message_Get(const upb_Message* msg,
+                                 const upb_FieldDef* f) {
+  if (upb_FieldDef_IsExtension(f)) {
+    const upb_Message_Extension* ext =
+        _upb_Message_Getext(msg, _upb_FieldDef_ExtensionMiniTable(f));
+    if (ext) {
+      upb_MessageValue val;
+      memcpy(&val, &ext->data, sizeof(val));
+      return val;
+    } else if (upb_FieldDef_IsRepeated(f)) {
+      return (upb_MessageValue){.array_val = NULL};
+    }
+  } else if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) {
+    return _upb_Message_Getraw(msg, f);
   }
+  return upb_FieldDef_Default(f);
 }
 
-upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f,
-                              upb_arena *a) {
-  const upb_msglayout_field *field = upb_fielddef_layout(f);
-  upb_mutmsgval ret;
-  char *mem = UPB_PTR_AT(msg, field->offset, char);
-  bool wrong_oneof =
-      in_oneof(field) && _upb_getoneofcase_field(msg, field) != field->number;
-
-  memcpy(&ret, mem, sizeof(void*));
-
-  if (a && (!ret.msg || wrong_oneof)) {
-    if (upb_fielddef_ismap(f)) {
-      const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
-      const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
-      const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
-      ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value));
-    } else if (upb_fielddef_isseq(f)) {
-      ret.array = upb_array_new(a, upb_fielddef_type(f));
-    } else {
-      UPB_ASSERT(upb_fielddef_issubmsg(f));
-      ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a);
-    }
-
-    memcpy(mem, &ret, sizeof(void*));
-
-    if (wrong_oneof) {
-      *_upb_oneofcase_field(msg, field) = field->number;
-    } else if (field->presence > 0) {
-      _upb_sethas_field(msg, field);
-    }
+upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg,
+                                            const upb_FieldDef* f,
+                                            upb_Arena* a) {
+  UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f));
+  if (upb_FieldDef_HasPresence(f) && !upb_Message_Has(msg, f)) {
+    // We need to skip the upb_Message_Get() call in this case.
+    goto make;
   }
+
+  upb_MessageValue val = upb_Message_Get(msg, f);
+  if (val.array_val) {
+    return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val};
+  }
+
+  upb_MutableMessageValue ret;
+make:
+  if (!a) return (upb_MutableMessageValue){.array = NULL};
+  if (upb_FieldDef_IsMap(f)) {
+    const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
+    const upb_FieldDef* key = upb_MessageDef_FindFieldByNumberWithSize(
+        entry, kUpb_MapEntry_KeyFieldNumber);
+    const upb_FieldDef* value = upb_MessageDef_FindFieldByNumberWithSize(
+        entry, kUpb_MapEntry_ValueFieldNumber);
+    ret.map =
+        upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value));
+  } else if (upb_FieldDef_IsRepeated(f)) {
+    ret.array = upb_Array_New(a, upb_FieldDef_CType(f));
+  } else {
+    UPB_ASSERT(upb_FieldDef_IsSubMessage(f));
+    ret.msg = upb_Message_New(upb_FieldDef_MessageSubDef(f), a);
+  }
+
+  val.array_val = ret.array;
+  upb_Message_Set(msg, f, val, a);
+
   return ret;
 }
 
-void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
-                 upb_arena *a) {
-  const upb_msglayout_field *field = upb_fielddef_layout(f);
-  char *mem = UPB_PTR_AT(msg, field->offset, char);
-  UPB_UNUSED(a);  /* We reserve the right to make set insert into a map. */
-  memcpy(mem, &val, get_field_size(field));
-  if (field->presence > 0) {
-    _upb_sethas_field(msg, field);
-  } else if (in_oneof(field)) {
-    *_upb_oneofcase_field(msg, field) = field->number;
+bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f,
+                     upb_MessageValue val, upb_Arena* a) {
+  if (upb_FieldDef_IsExtension(f)) {
+    upb_Message_Extension* ext = _upb_Message_Getorcreateext(
+        msg, _upb_FieldDef_ExtensionMiniTable(f), a);
+    if (!ext) return false;
+    memcpy(&ext->data, &val, sizeof(val));
+  } else {
+    const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f);
+    char* mem = UPB_PTR_AT(msg, field->offset, char);
+    memcpy(mem, &val, get_field_size(field));
+    if (field->presence > 0) {
+      _upb_sethas_field(msg, field);
+    } else if (in_oneof(field)) {
+      *_upb_oneofcase_field(msg, field) = field->number;
+    }
+  }
+  return true;
+}
+
+void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f) {
+  if (upb_FieldDef_IsExtension(f)) {
+    _upb_Message_Clearext(msg, _upb_FieldDef_ExtensionMiniTable(f));
+  } else {
+    const upb_MiniTable_Field* field = upb_FieldDef_MiniTable(f);
+    char* mem = UPB_PTR_AT(msg, field->offset, char);
+
+    if (field->presence > 0) {
+      _upb_clearhas_field(msg, field);
+    } else if (in_oneof(field)) {
+      uint32_t* oneof_case = _upb_oneofcase_field(msg, field);
+      if (*oneof_case != field->number) return;
+      *oneof_case = 0;
+    }
+
+    memset(mem, 0, get_field_size(field));
   }
 }
 
-void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f) {
-  const upb_msglayout_field *field = upb_fielddef_layout(f);
-  char *mem = UPB_PTR_AT(msg, field->offset, char);
-
-  if (field->presence > 0) {
-    _upb_clearhas_field(msg, field);
-  } else if (in_oneof(field)) {
-    uint32_t *oneof_case = _upb_oneofcase_field(msg, field);
-    if (*oneof_case != field->number) return;
-    *oneof_case = 0;
-  }
-
-  memset(mem, 0, get_field_size(field));
+void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m) {
+  _upb_Message_Clear(msg, upb_MessageDef_MiniTable(m));
 }
 
-void upb_msg_clear(upb_msg *msg, const upb_msgdef *m) {
-  _upb_msg_clear(msg, upb_msgdef_layout(m));
-}
-
-bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m,
-                  const upb_symtab *ext_pool, const upb_fielddef **out_f,
-                  upb_msgval *out_val, size_t *iter) {
-  int i = *iter;
-  int n = upb_msgdef_fieldcount(m);
-  const upb_msgval zero = {0};
+bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m,
+                      const upb_DefPool* ext_pool, const upb_FieldDef** out_f,
+                      upb_MessageValue* out_val, size_t* iter) {
+  size_t i = *iter;
+  size_t n = upb_MessageDef_FieldCount(m);
+  const upb_MessageValue zero = {0};
   UPB_UNUSED(ext_pool);
+
+  /* Iterate over normal fields, returning the first one that is set. */
   while (++i < n) {
-    const upb_fielddef *f = upb_msgdef_field(m, i);
-    upb_msgval val = _upb_msg_getraw(msg, f);
+    const upb_FieldDef* f = upb_MessageDef_Field(m, i);
+    upb_MessageValue val = _upb_Message_Getraw(msg, f);
 
     /* Skip field if unset or empty. */
-    if (upb_fielddef_haspresence(f)) {
-      if (!upb_msg_has(msg, f)) continue;
+    if (upb_FieldDef_HasPresence(f)) {
+      if (!upb_Message_Has(msg, f)) continue;
     } else {
-      upb_msgval test = val;
-      if (upb_fielddef_isstring(f) && !upb_fielddef_isseq(f)) {
+      upb_MessageValue test = val;
+      if (upb_FieldDef_IsString(f) && !upb_FieldDef_IsRepeated(f)) {
         /* Clear string pointer, only size matters (ptr could be non-NULL). */
         test.str_val.data = NULL;
       }
@@ -6800,10 +8546,10 @@
       if (memcmp(&test, &zero, sizeof(test)) == 0) continue;
 
       /* Continue on empty array or map. */
-      if (upb_fielddef_ismap(f)) {
-        if (upb_map_size(test.map_val) == 0) continue;
-      } else if (upb_fielddef_isseq(f)) {
-        if (upb_array_size(test.array_val) == 0) continue;
+      if (upb_FieldDef_IsMap(f)) {
+        if (upb_Map_Size(test.map_val) == 0) continue;
+      } else if (upb_FieldDef_IsRepeated(f)) {
+        if (upb_Array_Size(test.array_val) == 0) continue;
       }
     }
 
@@ -6812,48 +8558,67 @@
     *iter = i;
     return true;
   }
+
+  if (ext_pool) {
+    /* Return any extensions that are set. */
+    size_t count;
+    const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &count);
+    if (i - n < count) {
+      ext += count - 1 - (i - n);
+      memcpy(out_val, &ext->data, sizeof(*out_val));
+      *out_f = _upb_DefPool_FindExtensionByMiniTable(ext_pool, ext->ext);
+      *iter = i;
+      return true;
+    }
+  }
+
   *iter = i;
   return false;
 }
 
-bool _upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int depth) {
-  size_t iter = UPB_MSG_BEGIN;
-  const upb_fielddef *f;
-  upb_msgval val;
+bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m,
+                                 int depth) {
+  size_t iter = kUpb_Message_Begin;
+  const upb_FieldDef* f;
+  upb_MessageValue val;
   bool ret = true;
 
   if (--depth == 0) return false;
 
-  _upb_msg_discardunknown_shallow(msg);
+  _upb_Message_DiscardUnknown_shallow(msg);
 
-  while (upb_msg_next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) {
-    const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
+  while (upb_Message_Next(msg, m, NULL /*ext_pool*/, &f, &val, &iter)) {
+    const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f);
     if (!subm) continue;
-    if (upb_fielddef_ismap(f)) {
-      const upb_fielddef *val_f = upb_msgdef_itof(subm, 2);
-      const upb_msgdef *val_m = upb_fielddef_msgsubdef(val_f);
-      upb_map *map = (upb_map*)val.map_val;
-      size_t iter = UPB_MAP_BEGIN;
+    if (upb_FieldDef_IsMap(f)) {
+      const upb_FieldDef* val_f =
+          upb_MessageDef_FindFieldByNumberWithSize(subm, 2);
+      const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f);
+      upb_Map* map = (upb_Map*)val.map_val;
+      size_t iter = kUpb_Map_Begin;
 
       if (!val_m) continue;
 
-      while (upb_mapiter_next(map, &iter)) {
-        upb_msgval map_val = upb_mapiter_value(map, iter);
-        if (!_upb_msg_discardunknown((upb_msg*)map_val.msg_val, val_m, depth)) {
+      while (upb_MapIterator_Next(map, &iter)) {
+        upb_MessageValue map_val = upb_MapIterator_Value(map, iter);
+        if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m,
+                                         depth)) {
           ret = false;
         }
       }
-    } else if (upb_fielddef_isseq(f)) {
-      const upb_array *arr = val.array_val;
-      size_t i, n = upb_array_size(arr);
+    } else if (upb_FieldDef_IsRepeated(f)) {
+      const upb_Array* arr = val.array_val;
+      size_t i, n = upb_Array_Size(arr);
       for (i = 0; i < n; i++) {
-        upb_msgval elem = upb_array_get(arr, i);
-        if (!_upb_msg_discardunknown((upb_msg*)elem.msg_val, subm, depth)) {
+        upb_MessageValue elem = upb_Array_Get(arr, i);
+        if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm,
+                                         depth)) {
           ret = false;
         }
       }
     } else {
-      if (!_upb_msg_discardunknown((upb_msg*)val.msg_val, subm, depth)) {
+      if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm,
+                                       depth)) {
         ret = false;
       }
     }
@@ -6862,22 +8627,21 @@
   return ret;
 }
 
-bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth) {
-  return _upb_msg_discardunknown(msg, m, maxdepth);
+bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m,
+                                int maxdepth) {
+  return _upb_Message_DiscardUnknown(msg, m, maxdepth);
 }
 
-/** upb_array *****************************************************************/
+/** upb_Array *****************************************************************/
 
-upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) {
-  return _upb_array_new(a, 4, _upb_fieldtype_to_sizelg2[type]);
+upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) {
+  return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]);
 }
 
-size_t upb_array_size(const upb_array *arr) {
-  return arr->len;
-}
+size_t upb_Array_Size(const upb_Array* arr) { return arr->len; }
 
-upb_msgval upb_array_get(const upb_array *arr, size_t i) {
-  upb_msgval ret;
+upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) {
+  upb_MessageValue ret;
   const char* data = _upb_array_constptr(arr);
   int lg2 = arr->data & 7;
   UPB_ASSERT(i < arr->len);
@@ -6885,86 +8649,114 @@
   return ret;
 }
 
-void upb_array_set(upb_array *arr, size_t i, upb_msgval val) {
+void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) {
   char* data = _upb_array_ptr(arr);
   int lg2 = arr->data & 7;
   UPB_ASSERT(i < arr->len);
   memcpy(data + (i << lg2), &val, 1 << lg2);
 }
 
-bool upb_array_append(upb_array *arr, upb_msgval val, upb_arena *arena) {
-  if (!upb_array_resize(arr, arr->len + 1, arena)) {
+bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) {
+  if (!upb_Array_Resize(arr, arr->len + 1, arena)) {
     return false;
   }
-  upb_array_set(arr, arr->len - 1, val);
+  upb_Array_Set(arr, arr->len - 1, val);
   return true;
 }
 
-bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) {
-  return _upb_array_resize(arr, size, arena);
+void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx,
+                    size_t count) {
+  char* data = _upb_array_ptr(arr);
+  int lg2 = arr->data & 7;
+  memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2);
 }
 
-/** upb_map *******************************************************************/
-
-upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type,
-                     upb_fieldtype_t value_type) {
-  return _upb_map_new(a, _upb_fieldtype_to_mapsize[key_type],
-                      _upb_fieldtype_to_mapsize[value_type]);
+bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count,
+                      upb_Arena* arena) {
+  UPB_ASSERT(i <= arr->len);
+  UPB_ASSERT(count + arr->len >= count);
+  size_t oldsize = arr->len;
+  if (!upb_Array_Resize(arr, arr->len + count, arena)) {
+    return false;
+  }
+  upb_Array_Move(arr, i + count, i, oldsize - i);
+  return true;
 }
 
-size_t upb_map_size(const upb_map *map) {
-  return _upb_map_size(map);
+/*
+ *              i        end      arr->len
+ * |------------|XXXXXXXX|--------|
+ */
+void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) {
+  size_t end = i + count;
+  UPB_ASSERT(i <= end);
+  UPB_ASSERT(end <= arr->len);
+  upb_Array_Move(arr, i, end, arr->len - end);
+  arr->len -= count;
 }
 
-bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) {
-  return _upb_map_get(map, &key, map->key_size, val, map->val_size);
+bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) {
+  return _upb_Array_Resize(arr, size, arena);
 }
 
-void upb_map_clear(upb_map *map) {
-  _upb_map_clear(map);
+/** upb_Map *******************************************************************/
+
+upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) {
+  return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type],
+                      _upb_CTypeo_mapsize[value_type]);
 }
 
-bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val,
-                 upb_arena *arena) {
-  return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena);
+size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); }
+
+bool upb_Map_Get(const upb_Map* map, upb_MessageValue key,
+                 upb_MessageValue* val) {
+  return _upb_Map_Get(map, &key, map->key_size, val, map->val_size);
 }
 
-bool upb_map_delete(upb_map *map, upb_msgval key) {
-  return _upb_map_delete(map, &key, map->key_size);
+void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); }
+
+bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val,
+                 upb_Arena* arena) {
+  return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena);
 }
 
-bool upb_mapiter_next(const upb_map *map, size_t *iter) {
+bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) {
+  return _upb_Map_Delete(map, &key, map->key_size);
+}
+
+bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) {
   return _upb_map_next(map, iter);
 }
 
-bool upb_mapiter_done(const upb_map *map, size_t iter) {
+bool upb_MapIterator_Done(const upb_Map* map, size_t iter) {
   upb_strtable_iter i;
-  UPB_ASSERT(iter != UPB_MAP_BEGIN);
+  UPB_ASSERT(iter != kUpb_Map_Begin);
   i.t = &map->table;
   i.index = iter;
   return upb_strtable_done(&i);
 }
 
 /* Returns the key and value for this entry of the map. */
-upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) {
+upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) {
   upb_strtable_iter i;
-  upb_msgval ret;
+  upb_MessageValue ret;
   i.t = &map->table;
   i.index = iter;
   _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size);
   return ret;
 }
 
-upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) {
+upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) {
   upb_strtable_iter i;
-  upb_msgval ret;
+  upb_MessageValue ret;
   i.t = &map->table;
   i.index = iter;
   _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size);
   return ret;
 }
 
-/* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */
+/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue
+ * value); */
 
 /** upb/json_decode.c ************************************************************/
 
@@ -6982,62 +8774,64 @@
 
 typedef struct {
   const char *ptr, *end;
-  upb_arena *arena;  /* TODO: should we have a tmp arena for tmp data? */
-  const upb_symtab *any_pool;
+  upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */
+  const upb_DefPool* symtab;
   int depth;
-  upb_status *status;
+  upb_Status* status;
   jmp_buf err;
   int line;
-  const char *line_begin;
+  const char* line_begin;
   bool is_first;
   int options;
-  const upb_fielddef *debug_field;
+  const upb_FieldDef* debug_field;
 } jsondec;
 
 enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL };
 
 /* Forward declarations of mutually-recursive functions. */
-static void jsondec_wellknown(jsondec *d, upb_msg *msg, const upb_msgdef *m);
-static upb_msgval jsondec_value(jsondec *d, const upb_fielddef *f);
-static void jsondec_wellknownvalue(jsondec *d, upb_msg *msg,
-                                   const upb_msgdef *m);
-static void jsondec_object(jsondec *d, upb_msg *msg, const upb_msgdef *m);
+static void jsondec_wellknown(jsondec* d, upb_Message* msg,
+                              const upb_MessageDef* m);
+static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f);
+static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg,
+                                   const upb_MessageDef* m);
+static void jsondec_object(jsondec* d, upb_Message* msg,
+                           const upb_MessageDef* m);
 
-static bool jsondec_streql(upb_strview str, const char *lit) {
+static bool jsondec_streql(upb_StringView str, const char* lit) {
   return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0;
 }
 
-static bool jsondec_isnullvalue(const upb_fielddef *f) {
-  return upb_fielddef_type(f) == UPB_TYPE_ENUM &&
-         strcmp(upb_enumdef_fullname(upb_fielddef_enumsubdef(f)),
+static bool jsondec_isnullvalue(const upb_FieldDef* f) {
+  return upb_FieldDef_CType(f) == kUpb_CType_Enum &&
+         strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)),
                 "google.protobuf.NullValue") == 0;
 }
 
-static bool jsondec_isvalue(const upb_fielddef *f) {
-  return (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
-          upb_msgdef_wellknowntype(upb_fielddef_msgsubdef(f)) ==
-              UPB_WELLKNOWN_VALUE) ||
+static bool jsondec_isvalue(const upb_FieldDef* f) {
+  return (upb_FieldDef_CType(f) == kUpb_CType_Message &&
+          upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) ==
+              kUpb_WellKnown_Value) ||
          jsondec_isnullvalue(f);
 }
 
-UPB_NORETURN static void jsondec_err(jsondec *d, const char *msg) {
-  upb_status_seterrf(d->status, "Error parsing JSON @%d:%d: %s", d->line,
-                     (int)(d->ptr - d->line_begin), msg);
+UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) {
+  upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line,
+                            (int)(d->ptr - d->line_begin), msg);
   UPB_LONGJMP(d->err, 1);
 }
 
 UPB_PRINTF(2, 3)
-UPB_NORETURN static void jsondec_errf(jsondec *d, const char *fmt, ...) {
+UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) {
   va_list argp;
-  upb_status_seterrf(d->status, "Error parsing JSON @%d:%d: ", d->line,
-                     (int)(d->ptr - d->line_begin));
+  upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line,
+                            (int)(d->ptr - d->line_begin));
   va_start(argp, fmt);
-  upb_status_vappenderrf(d->status, fmt, argp);
+  upb_Status_VAppendErrorFormat(d->status, fmt, argp);
   va_end(argp);
   UPB_LONGJMP(d->err, 1);
 }
 
-static void jsondec_skipws(jsondec *d) {
+static void jsondec_skipws(jsondec* d) {
   while (d->ptr != d->end) {
     switch (*d->ptr) {
       case '\n':
@@ -7056,13 +8850,13 @@
   jsondec_err(d, "Unexpected EOF");
 }
 
-static bool jsondec_tryparsech(jsondec *d, char ch) {
+static bool jsondec_tryparsech(jsondec* d, char ch) {
   if (d->ptr == d->end || *d->ptr != ch) return false;
   d->ptr++;
   return true;
 }
 
-static void jsondec_parselit(jsondec *d, const char *lit) {
+static void jsondec_parselit(jsondec* d, const char* lit) {
   size_t avail = d->end - d->ptr;
   size_t len = strlen(lit);
   if (avail < len || memcmp(d->ptr, lit, len) != 0) {
@@ -7071,23 +8865,23 @@
   d->ptr += len;
 }
 
-static void jsondec_wsch(jsondec *d, char ch) {
+static void jsondec_wsch(jsondec* d, char ch) {
   jsondec_skipws(d);
   if (!jsondec_tryparsech(d, ch)) {
     jsondec_errf(d, "Expected: '%c'", ch);
   }
 }
 
-static void jsondec_true(jsondec *d) { jsondec_parselit(d, "true"); }
-static void jsondec_false(jsondec *d) { jsondec_parselit(d, "false"); }
-static void jsondec_null(jsondec *d) { jsondec_parselit(d, "null"); }
+static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); }
+static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); }
+static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); }
 
-static void jsondec_entrysep(jsondec *d) {
+static void jsondec_entrysep(jsondec* d) {
   jsondec_skipws(d);
   jsondec_parselit(d, ":");
 }
 
-static int jsondec_rawpeek(jsondec *d) {
+static int jsondec_rawpeek(jsondec* d) {
   switch (*d->ptr) {
     case '{':
       return JD_OBJECT;
@@ -7128,19 +8922,19 @@
  * }
  * jsondec_objend(d) */
 
-static int jsondec_peek(jsondec *d) {
+static int jsondec_peek(jsondec* d) {
   jsondec_skipws(d);
   return jsondec_rawpeek(d);
 }
 
-static void jsondec_push(jsondec *d) {
+static void jsondec_push(jsondec* d) {
   if (--d->depth < 0) {
     jsondec_err(d, "Recursion limit exceeded");
   }
   d->is_first = true;
 }
 
-static bool jsondec_seqnext(jsondec *d, char end_ch) {
+static bool jsondec_seqnext(jsondec* d, char end_ch) {
   bool is_first = d->is_first;
   d->is_first = false;
   jsondec_skipws(d);
@@ -7149,31 +8943,29 @@
   return true;
 }
 
-static void jsondec_arrstart(jsondec *d) {
+static void jsondec_arrstart(jsondec* d) {
   jsondec_push(d);
   jsondec_wsch(d, '[');
 }
 
-static void jsondec_arrend(jsondec *d) {
+static void jsondec_arrend(jsondec* d) {
   d->depth++;
   jsondec_wsch(d, ']');
 }
 
-static bool jsondec_arrnext(jsondec *d) {
-  return jsondec_seqnext(d, ']');
-}
+static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); }
 
-static void jsondec_objstart(jsondec *d) {
+static void jsondec_objstart(jsondec* d) {
   jsondec_push(d);
   jsondec_wsch(d, '{');
 }
 
-static void jsondec_objend(jsondec *d) {
+static void jsondec_objend(jsondec* d) {
   d->depth++;
   jsondec_wsch(d, '}');
 }
 
-static bool jsondec_objnext(jsondec *d) {
+static bool jsondec_objnext(jsondec* d) {
   if (!jsondec_seqnext(d, '}')) return false;
   if (jsondec_peek(d) != JD_STRING) {
     jsondec_err(d, "Object must start with string");
@@ -7183,8 +8975,8 @@
 
 /* JSON number ****************************************************************/
 
-static bool jsondec_tryskipdigits(jsondec *d) {
-  const char *start = d->ptr;
+static bool jsondec_tryskipdigits(jsondec* d) {
+  const char* start = d->ptr;
 
   while (d->ptr < d->end) {
     if (*d->ptr < '0' || *d->ptr > '9') {
@@ -7196,14 +8988,14 @@
   return d->ptr != start;
 }
 
-static void jsondec_skipdigits(jsondec *d) {
+static void jsondec_skipdigits(jsondec* d) {
   if (!jsondec_tryskipdigits(d)) {
     jsondec_err(d, "Expected one or more digits");
   }
 }
 
-static double jsondec_number(jsondec *d) {
-  const char *start = d->ptr;
+static double jsondec_number(jsondec* d) {
+  const char* start = d->ptr;
 
   assert(jsondec_rawpeek(d) == JD_NUMBER);
 
@@ -7263,7 +9055,7 @@
 
 /* JSON string ****************************************************************/
 
-static char jsondec_escape(jsondec *d) {
+static char jsondec_escape(jsondec* d) {
   switch (*d->ptr++) {
     case '"':
       return '\"';
@@ -7286,9 +9078,9 @@
   }
 }
 
-static uint32_t jsondec_codepoint(jsondec *d) {
+static uint32_t jsondec_codepoint(jsondec* d) {
   uint32_t cp = 0;
-  const char *end;
+  const char* end;
 
   if (d->end - d->ptr < 4) {
     jsondec_err(d, "EOF inside string");
@@ -7313,7 +9105,7 @@
 }
 
 /* Parses a \uXXXX unicode escape (possibly a surrogate pair). */
-static size_t jsondec_unicode(jsondec *d, char* out) {
+static size_t jsondec_unicode(jsondec* d, char* out) {
   uint32_t cp = jsondec_codepoint(d);
   if (cp >= 0xd800 && cp <= 0xdbff) {
     /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */
@@ -7355,22 +9147,22 @@
   }
 }
 
-static void jsondec_resize(jsondec *d, char **buf, char **end, char **buf_end) {
+static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) {
   size_t oldsize = *buf_end - *buf;
   size_t len = *end - *buf;
   size_t size = UPB_MAX(8, 2 * oldsize);
 
-  *buf = upb_arena_realloc(d->arena, *buf, len, size);
+  *buf = upb_Arena_Realloc(d->arena, *buf, len, size);
   if (!*buf) jsondec_err(d, "Out of memory");
 
   *end = *buf + len;
   *buf_end = *buf + size;
 }
 
-static upb_strview jsondec_string(jsondec *d) {
-  char *buf = NULL;
-  char *end = NULL;
-  char *buf_end = NULL;
+static upb_StringView jsondec_string(jsondec* d) {
+  char* buf = NULL;
+  char* end = NULL;
+  char* buf_end = NULL;
 
   jsondec_skipws(d);
 
@@ -7387,10 +9179,10 @@
 
     switch (ch) {
       case '"': {
-        upb_strview ret;
+        upb_StringView ret;
         ret.data = buf;
         ret.size = end - buf;
-        *end = '\0';  /* Needed for possible strtod(). */
+        *end = '\0'; /* Needed for possible strtod(). */
         return ret;
       }
       case '\\':
@@ -7419,7 +9211,7 @@
   jsondec_err(d, "EOF inside string");
 }
 
-static void jsondec_skipval(jsondec *d) {
+static void jsondec_skipval(jsondec* d) {
   switch (jsondec_peek(d)) {
     case JD_OBJECT:
       jsondec_objstart(d);
@@ -7502,8 +9294,8 @@
   return table[(unsigned)ch];
 }
 
-static char *jsondec_partialbase64(jsondec *d, const char *ptr, const char *end,
-                                   char *out) {
+static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end,
+                                   char* out) {
   int32_t val = -1;
 
   switch (end - ptr) {
@@ -7530,13 +9322,13 @@
   return out;
 }
 
-static size_t jsondec_base64(jsondec *d, upb_strview str) {
+static size_t jsondec_base64(jsondec* d, upb_StringView str) {
   /* We decode in place. This is safe because this is a new buffer (not
    * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */
-  char *out = (char*)str.data;
-  const char *ptr = str.data;
-  const char *end = ptr + str.size;
-  const char *end4 = ptr + (str.size & -4);  /* Round down to multiple of 4. */
+  char* out = (char*)str.data;
+  const char* ptr = str.data;
+  const char* end = ptr + str.size;
+  const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */
 
   for (; ptr < end4; ptr += 4, out += 3) {
     int val = jsondec_base64_tablelookup(ptr[0]) << 18 |
@@ -7574,8 +9366,8 @@
 /* We use these hand-written routines instead of strto[u]l() because the "long
  * long" variants aren't in c89. Also our version allows setting a ptr limit. */
 
-static const char *jsondec_buftouint64(jsondec *d, const char *ptr,
-                                       const char *end, uint64_t *val) {
+static const char* jsondec_buftouint64(jsondec* d, const char* ptr,
+                                       const char* end, uint64_t* val) {
   uint64_t u64 = 0;
   while (ptr < end) {
     unsigned ch = *ptr - '0';
@@ -7592,8 +9384,8 @@
   return ptr;
 }
 
-static const char *jsondec_buftoint64(jsondec *d, const char *ptr,
-                                      const char *end, int64_t *val) {
+static const char* jsondec_buftoint64(jsondec* d, const char* ptr,
+                                      const char* end, int64_t* val) {
   bool neg = false;
   uint64_t u64;
 
@@ -7611,8 +9403,8 @@
   return ptr;
 }
 
-static uint64_t jsondec_strtouint64(jsondec *d, upb_strview str) {
-  const char *end = str.data + str.size;
+static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) {
+  const char* end = str.data + str.size;
   uint64_t ret;
   if (jsondec_buftouint64(d, str.data, end, &ret) != end) {
     jsondec_err(d, "Non-number characters in quoted integer");
@@ -7620,8 +9412,8 @@
   return ret;
 }
 
-static int64_t jsondec_strtoint64(jsondec *d, upb_strview str) {
-  const char *end = str.data + str.size;
+static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) {
+  const char* end = str.data + str.size;
   int64_t ret;
   if (jsondec_buftoint64(d, str.data, end, &ret) != end) {
     jsondec_err(d, "Non-number characters in quoted integer");
@@ -7632,8 +9424,8 @@
 /* Primitive value types ******************************************************/
 
 /* Parse INT32 or INT64 value. */
-static upb_msgval jsondec_int(jsondec *d, const upb_fielddef *f) {
-  upb_msgval val;
+static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) {
+  upb_MessageValue val;
 
   switch (jsondec_peek(d)) {
     case JD_NUMBER: {
@@ -7641,7 +9433,7 @@
       if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) {
         jsondec_err(d, "JSON number is out of range.");
       }
-      val.int64_val = dbl;  /* must be guarded, overflow here is UB */
+      val.int64_val = dbl; /* must be guarded, overflow here is UB */
       if (val.int64_val != dbl) {
         jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl,
                      val.int64_val);
@@ -7649,7 +9441,7 @@
       break;
     }
     case JD_STRING: {
-      upb_strview str = jsondec_string(d);
+      upb_StringView str = jsondec_string(d);
       val.int64_val = jsondec_strtoint64(d, str);
       break;
     }
@@ -7657,7 +9449,8 @@
       jsondec_err(d, "Expected number or string");
   }
 
-  if (upb_fielddef_type(f) == UPB_TYPE_INT32) {
+  if (upb_FieldDef_CType(f) == kUpb_CType_Int32 ||
+      upb_FieldDef_CType(f) == kUpb_CType_Enum) {
     if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) {
       jsondec_err(d, "Integer out of range.");
     }
@@ -7668,8 +9461,8 @@
 }
 
 /* Parse UINT32 or UINT64 value. */
-static upb_msgval jsondec_uint(jsondec *d, const upb_fielddef *f) {
-  upb_msgval val = {0};
+static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) {
+  upb_MessageValue val = {0};
 
   switch (jsondec_peek(d)) {
     case JD_NUMBER: {
@@ -7677,7 +9470,7 @@
       if (dbl > 18446744073709549568.0 || dbl < 0) {
         jsondec_err(d, "JSON number is out of range.");
       }
-      val.uint64_val = dbl;  /* must be guarded, overflow here is UB */
+      val.uint64_val = dbl; /* must be guarded, overflow here is UB */
       if (val.uint64_val != dbl) {
         jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl,
                      val.uint64_val);
@@ -7685,7 +9478,7 @@
       break;
     }
     case JD_STRING: {
-      upb_strview str = jsondec_string(d);
+      upb_StringView str = jsondec_string(d);
       val.uint64_val = jsondec_strtouint64(d, str);
       break;
     }
@@ -7693,7 +9486,7 @@
       jsondec_err(d, "Expected number or string");
   }
 
-  if (upb_fielddef_type(f) == UPB_TYPE_UINT32) {
+  if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) {
     if (val.uint64_val > UINT32_MAX) {
       jsondec_err(d, "Integer out of range.");
     }
@@ -7704,9 +9497,9 @@
 }
 
 /* Parse DOUBLE or FLOAT value. */
-static upb_msgval jsondec_double(jsondec *d, const upb_fielddef *f) {
-  upb_strview str;
-  upb_msgval val = {0};
+static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) {
+  upb_StringView str;
+  upb_MessageValue val = {0};
 
   switch (jsondec_peek(d)) {
     case JD_NUMBER:
@@ -7728,7 +9521,7 @@
       jsondec_err(d, "Expected number or string");
   }
 
-  if (upb_fielddef_type(f) == UPB_TYPE_FLOAT) {
+  if (upb_FieldDef_CType(f) == kUpb_CType_Float) {
     if (val.double_val != INFINITY && val.double_val != -INFINITY &&
         (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) {
       jsondec_err(d, "Float out of range");
@@ -7740,34 +9533,38 @@
 }
 
 /* Parse STRING or BYTES value. */
-static upb_msgval jsondec_strfield(jsondec *d, const upb_fielddef *f) {
-  upb_msgval val;
+static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) {
+  upb_MessageValue val;
   val.str_val = jsondec_string(d);
-  if (upb_fielddef_type(f) == UPB_TYPE_BYTES) {
+  if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) {
     val.str_val.size = jsondec_base64(d, val.str_val);
   }
   return val;
 }
 
-static upb_msgval jsondec_enum(jsondec *d, const upb_fielddef *f) {
+static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) {
   switch (jsondec_peek(d)) {
     case JD_STRING: {
-      const upb_enumdef *e = upb_fielddef_enumsubdef(f);
-      upb_strview str = jsondec_string(d);
-      upb_msgval val;
-      if (!upb_enumdef_ntoi(e, str.data, str.size, &val.int32_val)) {
-        if (d->options & UPB_JSONDEC_IGNOREUNKNOWN) {
+      upb_StringView str = jsondec_string(d);
+      const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f);
+      const upb_EnumValueDef* ev =
+          upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size);
+      upb_MessageValue val;
+      if (ev) {
+        val.int32_val = upb_EnumValueDef_Number(ev);
+      } else {
+        if (d->options & upb_JsonDecode_IgnoreUnknown) {
           val.int32_val = 0;
         } else {
-          jsondec_errf(d, "Unknown enumerator: '" UPB_STRVIEW_FORMAT "'",
-                       UPB_STRVIEW_ARGS(str));
+          jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'",
+                       UPB_STRINGVIEW_ARGS(str));
         }
       }
       return val;
     }
     case JD_NULL: {
       if (jsondec_isnullvalue(f)) {
-        upb_msgval val;
+        upb_MessageValue val;
         jsondec_null(d);
         val.int32_val = 0;
         return val;
@@ -7779,13 +9576,13 @@
   }
 }
 
-static upb_msgval jsondec_bool(jsondec *d, const upb_fielddef *f) {
-  bool is_map_key = upb_fielddef_number(f) == 1 &&
-                    upb_msgdef_mapentry(upb_fielddef_containingtype(f));
-  upb_msgval val;
+static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) {
+  bool is_map_key = upb_FieldDef_Number(f) == 1 &&
+                    upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f));
+  upb_MessageValue val;
 
   if (is_map_key) {
-    upb_strview str = jsondec_string(d);
+    upb_StringView str = jsondec_string(d);
     if (jsondec_streql(str, "true")) {
       val.bool_val = true;
     } else if (jsondec_streql(str, "false")) {
@@ -7813,65 +9610,83 @@
 
 /* Composite types (array/message/map) ****************************************/
 
-static void jsondec_array(jsondec *d, upb_msg *msg, const upb_fielddef *f) {
-  upb_array *arr = upb_msg_mutable(msg, f, d->arena).array;
+static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
+  upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array;
 
   jsondec_arrstart(d);
   while (jsondec_arrnext(d)) {
-    upb_msgval elem = jsondec_value(d, f);
-    upb_array_append(arr, elem, d->arena);
+    upb_MessageValue elem = jsondec_value(d, f);
+    upb_Array_Append(arr, elem, d->arena);
   }
   jsondec_arrend(d);
 }
 
-static void jsondec_map(jsondec *d, upb_msg *msg, const upb_fielddef *f) {
-  upb_map *map = upb_msg_mutable(msg, f, d->arena).map;
-  const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
-  const upb_fielddef *key_f = upb_msgdef_itof(entry, 1);
-  const upb_fielddef *val_f = upb_msgdef_itof(entry, 2);
+static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) {
+  upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map;
+  const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
+  const upb_FieldDef* key_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry, 1);
+  const upb_FieldDef* val_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry, 2);
 
   jsondec_objstart(d);
   while (jsondec_objnext(d)) {
-    upb_msgval key, val;
+    upb_MessageValue key, val;
     key = jsondec_value(d, key_f);
     jsondec_entrysep(d);
     val = jsondec_value(d, val_f);
-    upb_map_set(map, key, val, d->arena);
+    upb_Map_Set(map, key, val, d->arena);
   }
   jsondec_objend(d);
 }
 
-static void jsondec_tomsg(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  if (upb_msgdef_wellknowntype(m) == UPB_WELLKNOWN_UNSPECIFIED) {
+static void jsondec_tomsg(jsondec* d, upb_Message* msg,
+                          const upb_MessageDef* m) {
+  if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) {
     jsondec_object(d, msg, m);
   } else {
     jsondec_wellknown(d, msg, m);
   }
 }
 
-static upb_msgval jsondec_msg(jsondec *d, const upb_fielddef *f) {
-  const upb_msgdef *m = upb_fielddef_msgsubdef(f);
-  upb_msg *msg = upb_msg_new(m, d->arena);
-  upb_msgval val;
+static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) {
+  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
+  upb_Message* msg = upb_Message_New(m, d->arena);
+  upb_MessageValue val;
 
   jsondec_tomsg(d, msg, m);
   val.msg_val = msg;
   return val;
 }
 
-static void jsondec_field(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  upb_strview name;
-  const upb_fielddef *f;
-  const upb_fielddef *preserved;
+static void jsondec_field(jsondec* d, upb_Message* msg,
+                          const upb_MessageDef* m) {
+  upb_StringView name;
+  const upb_FieldDef* f;
+  const upb_FieldDef* preserved;
 
   name = jsondec_string(d);
   jsondec_entrysep(d);
-  f = upb_msgdef_lookupjsonname(m, name.data, name.size);
+
+  if (name.size >= 2 && name.data[0] == '[' &&
+      name.data[name.size - 1] == ']') {
+    f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1,
+                                                name.size - 2);
+    if (f && upb_FieldDef_ContainingType(f) != m) {
+      jsondec_errf(
+          d, "Extension %s extends message %s, but was seen in message %s",
+          upb_FieldDef_FullName(f),
+          upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)),
+          upb_MessageDef_FullName(m));
+    }
+  } else {
+    f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size);
+  }
 
   if (!f) {
-    if ((d->options & UPB_JSONDEC_IGNOREUNKNOWN) == 0) {
-      jsondec_errf(d, "No such field: " UPB_STRVIEW_FORMAT,
-                   UPB_STRVIEW_ARGS(name));
+    if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) {
+      jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT,
+                   UPB_STRINGVIEW_ARGS(name));
     }
     jsondec_skipval(d);
     return;
@@ -7883,31 +9698,32 @@
     return;
   }
 
-  if (upb_fielddef_realcontainingoneof(f) &&
-      upb_msg_whichoneof(msg, upb_fielddef_containingoneof(f))) {
+  if (upb_FieldDef_RealContainingOneof(f) &&
+      upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) {
     jsondec_err(d, "More than one field for this oneof.");
   }
 
   preserved = d->debug_field;
   d->debug_field = f;
 
-  if (upb_fielddef_ismap(f)) {
+  if (upb_FieldDef_IsMap(f)) {
     jsondec_map(d, msg, f);
-  } else if (upb_fielddef_isseq(f)) {
+  } else if (upb_FieldDef_IsRepeated(f)) {
     jsondec_array(d, msg, f);
-  } else if (upb_fielddef_issubmsg(f)) {
-    upb_msg *submsg = upb_msg_mutable(msg, f, d->arena).msg;
-    const upb_msgdef *subm = upb_fielddef_msgsubdef(f);
+  } else if (upb_FieldDef_IsSubMessage(f)) {
+    upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg;
+    const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f);
     jsondec_tomsg(d, submsg, subm);
   } else {
-    upb_msgval val = jsondec_value(d, f);
-    upb_msg_set(msg, f, val, d->arena);
+    upb_MessageValue val = jsondec_value(d, f);
+    upb_Message_Set(msg, f, val, d->arena);
   }
 
   d->debug_field = preserved;
 }
 
-static void jsondec_object(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+static void jsondec_object(jsondec* d, upb_Message* msg,
+                           const upb_MessageDef* m) {
   jsondec_objstart(d);
   while (jsondec_objnext(d)) {
     jsondec_field(d, msg, m);
@@ -7915,25 +9731,25 @@
   jsondec_objend(d);
 }
 
-static upb_msgval jsondec_value(jsondec *d, const upb_fielddef *f) {
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_BOOL:
+static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) {
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Bool:
       return jsondec_bool(d, f);
-    case UPB_TYPE_FLOAT:
-    case UPB_TYPE_DOUBLE:
+    case kUpb_CType_Float:
+    case kUpb_CType_Double:
       return jsondec_double(d, f);
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_UInt64:
       return jsondec_uint(d, f);
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_INT64:
+    case kUpb_CType_Int32:
+    case kUpb_CType_Int64:
       return jsondec_int(d, f);
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       return jsondec_strfield(d, f);
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Enum:
       return jsondec_enum(d, f);
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       return jsondec_msg(d, f);
     default:
       UPB_UNREACHABLE();
@@ -7942,14 +9758,14 @@
 
 /* Well-known types ***********************************************************/
 
-static int jsondec_tsdigits(jsondec *d, const char **ptr, size_t digits,
-                            const char *after) {
+static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits,
+                            const char* after) {
   uint64_t val;
-  const char *p = *ptr;
-  const char *end = p + digits;
+  const char* p = *ptr;
+  const char* end = p + digits;
   size_t after_len = after ? strlen(after) : 0;
 
-  UPB_ASSERT(digits <= 9);  /* int can't overflow. */
+  UPB_ASSERT(digits <= 9); /* int can't overflow. */
 
   if (jsondec_buftouint64(d, p, end, &val) != end ||
       (after_len && memcmp(end, after, after_len) != 0)) {
@@ -7962,12 +9778,12 @@
   return (int)val;
 }
 
-static int jsondec_nanos(jsondec *d, const char **ptr, const char *end) {
+static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) {
   uint64_t nanos = 0;
-  const char *p = *ptr;
+  const char* p = *ptr;
 
   if (p != end && *p == '.') {
-    const char *nano_end = jsondec_buftouint64(d, p + 1, end, &nanos);
+    const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos);
     int digits = (int)(nano_end - p - 1);
     int exp_lg10 = 9 - digits;
     if (digits > 9) {
@@ -7984,8 +9800,8 @@
 
 /* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */
 int jsondec_epochdays(int y, int m, int d) {
-  const uint32_t year_base = 4800;    /* Before min year, multiple of 400. */
-  const uint32_t m_adj = m - 3;       /* March-based month. */
+  const uint32_t year_base = 4800; /* Before min year, multiple of 400. */
+  const uint32_t m_adj = m - 3;    /* March-based month. */
   const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0;
   const uint32_t adjust = carry ? 12 : 0;
   const uint32_t y_adj = y + year_base - carry;
@@ -7998,12 +9814,13 @@
   return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s;
 }
 
-static void jsondec_timestamp(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  upb_msgval seconds;
-  upb_msgval nanos;
-  upb_strview str = jsondec_string(d);
-  const char *ptr = str.data;
-  const char *end = ptr + str.size;
+static void jsondec_timestamp(jsondec* d, upb_Message* msg,
+                              const upb_MessageDef* m) {
+  upb_MessageValue seconds;
+  upb_MessageValue nanos;
+  upb_StringView str = jsondec_string(d);
+  const char* ptr = str.data;
+  const char* end = ptr + str.size;
 
   if (str.size < 20) goto malformed;
 
@@ -8052,20 +9869,23 @@
     jsondec_err(d, "Timestamp out of range");
   }
 
-  upb_msg_set(msg, upb_msgdef_itof(m, 1), seconds, d->arena);
-  upb_msg_set(msg, upb_msgdef_itof(m, 2), nanos, d->arena);
+  upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 1), seconds,
+                  d->arena);
+  upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 2), nanos,
+                  d->arena);
   return;
 
 malformed:
   jsondec_err(d, "Malformed timestamp");
 }
 
-static void jsondec_duration(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  upb_msgval seconds;
-  upb_msgval nanos;
-  upb_strview str = jsondec_string(d);
-  const char *ptr = str.data;
-  const char *end = ptr + str.size;
+static void jsondec_duration(jsondec* d, upb_Message* msg,
+                             const upb_MessageDef* m) {
+  upb_MessageValue seconds;
+  upb_MessageValue nanos;
+  upb_StringView str = jsondec_string(d);
+  const char* ptr = str.data;
+  const char* end = ptr + str.size;
   const int64_t max = (uint64_t)3652500 * 86400;
 
   /* "3.000000001s", "3s", etc. */
@@ -8081,110 +9901,116 @@
   }
 
   if (seconds.int64_val < 0) {
-    nanos.int32_val = - nanos.int32_val;
+    nanos.int32_val = -nanos.int32_val;
   }
 
-  upb_msg_set(msg, upb_msgdef_itof(m, 1), seconds, d->arena);
-  upb_msg_set(msg, upb_msgdef_itof(m, 2), nanos, d->arena);
+  upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 1), seconds,
+                  d->arena);
+  upb_Message_Set(msg, upb_MessageDef_FindFieldByNumberWithSize(m, 2), nanos,
+                  d->arena);
 }
 
-static void jsondec_listvalue(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  const upb_fielddef *values_f = upb_msgdef_itof(m, 1);
-  const upb_msgdef *value_m = upb_fielddef_msgsubdef(values_f);
-  upb_array *values = upb_msg_mutable(msg, values_f, d->arena).array;
+static void jsondec_listvalue(jsondec* d, upb_Message* msg,
+                              const upb_MessageDef* m) {
+  const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f);
+  upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array;
 
   jsondec_arrstart(d);
   while (jsondec_arrnext(d)) {
-    upb_msg *value_msg = upb_msg_new(value_m, d->arena);
-    upb_msgval value;
+    upb_Message* value_msg = upb_Message_New(value_m, d->arena);
+    upb_MessageValue value;
     value.msg_val = value_msg;
-    upb_array_append(values, value, d->arena);
+    upb_Array_Append(values, value, d->arena);
     jsondec_wellknownvalue(d, value_msg, value_m);
   }
   jsondec_arrend(d);
 }
 
-static void jsondec_struct(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  const upb_fielddef *fields_f = upb_msgdef_itof(m, 1);
-  const upb_msgdef *entry_m = upb_fielddef_msgsubdef(fields_f);
-  const upb_fielddef *value_f = upb_msgdef_itof(entry_m, 2);
-  const upb_msgdef *value_m = upb_fielddef_msgsubdef(value_f);
-  upb_map *fields = upb_msg_mutable(msg, fields_f, d->arena).map;
+static void jsondec_struct(jsondec* d, upb_Message* msg,
+                           const upb_MessageDef* m) {
+  const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f);
+  const upb_FieldDef* value_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2);
+  const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f);
+  upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map;
 
   jsondec_objstart(d);
   while (jsondec_objnext(d)) {
-    upb_msgval key, value;
-    upb_msg *value_msg = upb_msg_new(value_m, d->arena);
+    upb_MessageValue key, value;
+    upb_Message* value_msg = upb_Message_New(value_m, d->arena);
     key.str_val = jsondec_string(d);
     value.msg_val = value_msg;
-    upb_map_set(fields, key, value, d->arena);
+    upb_Map_Set(fields, key, value, d->arena);
     jsondec_entrysep(d);
     jsondec_wellknownvalue(d, value_msg, value_m);
   }
   jsondec_objend(d);
 }
 
-static void jsondec_wellknownvalue(jsondec *d, upb_msg *msg,
-                                   const upb_msgdef *m) {
-  upb_msgval val;
-  const upb_fielddef *f;
-  upb_msg *submsg;
+static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg,
+                                   const upb_MessageDef* m) {
+  upb_MessageValue val;
+  const upb_FieldDef* f;
+  upb_Message* submsg;
 
   switch (jsondec_peek(d)) {
     case JD_NUMBER:
       /* double number_value = 2; */
-      f = upb_msgdef_itof(m, 2);
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
       val.double_val = jsondec_number(d);
       break;
     case JD_STRING:
       /* string string_value = 3; */
-      f = upb_msgdef_itof(m, 3);
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 3);
       val.str_val = jsondec_string(d);
       break;
     case JD_FALSE:
       /* bool bool_value = 4; */
-      f = upb_msgdef_itof(m, 4);
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 4);
       val.bool_val = false;
       jsondec_false(d);
       break;
     case JD_TRUE:
       /* bool bool_value = 4; */
-      f = upb_msgdef_itof(m, 4);
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 4);
       val.bool_val = true;
       jsondec_true(d);
       break;
     case JD_NULL:
       /* NullValue null_value = 1; */
-      f = upb_msgdef_itof(m, 1);
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
       val.int32_val = 0;
       jsondec_null(d);
       break;
-    /* Note: these cases return, because upb_msg_mutable() is enough. */
+    /* Note: these cases return, because upb_Message_Mutable() is enough. */
     case JD_OBJECT:
       /* Struct struct_value = 5; */
-      f = upb_msgdef_itof(m, 5);
-      submsg = upb_msg_mutable(msg, f, d->arena).msg;
-      jsondec_struct(d, submsg, upb_fielddef_msgsubdef(f));
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 5);
+      submsg = upb_Message_Mutable(msg, f, d->arena).msg;
+      jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f));
       return;
     case JD_ARRAY:
       /* ListValue list_value = 6; */
-      f = upb_msgdef_itof(m, 6);
-      submsg = upb_msg_mutable(msg, f, d->arena).msg;
-      jsondec_listvalue(d, submsg, upb_fielddef_msgsubdef(f));
+      f = upb_MessageDef_FindFieldByNumberWithSize(m, 6);
+      submsg = upb_Message_Mutable(msg, f, d->arena).msg;
+      jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f));
       return;
     default:
       UPB_UNREACHABLE();
   }
 
-  upb_msg_set(msg, f, val, d->arena);
+  upb_Message_Set(msg, f, val, d->arena);
 }
 
-static upb_strview jsondec_mask(jsondec *d, const char *buf, const char *end) {
+static upb_StringView jsondec_mask(jsondec* d, const char* buf,
+                                   const char* end) {
   /* FieldMask fields grow due to inserted '_' characters, so we can't do the
    * transform in place. */
-  const char *ptr = buf;
-  upb_strview ret;
-  char *out;
+  const char* ptr = buf;
+  upb_StringView ret;
+  char* out;
 
   ret.size = end - ptr;
   while (ptr < end) {
@@ -8192,7 +10018,7 @@
     ptr++;
   }
 
-  out = upb_arena_malloc(d->arena, ret.size);
+  out = upb_Arena_Malloc(d->arena, ret.size);
   ptr = buf;
   ret.data = out;
 
@@ -8211,17 +10037,18 @@
   return ret;
 }
 
-static void jsondec_fieldmask(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+static void jsondec_fieldmask(jsondec* d, upb_Message* msg,
+                              const upb_MessageDef* m) {
   /* repeated string paths = 1; */
-  const upb_fielddef *paths_f = upb_msgdef_itof(m, 1);
-  upb_array *arr = upb_msg_mutable(msg, paths_f, d->arena).array;
-  upb_strview str = jsondec_string(d);
-  const char *ptr = str.data;
-  const char *end = ptr + str.size;
-  upb_msgval val;
+  const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array;
+  upb_StringView str = jsondec_string(d);
+  const char* ptr = str.data;
+  const char* end = ptr + str.size;
+  upb_MessageValue val;
 
   while (ptr < end) {
-    const char *elem_end = memchr(ptr, ',', end - ptr);
+    const char* elem_end = memchr(ptr, ',', end - ptr);
     if (elem_end) {
       val.str_val = jsondec_mask(d, ptr, elem_end);
       ptr = elem_end + 1;
@@ -8229,19 +10056,20 @@
       val.str_val = jsondec_mask(d, ptr, end);
       ptr = end;
     }
-    upb_array_append(arr, val, d->arena);
+    upb_Array_Append(arr, val, d->arena);
   }
 }
 
-static void jsondec_anyfield(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  if (upb_msgdef_wellknowntype(m) == UPB_WELLKNOWN_UNSPECIFIED) {
+static void jsondec_anyfield(jsondec* d, upb_Message* msg,
+                             const upb_MessageDef* m) {
+  if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) {
     /* For regular types: {"@type": "[user type]", "f1": <V1>, "f2": <V2>}
      * where f1, f2, etc. are the normal fields of this type. */
     jsondec_field(d, msg, m);
   } else {
     /* For well-known types: {"@type": "[well-known type]", "value": <X>}
      * where <X> is whatever encoding the WKT normally uses. */
-    upb_strview str = jsondec_string(d);
+    upb_StringView str = jsondec_string(d);
     jsondec_entrysep(d);
     if (!jsondec_streql(str, "value")) {
       jsondec_err(d, "Key for well-known type must be 'value'");
@@ -8250,27 +10078,29 @@
   }
 }
 
-static const upb_msgdef *jsondec_typeurl(jsondec *d, upb_msg *msg,
-                                         const upb_msgdef *m) {
-  const upb_fielddef *type_url_f = upb_msgdef_itof(m, 1);
-  const upb_msgdef *type_m;
-  upb_strview type_url = jsondec_string(d);
-  const char *end = type_url.data + type_url.size;
-  const char *ptr = end;
-  upb_msgval val;
+static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg,
+                                             const upb_MessageDef* m) {
+  const upb_FieldDef* type_url_f =
+      upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_MessageDef* type_m;
+  upb_StringView type_url = jsondec_string(d);
+  const char* end = type_url.data + type_url.size;
+  const char* ptr = end;
+  upb_MessageValue val;
 
   val.str_val = type_url;
-  upb_msg_set(msg, type_url_f, val, d->arena);
+  upb_Message_Set(msg, type_url_f, val, d->arena);
 
   /* Find message name after the last '/' */
-  while (ptr > type_url.data && *--ptr != '/') {}
+  while (ptr > type_url.data && *--ptr != '/') {
+  }
 
   if (ptr == type_url.data || ptr == end) {
     jsondec_err(d, "Type url must have at least one '/' and non-empty host");
   }
 
   ptr++;
-  type_m = upb_symtab_lookupmsg2(d->any_pool, ptr, end - ptr);
+  type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr);
 
   if (!type_m) {
     jsondec_err(d, "Type was not found");
@@ -8279,22 +10109,22 @@
   return type_m;
 }
 
-static void jsondec_any(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
+static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) {
   /* string type_url = 1;
    * bytes value = 2; */
-  const upb_fielddef *value_f = upb_msgdef_itof(m, 2);
-  upb_msg *any_msg;
-  const upb_msgdef *any_m = NULL;
-  const char *pre_type_data = NULL;
-  const char *pre_type_end = NULL;
-  upb_msgval encoded;
+  const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
+  upb_Message* any_msg;
+  const upb_MessageDef* any_m = NULL;
+  const char* pre_type_data = NULL;
+  const char* pre_type_end = NULL;
+  upb_MessageValue encoded;
 
   jsondec_objstart(d);
 
   /* Scan looking for "@type", which is not necessarily first. */
   while (!any_m && jsondec_objnext(d)) {
-    const char *start = d->ptr;
-    upb_strview name = jsondec_string(d);
+    const char* start = d->ptr;
+    upb_StringView name = jsondec_string(d);
     jsondec_entrysep(d);
     if (jsondec_streql(name, "@type")) {
       any_m = jsondec_typeurl(d, msg, m);
@@ -8312,13 +10142,13 @@
     jsondec_err(d, "Any object didn't contain a '@type' field");
   }
 
-  any_msg = upb_msg_new(any_m, d->arena);
+  any_msg = upb_Message_New(any_m, d->arena);
 
   if (pre_type_data) {
     size_t len = pre_type_end - pre_type_data + 1;
-    char *tmp = upb_arena_malloc(d->arena, len);
-    const char *saved_ptr = d->ptr;
-    const char *saved_end = d->end;
+    char* tmp = upb_Arena_Malloc(d->arena, len);
+    const char* saved_ptr = d->ptr;
+    const char* saved_end = d->end;
     memcpy(tmp, pre_type_data, len - 1);
     tmp[len - 1] = '}';
     d->ptr = tmp;
@@ -8337,49 +10167,51 @@
 
   jsondec_objend(d);
 
-  encoded.str_val.data = upb_encode(any_msg, upb_msgdef_layout(any_m), d->arena,
-                                    &encoded.str_val.size);
-  upb_msg_set(msg, value_f, encoded, d->arena);
+  encoded.str_val.data = upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0,
+                                    d->arena, &encoded.str_val.size);
+  upb_Message_Set(msg, value_f, encoded, d->arena);
 }
 
-static void jsondec_wrapper(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  const upb_fielddef *value_f = upb_msgdef_itof(m, 1);
-  upb_msgval val = jsondec_value(d, value_f);
-  upb_msg_set(msg, value_f, val, d->arena);
+static void jsondec_wrapper(jsondec* d, upb_Message* msg,
+                            const upb_MessageDef* m) {
+  const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  upb_MessageValue val = jsondec_value(d, value_f);
+  upb_Message_Set(msg, value_f, val, d->arena);
 }
 
-static void jsondec_wellknown(jsondec *d, upb_msg *msg, const upb_msgdef *m) {
-  switch (upb_msgdef_wellknowntype(m)) {
-    case UPB_WELLKNOWN_ANY:
+static void jsondec_wellknown(jsondec* d, upb_Message* msg,
+                              const upb_MessageDef* m) {
+  switch (upb_MessageDef_WellKnownType(m)) {
+    case kUpb_WellKnown_Any:
       jsondec_any(d, msg, m);
       break;
-    case UPB_WELLKNOWN_FIELDMASK:
+    case kUpb_WellKnown_FieldMask:
       jsondec_fieldmask(d, msg, m);
       break;
-    case UPB_WELLKNOWN_DURATION:
+    case kUpb_WellKnown_Duration:
       jsondec_duration(d, msg, m);
       break;
-    case UPB_WELLKNOWN_TIMESTAMP:
+    case kUpb_WellKnown_Timestamp:
       jsondec_timestamp(d, msg, m);
       break;
-    case UPB_WELLKNOWN_VALUE:
+    case kUpb_WellKnown_Value:
       jsondec_wellknownvalue(d, msg, m);
       break;
-    case UPB_WELLKNOWN_LISTVALUE:
+    case kUpb_WellKnown_ListValue:
       jsondec_listvalue(d, msg, m);
       break;
-    case UPB_WELLKNOWN_STRUCT:
+    case kUpb_WellKnown_Struct:
       jsondec_struct(d, msg, m);
       break;
-    case UPB_WELLKNOWN_DOUBLEVALUE:
-    case UPB_WELLKNOWN_FLOATVALUE:
-    case UPB_WELLKNOWN_INT64VALUE:
-    case UPB_WELLKNOWN_UINT64VALUE:
-    case UPB_WELLKNOWN_INT32VALUE:
-    case UPB_WELLKNOWN_UINT32VALUE:
-    case UPB_WELLKNOWN_STRINGVALUE:
-    case UPB_WELLKNOWN_BYTESVALUE:
-    case UPB_WELLKNOWN_BOOLVALUE:
+    case kUpb_WellKnown_DoubleValue:
+    case kUpb_WellKnown_FloatValue:
+    case kUpb_WellKnown_Int64Value:
+    case kUpb_WellKnown_UInt64Value:
+    case kUpb_WellKnown_Int32Value:
+    case kUpb_WellKnown_UInt32Value:
+    case kUpb_WellKnown_StringValue:
+    case kUpb_WellKnown_BytesValue:
+    case kUpb_WellKnown_BoolValue:
       jsondec_wrapper(d, msg, m);
       break;
     default:
@@ -8387,9 +10219,9 @@
   }
 }
 
-bool upb_json_decode(const char *buf, size_t size, upb_msg *msg,
-                     const upb_msgdef *m, const upb_symtab *any_pool,
-                     int options, upb_arena *arena, upb_status *status) {
+bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg,
+                    const upb_MessageDef* m, const upb_DefPool* symtab,
+                    int options, upb_Arena* arena, upb_Status* status) {
   jsondec d;
 
   if (size == 0) return true;
@@ -8397,7 +10229,7 @@
   d.ptr = buf;
   d.end = buf + size;
   d.arena = arena;
-  d.any_pool = any_pool;
+  d.symtab = symtab;
   d.status = status;
   d.options = options;
   d.depth = 64;
@@ -8431,43 +10263,46 @@
   size_t overflow;
   int indent_depth;
   int options;
-  const upb_symtab *ext_pool;
+  const upb_DefPool* ext_pool;
   jmp_buf err;
-  upb_status *status;
-  upb_arena *arena;
+  upb_Status* status;
+  upb_Arena* arena;
 } jsonenc;
 
-static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
-static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f);
-static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg,
-                             const upb_msgdef *m);
-static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
-                              const upb_msgdef *m, bool first);
-static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m);
+static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
+                        const upb_MessageDef* m);
+static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
+                           const upb_FieldDef* f);
+static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
+                             const upb_MessageDef* m);
+static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
+                              const upb_MessageDef* m, bool first);
+static void jsonenc_value(jsonenc* e, const upb_Message* msg,
+                          const upb_MessageDef* m);
 
-UPB_NORETURN static void jsonenc_err(jsonenc *e, const char *msg) {
-  upb_status_seterrmsg(e->status, msg);
+UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) {
+  upb_Status_SetErrorMessage(e->status, msg);
   longjmp(e->err, 1);
 }
 
 UPB_PRINTF(2, 3)
-UPB_NORETURN static void jsonenc_errf(jsonenc *e, const char *fmt, ...) {
+UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) {
   va_list argp;
   va_start(argp, fmt);
-  upb_status_vseterrf(e->status, fmt, argp);
+  upb_Status_VSetErrorFormat(e->status, fmt, argp);
   va_end(argp);
   longjmp(e->err, 1);
 }
 
-static upb_arena *jsonenc_arena(jsonenc *e) {
+static upb_Arena* jsonenc_arena(jsonenc* e) {
   /* Create lazily, since it's only needed for Any */
   if (!e->arena) {
-    e->arena = upb_arena_new();
+    e->arena = upb_Arena_New();
   }
   return e->arena;
 }
 
-static void jsonenc_putbytes(jsonenc *e, const void *data, size_t len) {
+static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) {
   size_t have = e->end - e->ptr;
   if (UPB_LIKELY(have >= len)) {
     memcpy(e->ptr, data, len);
@@ -8481,12 +10316,12 @@
   }
 }
 
-static void jsonenc_putstr(jsonenc *e, const char *str) {
+static void jsonenc_putstr(jsonenc* e, const char* str) {
   jsonenc_putbytes(e, str, strlen(str));
 }
 
 UPB_PRINTF(2, 3)
-static void jsonenc_printf(jsonenc *e, const char *fmt, ...) {
+static void jsonenc_printf(jsonenc* e, const char* fmt, ...) {
   size_t n;
   size_t have = e->end - e->ptr;
   va_list args;
@@ -8503,7 +10338,7 @@
   }
 }
 
-static void jsonenc_nanos(jsonenc *e, int32_t nanos) {
+static void jsonenc_nanos(jsonenc* e, int32_t nanos) {
   int digits = 9;
 
   if (nanos == 0) return;
@@ -8519,12 +10354,13 @@
   jsonenc_printf(e, ".%.*" PRId32, digits, nanos);
 }
 
-static void jsonenc_timestamp(jsonenc *e, const upb_msg *msg,
-                              const upb_msgdef *m) {
-  const upb_fielddef *seconds_f = upb_msgdef_itof(m, 1);
-  const upb_fielddef *nanos_f = upb_msgdef_itof(m, 2);
-  int64_t seconds = upb_msg_get(msg, seconds_f).int64_val;
-  int32_t nanos = upb_msg_get(msg, nanos_f).int32_val;
+static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg,
+                              const upb_MessageDef* m) {
+  const upb_FieldDef* seconds_f =
+      upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
+  int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val;
+  int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val;
   int L, N, I, J, K, hour, min, sec;
 
   if (seconds < -62135596800) {
@@ -8561,11 +10397,13 @@
   jsonenc_putstr(e, "Z\"");
 }
 
-static void jsonenc_duration(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
-  const upb_fielddef *seconds_f = upb_msgdef_itof(m, 1);
-  const upb_fielddef *nanos_f = upb_msgdef_itof(m, 2);
-  int64_t seconds = upb_msg_get(msg, seconds_f).int64_val;
-  int32_t nanos = upb_msg_get(msg, nanos_f).int32_val;
+static void jsonenc_duration(jsonenc* e, const upb_Message* msg,
+                             const upb_MessageDef* m) {
+  const upb_FieldDef* seconds_f =
+      upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
+  int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val;
+  int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val;
 
   if (seconds > 315576000000 || seconds < -315576000000 ||
       (seconds < 0) != (nanos < 0)) {
@@ -8581,28 +10419,28 @@
   jsonenc_putstr(e, "s\"");
 }
 
-static void jsonenc_enum(int32_t val, const upb_fielddef *f, jsonenc *e) {
-  const upb_enumdef *e_def = upb_fielddef_enumsubdef(f);
+static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) {
+  const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f);
 
-  if (strcmp(upb_enumdef_fullname(e_def), "google.protobuf.NullValue") == 0) {
+  if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) {
     jsonenc_putstr(e, "null");
   } else {
-    const char *name = upb_enumdef_iton(e_def, val);
+    const upb_EnumValueDef* ev = upb_EnumDef_FindValueByNumber(e_def, val);
 
-    if (name) {
-      jsonenc_printf(e, "\"%s\"", name);
+    if (ev) {
+      jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev));
     } else {
       jsonenc_printf(e, "%" PRId32, val);
     }
   }
 }
 
-static void jsonenc_bytes(jsonenc *e, upb_strview str) {
+static void jsonenc_bytes(jsonenc* e, upb_StringView str) {
   /* This is the regular base64, not the "web-safe" version. */
   static const char base64[] =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  const unsigned char *ptr = (unsigned char*)str.data;
-  const unsigned char *end = UPB_PTRADD(ptr, str.size);
+  const unsigned char* ptr = (unsigned char*)str.data;
+  const unsigned char* end = UPB_PTRADD(ptr, str.size);
   char buf[4];
 
   jsonenc_putstr(e, "\"");
@@ -8636,9 +10474,9 @@
   jsonenc_putstr(e, "\"");
 }
 
-static void jsonenc_stringbody(jsonenc *e, upb_strview str) {
-  const char *ptr = str.data;
-  const char *end = UPB_PTRADD(ptr, str.size);
+static void jsonenc_stringbody(jsonenc* e, upb_StringView str) {
+  const char* ptr = str.data;
+  const char* end = UPB_PTRADD(ptr, str.size);
 
   while (ptr < end) {
     switch (*ptr) {
@@ -8677,13 +10515,13 @@
   }
 }
 
-static void jsonenc_string(jsonenc *e, upb_strview str) {
+static void jsonenc_string(jsonenc* e, upb_StringView str) {
   jsonenc_putstr(e, "\"");
   jsonenc_stringbody(e, str);
   jsonenc_putstr(e, "\"");
 }
 
-static void jsonenc_double(jsonenc *e, const char *fmt, double val) {
+static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) {
   if (val == INFINITY) {
     jsonenc_putstr(e, "\"Infinity\"");
   } else if (val == -INFINITY) {
@@ -8691,32 +10529,38 @@
   } else if (val != val) {
     jsonenc_putstr(e, "\"NaN\"");
   } else {
-    char *p = e->ptr;
-    jsonenc_printf(e, fmt, val);
-
-    /* printf() is dependent on locales; sadly there is no easy and portable way
-     * to avoid this. This little post-processing step will translate 1,2 -> 1.2
-     * since JSON needs the latter. Arguably a hack, but it is simple and the
-     * alternatives are far more complicated, platform-dependent, and/or larger
-     * in code size. */
-    for (char *end = e->ptr; p < end; p++) {
-      if (*p == ',') *p = '.';
-    }
+    return false;
   }
+  return true;
 }
 
-static void jsonenc_wrapper(jsonenc *e, const upb_msg *msg,
-                            const upb_msgdef *m) {
-  const upb_fielddef *val_f = upb_msgdef_itof(m, 1);
-  upb_msgval val = upb_msg_get(msg, val_f);
+static void upb_JsonEncode_Double(jsonenc* e, double val) {
+  if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
+  char buf[32];
+  _upb_EncodeRoundTripDouble(val, buf, sizeof(buf));
+  jsonenc_putstr(e, buf);
+}
+
+static void upb_JsonEncode_Float(jsonenc* e, float val) {
+  if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return;
+  char buf[32];
+  _upb_EncodeRoundTripFloat(val, buf, sizeof(buf));
+  jsonenc_putstr(e, buf);
+}
+
+static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg,
+                            const upb_MessageDef* m) {
+  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  upb_MessageValue val = upb_Message_Get(msg, val_f);
   jsonenc_scalar(e, val, val_f);
 }
 
-static const upb_msgdef *jsonenc_getanymsg(jsonenc *e, upb_strview type_url) {
+static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e,
+                                               upb_StringView type_url) {
   /* Find last '/', if any. */
-  const char *end = type_url.data + type_url.size;
-  const char *ptr = end;
-  const upb_msgdef *ret;
+  const char* end = type_url.data + type_url.size;
+  const char* ptr = end;
+  const upb_MessageDef* ret;
 
   if (!e->ext_pool) {
     jsonenc_err(e, "Tried to encode Any, but no symtab was provided");
@@ -8735,7 +10579,7 @@
     }
   }
 
-  ret = upb_symtab_lookupmsg2(e->ext_pool, ptr, end - ptr);
+  ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr);
 
   if (!ret) {
     jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr);
@@ -8744,28 +10588,31 @@
   return ret;
 
 badurl:
-  jsonenc_errf(
-      e, "Bad type URL: " UPB_STRVIEW_FORMAT, UPB_STRVIEW_ARGS(type_url));
+  jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT,
+               UPB_STRINGVIEW_ARGS(type_url));
 }
 
-static void jsonenc_any(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
-  const upb_fielddef *type_url_f = upb_msgdef_itof(m, 1);
-  const upb_fielddef *value_f = upb_msgdef_itof(m, 2);
-  upb_strview type_url = upb_msg_get(msg, type_url_f).str_val;
-  upb_strview value = upb_msg_get(msg, value_f).str_val;
-  const upb_msgdef *any_m = jsonenc_getanymsg(e, type_url);
-  const upb_msglayout *any_layout = upb_msgdef_layout(any_m);
-  upb_arena *arena = jsonenc_arena(e);
-  upb_msg *any = upb_msg_new(any_m, arena);
+static void jsonenc_any(jsonenc* e, const upb_Message* msg,
+                        const upb_MessageDef* m) {
+  const upb_FieldDef* type_url_f =
+      upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumberWithSize(m, 2);
+  upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val;
+  upb_StringView value = upb_Message_Get(msg, value_f).str_val;
+  const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url);
+  const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m);
+  upb_Arena* arena = jsonenc_arena(e);
+  upb_Message* any = upb_Message_New(any_m, arena);
 
-  if (!upb_decode(value.data, value.size, any, any_layout, arena)) {
+  if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) !=
+      kUpb_DecodeStatus_Ok) {
     jsonenc_err(e, "Error decoding message in Any");
   }
 
   jsonenc_putstr(e, "{\"@type\":");
   jsonenc_string(e, type_url);
 
-  if (upb_msgdef_wellknowntype(any_m) == UPB_WELLKNOWN_UNSPECIFIED) {
+  if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) {
     /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */
     jsonenc_msgfields(e, any, any_m, false);
   } else {
@@ -8777,7 +10624,7 @@
   jsonenc_putstr(e, "}");
 }
 
-static void jsonenc_putsep(jsonenc *e, const char *str, bool *first) {
+static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) {
   if (*first) {
     *first = false;
   } else {
@@ -8785,9 +10632,9 @@
   }
 }
 
-static void jsonenc_fieldpath(jsonenc *e, upb_strview path) {
-  const char *ptr = path.data;
-  const char *end = ptr + path.size;
+static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) {
+  const char* ptr = path.data;
+  const char* end = ptr + path.size;
 
   while (ptr < end) {
     char ch = *ptr;
@@ -8806,65 +10653,66 @@
   }
 }
 
-static void jsonenc_fieldmask(jsonenc *e, const upb_msg *msg,
-                              const upb_msgdef *m) {
-  const upb_fielddef *paths_f = upb_msgdef_itof(m, 1);
-  const upb_array *paths = upb_msg_get(msg, paths_f).array_val;
+static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg,
+                              const upb_MessageDef* m) {
+  const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val;
   bool first = true;
   size_t i, n = 0;
 
-  if (paths) n = upb_array_size(paths);
+  if (paths) n = upb_Array_Size(paths);
 
   jsonenc_putstr(e, "\"");
 
   for (i = 0; i < n; i++) {
     jsonenc_putsep(e, ",", &first);
-    jsonenc_fieldpath(e, upb_array_get(paths, i).str_val);
+    jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val);
   }
 
   jsonenc_putstr(e, "\"");
 }
 
-static void jsonenc_struct(jsonenc *e, const upb_msg *msg,
-                           const upb_msgdef *m) {
-  const upb_fielddef *fields_f = upb_msgdef_itof(m, 1);
-  const upb_map *fields = upb_msg_get(msg, fields_f).map_val;
-  const upb_msgdef *entry_m = upb_fielddef_msgsubdef(fields_f);
-  const upb_fielddef *value_f = upb_msgdef_itof(entry_m, 2);
-  size_t iter = UPB_MAP_BEGIN;
+static void jsonenc_struct(jsonenc* e, const upb_Message* msg,
+                           const upb_MessageDef* m) {
+  const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val;
+  const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f);
+  const upb_FieldDef* value_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry_m, 2);
+  size_t iter = kUpb_Map_Begin;
   bool first = true;
 
   jsonenc_putstr(e, "{");
 
   if (fields) {
-    while (upb_mapiter_next(fields, &iter)) {
-      upb_msgval key = upb_mapiter_key(fields, iter);
-      upb_msgval val = upb_mapiter_value(fields, iter);
+    while (upb_MapIterator_Next(fields, &iter)) {
+      upb_MessageValue key = upb_MapIterator_Key(fields, iter);
+      upb_MessageValue val = upb_MapIterator_Value(fields, iter);
 
       jsonenc_putsep(e, ",", &first);
       jsonenc_string(e, key.str_val);
       jsonenc_putstr(e, ":");
-      jsonenc_value(e, val.msg_val, upb_fielddef_msgsubdef(value_f));
+      jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f));
     }
   }
 
   jsonenc_putstr(e, "}");
 }
 
-static void jsonenc_listvalue(jsonenc *e, const upb_msg *msg,
-                              const upb_msgdef *m) {
-  const upb_fielddef *values_f = upb_msgdef_itof(m, 1);
-  const upb_msgdef *values_m = upb_fielddef_msgsubdef(values_f);
-  const upb_array *values = upb_msg_get(msg, values_f).array_val;
+static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg,
+                              const upb_MessageDef* m) {
+  const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumberWithSize(m, 1);
+  const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f);
+  const upb_Array* values = upb_Message_Get(msg, values_f).array_val;
   size_t i;
   bool first = true;
 
   jsonenc_putstr(e, "[");
 
   if (values) {
-    const size_t size = upb_array_size(values);
+    const size_t size = upb_Array_Size(values);
     for (i = 0; i < size; i++) {
-      upb_msgval elem = upb_array_get(values, i);
+      upb_MessageValue elem = upb_Array_Get(values, i);
 
       jsonenc_putsep(e, ",", &first);
       jsonenc_value(e, elem.msg_val, values_m);
@@ -8874,22 +10722,23 @@
   jsonenc_putstr(e, "]");
 }
 
-static void jsonenc_value(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+static void jsonenc_value(jsonenc* e, const upb_Message* msg,
+                          const upb_MessageDef* m) {
   /* TODO(haberman): do we want a reflection method to get oneof case? */
-  size_t iter = UPB_MSG_BEGIN;
-  const upb_fielddef *f;
-  upb_msgval val;
+  size_t iter = kUpb_Message_Begin;
+  const upb_FieldDef* f;
+  upb_MessageValue val;
 
-  if (!upb_msg_next(msg, m, NULL,  &f, &val, &iter)) {
+  if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) {
     jsonenc_err(e, "No value set in Value proto");
   }
 
-  switch (upb_fielddef_number(f)) {
+  switch (upb_FieldDef_Number(f)) {
     case 1:
       jsonenc_putstr(e, "null");
       break;
     case 2:
-      jsonenc_double(e, "%.17g", val.double_val);
+      upb_JsonEncode_Double(e, val.double_val);
       break;
     case 3:
       jsonenc_string(e, val.str_val);
@@ -8898,113 +10747,115 @@
       jsonenc_putstr(e, val.bool_val ? "true" : "false");
       break;
     case 5:
-      jsonenc_struct(e, val.msg_val, upb_fielddef_msgsubdef(f));
+      jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
       break;
     case 6:
-      jsonenc_listvalue(e, val.msg_val, upb_fielddef_msgsubdef(f));
+      jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
       break;
   }
 }
 
-static void jsonenc_msgfield(jsonenc *e, const upb_msg *msg,
-                             const upb_msgdef *m) {
-  switch (upb_msgdef_wellknowntype(m)) {
-    case UPB_WELLKNOWN_UNSPECIFIED:
+static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg,
+                             const upb_MessageDef* m) {
+  switch (upb_MessageDef_WellKnownType(m)) {
+    case kUpb_WellKnown_Unspecified:
       jsonenc_msg(e, msg, m);
       break;
-    case UPB_WELLKNOWN_ANY:
+    case kUpb_WellKnown_Any:
       jsonenc_any(e, msg, m);
       break;
-    case UPB_WELLKNOWN_FIELDMASK:
+    case kUpb_WellKnown_FieldMask:
       jsonenc_fieldmask(e, msg, m);
       break;
-    case UPB_WELLKNOWN_DURATION:
+    case kUpb_WellKnown_Duration:
       jsonenc_duration(e, msg, m);
       break;
-    case UPB_WELLKNOWN_TIMESTAMP:
+    case kUpb_WellKnown_Timestamp:
       jsonenc_timestamp(e, msg, m);
       break;
-    case UPB_WELLKNOWN_DOUBLEVALUE:
-    case UPB_WELLKNOWN_FLOATVALUE:
-    case UPB_WELLKNOWN_INT64VALUE:
-    case UPB_WELLKNOWN_UINT64VALUE:
-    case UPB_WELLKNOWN_INT32VALUE:
-    case UPB_WELLKNOWN_UINT32VALUE:
-    case UPB_WELLKNOWN_STRINGVALUE:
-    case UPB_WELLKNOWN_BYTESVALUE:
-    case UPB_WELLKNOWN_BOOLVALUE:
+    case kUpb_WellKnown_DoubleValue:
+    case kUpb_WellKnown_FloatValue:
+    case kUpb_WellKnown_Int64Value:
+    case kUpb_WellKnown_UInt64Value:
+    case kUpb_WellKnown_Int32Value:
+    case kUpb_WellKnown_UInt32Value:
+    case kUpb_WellKnown_StringValue:
+    case kUpb_WellKnown_BytesValue:
+    case kUpb_WellKnown_BoolValue:
       jsonenc_wrapper(e, msg, m);
       break;
-    case UPB_WELLKNOWN_VALUE:
+    case kUpb_WellKnown_Value:
       jsonenc_value(e, msg, m);
       break;
-    case UPB_WELLKNOWN_LISTVALUE:
+    case kUpb_WellKnown_ListValue:
       jsonenc_listvalue(e, msg, m);
       break;
-    case UPB_WELLKNOWN_STRUCT:
+    case kUpb_WellKnown_Struct:
       jsonenc_struct(e, msg, m);
       break;
   }
 }
 
-static void jsonenc_scalar(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_BOOL:
+static void jsonenc_scalar(jsonenc* e, upb_MessageValue val,
+                           const upb_FieldDef* f) {
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Bool:
       jsonenc_putstr(e, val.bool_val ? "true" : "false");
       break;
-    case UPB_TYPE_FLOAT:
-      jsonenc_double(e, "%.9g", val.float_val);
+    case kUpb_CType_Float:
+      upb_JsonEncode_Float(e, val.float_val);
       break;
-    case UPB_TYPE_DOUBLE:
-      jsonenc_double(e, "%.17g", val.double_val);
+    case kUpb_CType_Double:
+      upb_JsonEncode_Double(e, val.double_val);
       break;
-    case UPB_TYPE_INT32:
+    case kUpb_CType_Int32:
       jsonenc_printf(e, "%" PRId32, val.int32_val);
       break;
-    case UPB_TYPE_UINT32:
+    case kUpb_CType_UInt32:
       jsonenc_printf(e, "%" PRIu32, val.uint32_val);
       break;
-    case UPB_TYPE_INT64:
+    case kUpb_CType_Int64:
       jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val);
       break;
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_UInt64:
       jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val);
       break;
-    case UPB_TYPE_STRING:
+    case kUpb_CType_String:
       jsonenc_string(e, val.str_val);
       break;
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_Bytes:
       jsonenc_bytes(e, val.str_val);
       break;
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Enum:
       jsonenc_enum(val.int32_val, f, e);
       break;
-    case UPB_TYPE_MESSAGE:
-      jsonenc_msgfield(e, val.msg_val, upb_fielddef_msgsubdef(f));
+    case kUpb_CType_Message:
+      jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f));
       break;
   }
 }
 
-static void jsonenc_mapkey(jsonenc *e, upb_msgval val, const upb_fielddef *f) {
+static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val,
+                           const upb_FieldDef* f) {
   jsonenc_putstr(e, "\"");
 
-  switch (upb_fielddef_type(f)) {
-    case UPB_TYPE_BOOL:
+  switch (upb_FieldDef_CType(f)) {
+    case kUpb_CType_Bool:
       jsonenc_putstr(e, val.bool_val ? "true" : "false");
       break;
-    case UPB_TYPE_INT32:
+    case kUpb_CType_Int32:
       jsonenc_printf(e, "%" PRId32, val.int32_val);
       break;
-    case UPB_TYPE_UINT32:
+    case kUpb_CType_UInt32:
       jsonenc_printf(e, "%" PRIu32, val.uint32_val);
       break;
-    case UPB_TYPE_INT64:
+    case kUpb_CType_Int64:
       jsonenc_printf(e, "%" PRId64, val.int64_val);
       break;
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_UInt64:
       jsonenc_printf(e, "%" PRIu64, val.uint64_val);
       break;
-    case UPB_TYPE_STRING:
+    case kUpb_CType_String:
       jsonenc_stringbody(e, val.str_val);
       break;
     default:
@@ -9014,95 +10865,105 @@
   jsonenc_putstr(e, "\":");
 }
 
-static void jsonenc_array(jsonenc *e, const upb_array *arr,
-                         const upb_fielddef *f) {
+static void jsonenc_array(jsonenc* e, const upb_Array* arr,
+                          const upb_FieldDef* f) {
   size_t i;
-  size_t size = arr ? upb_array_size(arr) : 0;
+  size_t size = arr ? upb_Array_Size(arr) : 0;
   bool first = true;
 
   jsonenc_putstr(e, "[");
 
   for (i = 0; i < size; i++) {
     jsonenc_putsep(e, ",", &first);
-    jsonenc_scalar(e, upb_array_get(arr, i), f);
+    jsonenc_scalar(e, upb_Array_Get(arr, i), f);
   }
 
   jsonenc_putstr(e, "]");
 }
 
-static void jsonenc_map(jsonenc *e, const upb_map *map, const upb_fielddef *f) {
-  const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
-  const upb_fielddef *key_f = upb_msgdef_itof(entry, 1);
-  const upb_fielddef *val_f = upb_msgdef_itof(entry, 2);
-  size_t iter = UPB_MAP_BEGIN;
+static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) {
+  const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
+  const upb_FieldDef* key_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry, 1);
+  const upb_FieldDef* val_f =
+      upb_MessageDef_FindFieldByNumberWithSize(entry, 2);
+  size_t iter = kUpb_Map_Begin;
   bool first = true;
 
   jsonenc_putstr(e, "{");
 
   if (map) {
-    while (upb_mapiter_next(map, &iter)) {
+    while (upb_MapIterator_Next(map, &iter)) {
       jsonenc_putsep(e, ",", &first);
-      jsonenc_mapkey(e, upb_mapiter_key(map, iter), key_f);
-      jsonenc_scalar(e, upb_mapiter_value(map, iter), val_f);
+      jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f);
+      jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f);
     }
   }
 
   jsonenc_putstr(e, "}");
 }
 
-static void jsonenc_fieldval(jsonenc *e, const upb_fielddef *f,
-                             upb_msgval val, bool *first) {
-  const char *name;
-
-  if (e->options & UPB_JSONENC_PROTONAMES) {
-    name = upb_fielddef_name(f);
-  } else {
-    name = upb_fielddef_jsonname(f);
-  }
+static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f,
+                             upb_MessageValue val, bool* first) {
+  const char* name;
 
   jsonenc_putsep(e, ",", first);
-  jsonenc_printf(e, "\"%s\":", name);
 
-  if (upb_fielddef_ismap(f)) {
+  if (upb_FieldDef_IsExtension(f)) {
+    // TODO: For MessageSet, I would have expected this to print the message
+    // name here, but Python doesn't appear to do this. We should do more
+    // research here about what various implementations do.
+    jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f));
+  } else {
+    if (e->options & upb_JsonEncode_UseProtoNames) {
+      name = upb_FieldDef_Name(f);
+    } else {
+      name = upb_FieldDef_JsonName(f);
+    }
+    jsonenc_printf(e, "\"%s\":", name);
+  }
+
+  if (upb_FieldDef_IsMap(f)) {
     jsonenc_map(e, val.map_val, f);
-  } else if (upb_fielddef_isseq(f)) {
+  } else if (upb_FieldDef_IsRepeated(f)) {
     jsonenc_array(e, val.array_val, f);
   } else {
     jsonenc_scalar(e, val, f);
   }
 }
 
-static void jsonenc_msgfields(jsonenc *e, const upb_msg *msg,
-                              const upb_msgdef *m, bool first) {
-  upb_msgval val;
-  const upb_fielddef *f;
+static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg,
+                              const upb_MessageDef* m, bool first) {
+  upb_MessageValue val;
+  const upb_FieldDef* f;
 
-  if (e->options & UPB_JSONENC_EMITDEFAULTS) {
+  if (e->options & upb_JsonEncode_EmitDefaults) {
     /* Iterate over all fields. */
     int i = 0;
-    int n = upb_msgdef_fieldcount(m);
+    int n = upb_MessageDef_FieldCount(m);
     for (i = 0; i < n; i++) {
-      f = upb_msgdef_field(m, i);
-      if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) {
-        jsonenc_fieldval(e, f, upb_msg_get(msg, f), &first);
+      f = upb_MessageDef_Field(m, i);
+      if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) {
+        jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first);
       }
     }
   } else {
     /* Iterate over non-empty fields. */
-    size_t iter = UPB_MSG_BEGIN;
-    while (upb_msg_next(msg, m, e->ext_pool, &f, &val, &iter)) {
+    size_t iter = kUpb_Message_Begin;
+    while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) {
       jsonenc_fieldval(e, f, val, &first);
     }
   }
 }
 
-static void jsonenc_msg(jsonenc *e, const upb_msg *msg, const upb_msgdef *m) {
+static void jsonenc_msg(jsonenc* e, const upb_Message* msg,
+                        const upb_MessageDef* m) {
   jsonenc_putstr(e, "{");
   jsonenc_msgfields(e, msg, m, true);
   jsonenc_putstr(e, "}");
 }
 
-static size_t jsonenc_nullz(jsonenc *e, size_t size) {
+static size_t jsonenc_nullz(jsonenc* e, size_t size) {
   size_t ret = e->ptr - e->buf + e->overflow;
 
   if (size > 0) {
@@ -9113,9 +10974,9 @@
   return ret;
 }
 
-size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m,
-                       const upb_symtab *ext_pool, int options, char *buf,
-                       size_t size, upb_status *status) {
+size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m,
+                      const upb_DefPool* ext_pool, int options, char* buf,
+                      size_t size, upb_Status* status) {
   jsonenc e;
 
   e.buf = buf;
@@ -9130,7 +10991,7 @@
   if (setjmp(e.err)) return -1;
 
   jsonenc_msgfield(&e, msg, m);
-  if (e.arena) upb_arena_free(e.arena);
+  if (e.arena) upb_Arena_Free(e.arena);
   return jsonenc_nullz(&e, size);
 }
 
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h
index 4007277..369861c 100755
--- a/ruby/ext/google/protobuf_c/ruby-upb.h
+++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -255,7 +255,7 @@
 
 /** upb/decode.h ************************************************************/
 /*
- * upb_decode: parsing into a upb_msg using a upb_msglayout.
+ * upb_decode: parsing into a upb_Message using a upb_MiniTable.
  */
 
 #ifndef UPB_DECODE_H_
@@ -297,54 +297,56 @@
 extern "C" {
 #endif
 
-/* upb_status *****************************************************************/
+/* upb_Status *****************************************************************/
 
-#define UPB_STATUS_MAX_MESSAGE 127
+#define _kUpb_Status_MaxMessage 127
 
 typedef struct {
   bool ok;
-  char msg[UPB_STATUS_MAX_MESSAGE];  /* Error message; NULL-terminated. */
-} upb_status;
+  char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */
+} upb_Status;
 
-const char *upb_status_errmsg(const upb_status *status);
-bool upb_ok(const upb_status *status);
+const char* upb_Status_ErrorMessage(const upb_Status* status);
+bool upb_Status_IsOk(const upb_Status* status);
 
 /* These are no-op if |status| is NULL. */
-void upb_status_clear(upb_status *status);
-void upb_status_seterrmsg(upb_status *status, const char *msg);
-void upb_status_seterrf(upb_status *status, const char *fmt, ...)
+void upb_Status_Clear(upb_Status* status);
+void upb_Status_SetErrorMessage(upb_Status* status, const char* msg);
+void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...)
     UPB_PRINTF(2, 3);
-void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args)
-    UPB_PRINTF(2, 0);
-void upb_status_vappenderrf(upb_status *status, const char *fmt, va_list args)
-    UPB_PRINTF(2, 0);
+void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
+                                va_list args) UPB_PRINTF(2, 0);
+void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
+                                   va_list args) UPB_PRINTF(2, 0);
 
-/** upb_strview ************************************************************/
+/** upb_StringView ************************************************************/
 
 typedef struct {
-  const char *data;
+  const char* data;
   size_t size;
-} upb_strview;
+} upb_StringView;
 
-UPB_INLINE upb_strview upb_strview_make(const char *data, size_t size) {
-  upb_strview ret;
+UPB_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data,
+                                                         size_t size) {
+  upb_StringView ret;
   ret.data = data;
   ret.size = size;
   return ret;
 }
 
-UPB_INLINE upb_strview upb_strview_makez(const char *data) {
-  return upb_strview_make(data, strlen(data));
+UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) {
+  return upb_StringView_FromDataAndSize(data, strlen(data));
 }
 
-UPB_INLINE bool upb_strview_eql(upb_strview a, upb_strview b) {
+UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) {
   return a.size == b.size && memcmp(a.data, b.data, a.size) == 0;
 }
 
-#define UPB_STRVIEW_INIT(ptr, len) {ptr, len}
+#define UPB_STRINGVIEW_INIT(ptr, len) \
+  { ptr, len }
 
-#define UPB_STRVIEW_FORMAT "%.*s"
-#define UPB_STRVIEW_ARGS(view) (int)(view).size, (view).data
+#define UPB_STRINGVIEW_FORMAT "%.*s"
+#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data
 
 /** upb_alloc *****************************************************************/
 
@@ -360,25 +362,25 @@
 /* A malloc()/free() function.
  * If "size" is 0 then the function acts like free(), otherwise it acts like
  * realloc().  Only "oldsize" bytes from a previous allocation are preserved. */
-typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize,
+typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize,
                              size_t size);
 
 struct upb_alloc {
-  upb_alloc_func *func;
+  upb_alloc_func* func;
 };
 
-UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) {
+UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) {
   UPB_ASSERT(alloc);
   return alloc->func(alloc, NULL, 0, size);
 }
 
-UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize,
                              size_t size) {
   UPB_ASSERT(alloc);
   return alloc->func(alloc, ptr, oldsize, size);
 }
 
-UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) {
+UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) {
   assert(alloc);
   alloc->func(alloc, ptr, 0, 0);
 }
@@ -392,69 +394,67 @@
  * We still get benefit because we can put custom logic into our global
  * allocator, like injecting out-of-memory faults in debug/testing builds. */
 
-UPB_INLINE void *upb_gmalloc(size_t size) {
+UPB_INLINE void* upb_gmalloc(size_t size) {
   return upb_malloc(&upb_alloc_global, size);
 }
 
-UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) {
+UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) {
   return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
 }
 
-UPB_INLINE void upb_gfree(void *ptr) {
-  upb_free(&upb_alloc_global, ptr);
-}
+UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); }
 
-/* upb_arena ******************************************************************/
+/* upb_Arena ******************************************************************/
 
-/* upb_arena is a specific allocator implementation that uses arena allocation.
+/* upb_Arena is a specific allocator implementation that uses arena allocation.
  * The user provides an allocator that will be used to allocate the underlying
  * arena blocks.  Arenas by nature do not require the individual allocations
  * to be freed.  However the Arena does allow users to register cleanup
  * functions that will run when the arena is destroyed.
  *
- * A upb_arena is *not* thread-safe.
+ * A upb_Arena is *not* thread-safe.
  *
  * You could write a thread-safe arena allocator that satisfies the
  * upb_alloc interface, but it would not be as efficient for the
  * single-threaded case. */
 
-typedef void upb_cleanup_func(void *ud);
+typedef void upb_CleanupFunc(void* ud);
 
-struct upb_arena;
-typedef struct upb_arena upb_arena;
+struct upb_Arena;
+typedef struct upb_Arena upb_Arena;
 
 typedef struct {
   /* We implement the allocator interface.
-   * This must be the first member of upb_arena!
+   * This must be the first member of upb_Arena!
    * TODO(haberman): remove once handlers are gone. */
   upb_alloc alloc;
 
   char *ptr, *end;
-} _upb_arena_head;
+} _upb_ArenaHead;
 
 /* Creates an arena from the given initial block (if any -- n may be 0).
  * Additional blocks will be allocated from |alloc|.  If |alloc| is NULL, this
  * is a fixed-size arena and cannot grow. */
-upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc);
-void upb_arena_free(upb_arena *a);
-bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func);
-bool upb_arena_fuse(upb_arena *a, upb_arena *b);
-void *_upb_arena_slowmalloc(upb_arena *a, size_t size);
+upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc);
+void upb_Arena_Free(upb_Arena* a);
+bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func);
+bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b);
+void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size);
 
-UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; }
+UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; }
 
-UPB_INLINE size_t _upb_arenahas(upb_arena *a) {
-  _upb_arena_head *h = (_upb_arena_head*)a;
+UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) {
+  _upb_ArenaHead* h = (_upb_ArenaHead*)a;
   return (size_t)(h->end - h->ptr);
 }
 
-UPB_INLINE void *upb_arena_malloc(upb_arena *a, size_t size) {
-  _upb_arena_head *h = (_upb_arena_head*)a;
+UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) {
+  _upb_ArenaHead* h = (_upb_ArenaHead*)a;
   void* ret;
   size = UPB_ALIGN_MALLOC(size);
 
-  if (UPB_UNLIKELY(_upb_arenahas(a) < size)) {
-    return _upb_arena_slowmalloc(a, size);
+  if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) {
+    return _upb_Arena_SlowMalloc(a, size);
   }
 
   ret = h->ptr;
@@ -464,7 +464,7 @@
 #if UPB_ASAN
   {
     size_t guard_size = 32;
-    if (_upb_arenahas(a) >= guard_size) {
+    if (_upb_ArenaHas(a) >= guard_size) {
       h->ptr += guard_size;
     } else {
       h->ptr = h->end;
@@ -475,9 +475,9 @@
   return ret;
 }
 
-UPB_INLINE void *upb_arena_realloc(upb_arena *a, void *ptr, size_t oldsize,
+UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize,
                                    size_t size) {
-  void *ret = upb_arena_malloc(a, size);
+  void* ret = upb_Arena_Malloc(a, size);
 
   if (ret && oldsize > 0) {
     memcpy(ret, ptr, oldsize);
@@ -486,100 +486,77 @@
   return ret;
 }
 
-UPB_INLINE upb_arena *upb_arena_new(void) {
-  return upb_arena_init(NULL, 0, &upb_alloc_global);
+UPB_INLINE upb_Arena* upb_Arena_New(void) {
+  return upb_Arena_Init(NULL, 0, &upb_alloc_global);
 }
 
 /* Constants ******************************************************************/
 
-/* Generic function type. */
-typedef void upb_func(void);
-
 /* A list of types as they are encoded on-the-wire. */
 typedef enum {
-  UPB_WIRE_TYPE_VARINT      = 0,
-  UPB_WIRE_TYPE_64BIT       = 1,
-  UPB_WIRE_TYPE_DELIMITED   = 2,
-  UPB_WIRE_TYPE_START_GROUP = 3,
-  UPB_WIRE_TYPE_END_GROUP   = 4,
-  UPB_WIRE_TYPE_32BIT       = 5
-} upb_wiretype_t;
+  kUpb_WireType_Varint = 0,
+  kUpb_WireType_64Bit = 1,
+  kUpb_WireType_Delimited = 2,
+  kUpb_WireType_StartGroup = 3,
+  kUpb_WireType_EndGroup = 4,
+  kUpb_WireType_32Bit = 5
+} upb_WireType;
 
 /* The types a field can have.  Note that this list is not identical to the
  * types defined in descriptor.proto, which gives INT32 and SINT32 separate
  * types (we distinguish the two with the "integer encoding" enum below). */
 typedef enum {
-  UPB_TYPE_BOOL     = 1,
-  UPB_TYPE_FLOAT    = 2,
-  UPB_TYPE_INT32    = 3,
-  UPB_TYPE_UINT32   = 4,
-  UPB_TYPE_ENUM     = 5,  /* Enum values are int32. */
-  UPB_TYPE_MESSAGE  = 6,
-  UPB_TYPE_DOUBLE   = 7,
-  UPB_TYPE_INT64    = 8,
-  UPB_TYPE_UINT64   = 9,
-  UPB_TYPE_STRING   = 10,
-  UPB_TYPE_BYTES    = 11
-} upb_fieldtype_t;
+  kUpb_CType_Bool = 1,
+  kUpb_CType_Float = 2,
+  kUpb_CType_Int32 = 3,
+  kUpb_CType_UInt32 = 4,
+  kUpb_CType_Enum = 5, /* Enum values are int32. */
+  kUpb_CType_Message = 6,
+  kUpb_CType_Double = 7,
+  kUpb_CType_Int64 = 8,
+  kUpb_CType_UInt64 = 9,
+  kUpb_CType_String = 10,
+  kUpb_CType_Bytes = 11
+} upb_CType;
 
 /* The repeated-ness of each field; this matches descriptor.proto. */
 typedef enum {
-  UPB_LABEL_OPTIONAL = 1,
-  UPB_LABEL_REQUIRED = 2,
-  UPB_LABEL_REPEATED = 3
-} upb_label_t;
+  kUpb_Label_Optional = 1,
+  kUpb_Label_Required = 2,
+  kUpb_Label_Repeated = 3
+} upb_Label;
 
 /* Descriptor types, as defined in descriptor.proto. */
 typedef enum {
-  /* Old (long) names.  TODO(haberman): remove */
-  UPB_DESCRIPTOR_TYPE_DOUBLE   = 1,
-  UPB_DESCRIPTOR_TYPE_FLOAT    = 2,
-  UPB_DESCRIPTOR_TYPE_INT64    = 3,
-  UPB_DESCRIPTOR_TYPE_UINT64   = 4,
-  UPB_DESCRIPTOR_TYPE_INT32    = 5,
-  UPB_DESCRIPTOR_TYPE_FIXED64  = 6,
-  UPB_DESCRIPTOR_TYPE_FIXED32  = 7,
-  UPB_DESCRIPTOR_TYPE_BOOL     = 8,
-  UPB_DESCRIPTOR_TYPE_STRING   = 9,
-  UPB_DESCRIPTOR_TYPE_GROUP    = 10,
-  UPB_DESCRIPTOR_TYPE_MESSAGE  = 11,
-  UPB_DESCRIPTOR_TYPE_BYTES    = 12,
-  UPB_DESCRIPTOR_TYPE_UINT32   = 13,
-  UPB_DESCRIPTOR_TYPE_ENUM     = 14,
-  UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
-  UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
-  UPB_DESCRIPTOR_TYPE_SINT32   = 17,
-  UPB_DESCRIPTOR_TYPE_SINT64   = 18,
+  kUpb_FieldType_Double = 1,
+  kUpb_FieldType_Float = 2,
+  kUpb_FieldType_Int64 = 3,
+  kUpb_FieldType_UInt64 = 4,
+  kUpb_FieldType_Int32 = 5,
+  kUpb_FieldType_Fixed64 = 6,
+  kUpb_FieldType_Fixed32 = 7,
+  kUpb_FieldType_Bool = 8,
+  kUpb_FieldType_String = 9,
+  kUpb_FieldType_Group = 10,
+  kUpb_FieldType_Message = 11,
+  kUpb_FieldType_Bytes = 12,
+  kUpb_FieldType_UInt32 = 13,
+  kUpb_FieldType_Enum = 14,
+  kUpb_FieldType_SFixed32 = 15,
+  kUpb_FieldType_SFixed64 = 16,
+  kUpb_FieldType_SInt32 = 17,
+  kUpb_FieldType_SInt64 = 18
+} upb_FieldType;
 
-  UPB_DTYPE_DOUBLE   = 1,
-  UPB_DTYPE_FLOAT    = 2,
-  UPB_DTYPE_INT64    = 3,
-  UPB_DTYPE_UINT64   = 4,
-  UPB_DTYPE_INT32    = 5,
-  UPB_DTYPE_FIXED64  = 6,
-  UPB_DTYPE_FIXED32  = 7,
-  UPB_DTYPE_BOOL     = 8,
-  UPB_DTYPE_STRING   = 9,
-  UPB_DTYPE_GROUP    = 10,
-  UPB_DTYPE_MESSAGE  = 11,
-  UPB_DTYPE_BYTES    = 12,
-  UPB_DTYPE_UINT32   = 13,
-  UPB_DTYPE_ENUM     = 14,
-  UPB_DTYPE_SFIXED32 = 15,
-  UPB_DTYPE_SFIXED64 = 16,
-  UPB_DTYPE_SINT32   = 17,
-  UPB_DTYPE_SINT64   = 18
-} upb_descriptortype_t;
+#define kUpb_Map_Begin ((size_t)-1)
 
-#define UPB_MAP_BEGIN ((size_t)-1)
-
-UPB_INLINE bool _upb_isle(void) {
+UPB_INLINE bool _upb_IsLittleEndian(void) {
   int x = 1;
   return *(char*)&x == 1;
 }
 
-UPB_INLINE uint32_t _upb_be_swap32(uint32_t val) {
-  if (_upb_isle()) {
+UPB_INLINE uint32_t _upb_BigEndian_Swap32(uint32_t val) {
+  if (_upb_IsLittleEndian()) {
     return val;
   } else {
     return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
@@ -587,15 +564,16 @@
   }
 }
 
-UPB_INLINE uint64_t _upb_be_swap64(uint64_t val) {
-  if (_upb_isle()) {
+UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) {
+  if (_upb_IsLittleEndian()) {
     return val;
   } else {
-    return ((uint64_t)_upb_be_swap32(val) << 32) | _upb_be_swap32(val >> 32);
+    return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) |
+           _upb_BigEndian_Swap32(val >> 32);
   }
 }
 
-UPB_INLINE int _upb_lg2ceil(int x) {
+UPB_INLINE int _upb_Log2Ceiling(int x) {
   if (x <= 1) return 0;
 #ifdef __GNUC__
   return 32 - __builtin_clz(x - 1);
@@ -606,54 +584,59 @@
 #endif
 }
 
-UPB_INLINE int _upb_lg2ceilsize(int x) {
-  return 1 << _upb_lg2ceil(x);
-}
+UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); }
 
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
-#endif  /* UPB_H_ */
+#endif /* UPB_H_ */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef void upb_msg;
+/** upb_Message
+ * *******************************************************************/
 
-/* For users these are opaque. They can be obtained from upb_msgdef_layout()
- * but users cannot access any of the members. */
-struct upb_msglayout;
-typedef struct upb_msglayout upb_msglayout;
+typedef void upb_Message;
+
+/* For users these are opaque. They can be obtained from
+ * upb_MessageDef_MiniTable() but users cannot access any of the members. */
+struct upb_MiniTable;
+typedef struct upb_MiniTable upb_MiniTable;
 
 /* Adds unknown data (serialized protobuf data) to the given message.  The data
  * is copied into the message instance. */
-void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
-                        upb_arena *arena);
+void upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len,
+                            upb_Arena* arena);
 
 /* Returns a reference to the message's unknown data. */
-const char *upb_msg_getunknown(const upb_msg *msg, size_t *len);
+const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len);
 
-/** upb_extreg *******************************************************************/
+/* Returns the number of extensions present in this message. */
+size_t upb_Message_ExtensionCount(const upb_Message* msg);
+
+/** upb_ExtensionRegistry *****************************************************/
 
 /* Extension registry: a dynamic data structure that stores a map of:
- *   (upb_msglayout, number) -> extension info
+ *   (upb_MiniTable, number) -> extension info
  *
- * upb_decode() uses upb_extreg to look up extensions while parsing binary
- * format.
+ * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing
+ * binary format.
  *
- * upb_extreg is part of the mini-table (msglayout) family of objects. Like all
- * mini-table objects, it is suitable for reflection-less builds that do not
- * want to expose names into the binary.
+ * upb_ExtensionRegistry is part of the mini-table (msglayout) family of
+ * objects. Like all mini-table objects, it is suitable for reflection-less
+ * builds that do not want to expose names into the binary.
  *
- * Unlike most mini-table types, upb_extreg requires dynamic memory allocation
- * and dynamic initialization:
- * * If reflection is being used, then upb_symtab will construct an appropriate
- *   upb_extreg automatically.
+ * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory
+ * allocation and dynamic initialization:
+ * * If reflection is being used, then upb_DefPool will construct an appropriate
+ *   upb_ExtensionRegistry automatically.
  * * For a mini-table only build, the user must manually construct the
- *   upb_extreg and populate it with all of the extensions the user cares about.
+ *   upb_ExtensionRegistry and populate it with all of the extensions the user
+ * cares about.
  * * A third alternative is to manually unpack relevant extensions after the
  *   main parse is complete, similar to how Any works. This is perhaps the
  *   nicest solution from the perspective of reducing dependencies, avoiding
@@ -667,19 +650,19 @@
  * extensions from a generated module and pass the extension registry to the
  * binary decoder.
  *
- * A upb_symtab provides a upb_extreg, so any users who use reflection do not
- * need to populate a upb_extreg directly.
+ * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use
+ * reflection do not need to populate a upb_ExtensionRegistry directly.
  */
 
-struct upb_extreg;
-typedef struct upb_extreg upb_extreg;
+struct upb_ExtensionRegistry;
+typedef struct upb_ExtensionRegistry upb_ExtensionRegistry;
 
-/* Creates a upb_extreg in the given arena.  The arena must outlive any use of
- * the extreg. */
-upb_extreg *upb_extreg_new(upb_arena *arena);
+/* Creates a upb_ExtensionRegistry in the given arena.  The arena must outlive
+ * any use of the extreg. */
+upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
 #endif /* UPB_MSG_INT_H_ */
@@ -693,27 +676,53 @@
 enum {
   /* If set, strings will alias the input buffer instead of copying into the
    * arena. */
-  UPB_DECODE_ALIAS = 1,
+  kUpb_DecodeOption_AliasString = 1,
+
+  /* If set, the parse will return failure if any message is missing any
+   * required fields when the message data ends.  The parse will still continue,
+   * and the failure will only be reported at the end.
+   *
+   * IMPORTANT CAVEATS:
+   *
+   * 1. This can throw a false positive failure if an incomplete message is seen
+   *    on the wire but is later completed when the sub-message occurs again.
+   *    For this reason, a second pass is required to verify a failure, to be
+   *    truly robust.
+   *
+   * 2. This can return a false success if you are decoding into a message that
+   *    already has some sub-message fields present.  If the sub-message does
+   *    not occur in the binary payload, we will never visit it and discover the
+   *    incomplete sub-message.  For this reason, this check is only useful for
+   *    implemting ParseFromString() semantics.  For MergeFromString(), a
+   *    post-parse validation step will always be necessary. */
+  kUpb_DecodeOption_CheckRequired = 2,
 };
 
 #define UPB_DECODE_MAXDEPTH(depth) ((depth) << 16)
 
-bool _upb_decode(const char *buf, size_t size, upb_msg *msg,
-                 const upb_msglayout *l, const upb_extreg *extreg, int options,
-                 upb_arena *arena);
+typedef enum {
+  kUpb_DecodeStatus_Ok = 0,
+  kUpb_DecodeStatus_Malformed = 1,         // Wire format was corrupt
+  kUpb_DecodeStatus_OutOfMemory = 2,       // Arena alloc failed
+  kUpb_DecodeStatus_BadUtf8 = 3,           // String field had bad UTF-8
+  kUpb_DecodeStatus_MaxDepthExceeded = 4,  // Exceeded UPB_DECODE_MAXDEPTH
 
-UPB_INLINE
-bool upb_decode(const char *buf, size_t size, upb_msg *msg,
-                const upb_msglayout *l, upb_arena *arena) {
-  return _upb_decode(buf, size, msg, l, NULL, 0, arena);
-}
+  // kUpb_DecodeOption_CheckRequired failed (see above), but the parse otherwise
+  // succeeded.
+  kUpb_DecodeStatus_MissingRequired = 5,
+} upb_DecodeStatus;
+
+upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg,
+                            const upb_MiniTable* l,
+                            const upb_ExtensionRegistry* extreg, int options,
+                            upb_Arena* arena);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
 
-#endif  /* UPB_DECODE_H_ */
+#endif /* UPB_DECODE_H_ */
 
 /** upb/decode_internal.h ************************************************************/
 /*
@@ -726,8 +735,10 @@
 
 #include <setjmp.h>
 
+#include "third_party/utf8_range/utf8_range.h"
 
-/** upb/msg_internal.h ************************************************************//*
+/** upb/msg_internal.h ************************************************************/
+/*
 ** Our memory representation for parsing tables and messages themselves.
 ** Functions in this file are used by generated code and possibly reflection.
 **
@@ -769,10 +780,15 @@
 #include <string.h>
 
 
+// Must be last.
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
+                       const uint64_t salt[]);
+extern const uint64_t kWyhashSalt[5];
 
 /* upb_value ******************************************************************/
 
@@ -782,11 +798,9 @@
 
 /* Variant that works with a length-delimited rather than NULL-delimited string,
  * as supported by strtable. */
-char *upb_strdup2(const char *s, size_t len, upb_arena *a);
+char* upb_strdup2(const char* s, size_t len, upb_Arena* a);
 
-UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) {
-  v->val = val;
-}
+UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; }
 
 /* For each value ctype, define the following set of functions:
  *
@@ -796,36 +810,35 @@
  *
  * // Construct a new upb_value from an int32.
  * upb_value upb_value_int32(int32_t val); */
-#define FUNCS(name, membername, type_t, converter, proto_type) \
-  UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \
-    val->val = (converter)cval; \
-  } \
-  UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
-    upb_value ret; \
-    upb_value_set ## name(&ret, val); \
-    return ret; \
-  } \
-  UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
-    return (type_t)(converter)val.val; \
+#define FUNCS(name, membername, type_t, converter, proto_type)       \
+  UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \
+    val->val = (converter)cval;                                      \
+  }                                                                  \
+  UPB_INLINE upb_value upb_value_##name(type_t val) {                \
+    upb_value ret;                                                   \
+    upb_value_set##name(&ret, val);                                  \
+    return ret;                                                      \
+  }                                                                  \
+  UPB_INLINE type_t upb_value_get##name(upb_value val) {             \
+    return (type_t)(converter)val.val;                               \
   }
 
-FUNCS(int32,    int32,        int32_t,      int32_t,    UPB_CTYPE_INT32)
-FUNCS(int64,    int64,        int64_t,      int64_t,    UPB_CTYPE_INT64)
-FUNCS(uint32,   uint32,       uint32_t,     uint32_t,   UPB_CTYPE_UINT32)
-FUNCS(uint64,   uint64,       uint64_t,     uint64_t,   UPB_CTYPE_UINT64)
-FUNCS(bool,     _bool,        bool,         bool,       UPB_CTYPE_BOOL)
-FUNCS(cstr,     cstr,         char*,        uintptr_t,  UPB_CTYPE_CSTR)
-FUNCS(ptr,      ptr,          void*,        uintptr_t,  UPB_CTYPE_PTR)
-FUNCS(constptr, constptr,     const void*,  uintptr_t,  UPB_CTYPE_CONSTPTR)
-FUNCS(fptr,     fptr,         upb_func*,    uintptr_t,  UPB_CTYPE_FPTR)
+FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32)
+FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64)
+FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32)
+FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64)
+FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL)
+FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR)
+FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR)
+FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR)
 
 #undef FUNCS
 
-UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) {
+UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) {
   memcpy(&val->val, &cval, sizeof(cval));
 }
 
-UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) {
+UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) {
   memcpy(&val->val, &cval, sizeof(cval));
 }
 
@@ -843,7 +856,6 @@
 
 #undef SET_TYPE
 
-
 /* upb_tabkey *****************************************************************/
 
 /* Either:
@@ -855,14 +867,14 @@
  * initializing a non-first union member. */
 typedef uintptr_t upb_tabkey;
 
-UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
+UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) {
   char* mem = (char*)key;
   if (len) memcpy(len, mem, sizeof(*len));
   return mem + sizeof(*len);
 }
 
-UPB_INLINE upb_strview upb_tabstrview(upb_tabkey key) {
-  upb_strview ret;
+UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) {
+  upb_StringView ret;
   uint32_t len;
   ret.data = upb_tabstr(key, &len);
   ret.size = len;
@@ -875,14 +887,11 @@
   uint64_t val;
 } upb_tabval;
 
-#define UPB_TABVALUE_EMPTY_INIT  {-1}
+#define UPB_TABVALUE_EMPTY_INIT \
+  { -1 }
 
 /* upb_table ******************************************************************/
 
-uint64_t Wyhash(const void *data, size_t len, uint64_t seed,
-                const uint64_t salt[]);
-extern const uint64_t kWyhashSalt[5];
-
 typedef struct _upb_tabent {
   upb_tabkey key;
   upb_tabval val;
@@ -891,15 +900,15 @@
    * tables.  We cast away const sometimes, but *only* when the containing
    * upb_table is known to be non-const.  This requires a bit of care, but
    * the subtlety is confined to table.c. */
-  const struct _upb_tabent *next;
+  const struct _upb_tabent* next;
 } upb_tabent;
 
 typedef struct {
-  size_t count;          /* Number of entries in the hash part. */
-  uint32_t mask;         /* Mask to turn hash value -> bucket. */
-  uint32_t max_count;    /* Max count before we hit our load limit. */
-  uint8_t size_lg2;      /* Size of the hashtable part is 2^size_lg2 entries. */
-  upb_tabent *entries;
+  size_t count;       /* Number of entries in the hash part. */
+  uint32_t mask;      /* Mask to turn hash value -> bucket. */
+  uint32_t max_count; /* Max count before we hit our load limit. */
+  uint8_t size_lg2;   /* Size of the hashtable part is 2^size_lg2 entries. */
+  upb_tabent* entries;
 } upb_table;
 
 typedef struct {
@@ -907,13 +916,13 @@
 } upb_strtable;
 
 typedef struct {
-  upb_table t;              /* For entries that don't fit in the array part. */
-  const upb_tabval *array;  /* Array part of the table. See const note above. */
-  size_t array_size;        /* Array part size. */
-  size_t array_count;       /* Array part number of elements. */
+  upb_table t;             /* For entries that don't fit in the array part. */
+  const upb_tabval* array; /* Array part of the table. See const note above. */
+  size_t array_size;       /* Array part size. */
+  size_t array_count;      /* Array part number of elements. */
 } upb_inttable;
 
-UPB_INLINE size_t upb_table_size(const upb_table *t) {
+UPB_INLINE size_t upb_table_size(const upb_table* t) {
   if (t->size_lg2 == 0)
     return 0;
   else
@@ -921,22 +930,20 @@
 }
 
 /* Internal-only functions, in .h file only out of necessity. */
-UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
-  return e->key == 0;
-}
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; }
 
 /* Initialize and uninitialize a table, respectively.  If memory allocation
  * failed, false is returned that the table is uninitialized. */
-bool upb_inttable_init(upb_inttable *table, upb_arena *a);
-bool upb_strtable_init(upb_strtable *table, size_t expected_size, upb_arena *a);
+bool upb_inttable_init(upb_inttable* table, upb_Arena* a);
+bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a);
 
 /* Returns the number of values in the table. */
-size_t upb_inttable_count(const upb_inttable *t);
-UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
+size_t upb_inttable_count(const upb_inttable* t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) {
   return t->t.count;
 }
 
-void upb_strtable_clear(upb_strtable *t);
+void upb_strtable_clear(upb_strtable* t);
 
 /* Inserts the given key into the hashtable with the given value.  The key must
  * not already exist in the hash table.  For string tables, the key must be
@@ -945,45 +952,84 @@
  *
  * If a table resize was required but memory allocation failed, false is
  * returned and the table is unchanged. */
-bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val,
-                         upb_arena *a);
-bool upb_strtable_insert(upb_strtable *t, const char *key, size_t len,
-                         upb_value val, upb_arena *a);
+bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
+                         upb_Arena* a);
+bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len,
+                         upb_value val, upb_Arena* a);
 
 /* Looks up key in this table, returning "true" if the key was found.
  * If v is non-NULL, copies the value for this key into *v. */
-bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
-bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
-                          upb_value *v);
+bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v);
+bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
+                          upb_value* v);
 
 /* For NULL-terminated strings. */
-UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
-                                    upb_value *v) {
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key,
+                                    upb_value* v) {
   return upb_strtable_lookup2(t, key, strlen(key), v);
 }
 
 /* Removes an item from the table.  Returns true if the remove was successful,
  * and stores the removed item in *val if non-NULL. */
-bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
-bool upb_strtable_remove(upb_strtable *t, const char *key, size_t len,
-                          upb_value *val);
+bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val);
+bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
+                          upb_value* val);
+
+UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key,
+                                    upb_value* v) {
+  return upb_strtable_remove2(t, key, strlen(key), v);
+}
 
 /* Updates an existing entry in an inttable.  If the entry does not exist,
  * returns false and does nothing.  Unlike insert/remove, this does not
  * invalidate iterators. */
-bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
+bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val);
 
 /* Optimizes the table for the current set of entries, for both memory use and
  * lookup time.  Client should call this after all entries have been inserted;
  * inserting more entries is legal, but will likely require a table resize. */
-void upb_inttable_compact(upb_inttable *t, upb_arena *a);
+void upb_inttable_compact(upb_inttable* t, upb_Arena* a);
 
 /* Exposed for testing only. */
-bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_arena *a);
+bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a);
 
 /* Iterators ******************************************************************/
 
-/* Iterators for int and string tables.  We are subject to some kind of unusual
+/* Iteration over inttable.
+ *
+ *   intptr_t iter = UPB_INTTABLE_BEGIN;
+ *   uintptr_t key;
+ *   upb_value val;
+ *   while (upb_inttable_next2(t, &key, &val, &iter)) {
+ *      // ...
+ *   }
+ */
+
+#define UPB_INTTABLE_BEGIN -1
+
+bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val,
+                        intptr_t* iter);
+void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter);
+
+/* Iteration over strtable.
+ *
+ *   intptr_t iter = UPB_INTTABLE_BEGIN;
+ *   upb_StringView key;
+ *   upb_value val;
+ *   while (upb_strtable_next2(t, &key, &val, &iter)) {
+ *      // ...
+ *   }
+ */
+
+#define UPB_STRTABLE_BEGIN -1
+
+bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
+                        upb_value* val, intptr_t* iter);
+void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter);
+
+/* DEPRECATED iterators, slated for removal.
+ *
+ * Iterators for int and string tables.  We are subject to some kind of unusual
  * design constraints:
  *
  * For high-level languages:
@@ -1004,7 +1050,6 @@
  * guaranteed not to crash and to return real table elements (except when done()
  * is true). */
 
-
 /* upb_strtable_iter **********************************************************/
 
 /*   upb_strtable_iter i;
@@ -1017,19 +1062,18 @@
  */
 
 typedef struct {
-  const upb_strtable *t;
+  const upb_strtable* t;
   size_t index;
 } upb_strtable_iter;
 
-void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
-void upb_strtable_next(upb_strtable_iter *i);
-bool upb_strtable_done(const upb_strtable_iter *i);
-upb_strview upb_strtable_iter_key(const upb_strtable_iter *i);
-upb_value upb_strtable_iter_value(const upb_strtable_iter *i);
-void upb_strtable_iter_setdone(upb_strtable_iter *i);
-bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
-                               const upb_strtable_iter *i2);
-
+void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t);
+void upb_strtable_next(upb_strtable_iter* i);
+bool upb_strtable_done(const upb_strtable_iter* i);
+upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter* i);
+void upb_strtable_iter_setdone(upb_strtable_iter* i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
+                               const upb_strtable_iter* i2);
 
 /* upb_inttable_iter **********************************************************/
 
@@ -1043,31 +1087,30 @@
  */
 
 typedef struct {
-  const upb_inttable *t;
+  const upb_inttable* t;
   size_t index;
   bool array_part;
 } upb_inttable_iter;
 
-UPB_INLINE const upb_tabent *str_tabent(const upb_strtable_iter *i) {
+UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) {
   return &i->t->t.entries[i->index];
 }
 
-void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
-void upb_inttable_next(upb_inttable_iter *i);
-bool upb_inttable_done(const upb_inttable_iter *i);
-uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i);
-upb_value upb_inttable_iter_value(const upb_inttable_iter *i);
-void upb_inttable_iter_setdone(upb_inttable_iter *i);
-bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
-                               const upb_inttable_iter *i2);
-
+void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t);
+void upb_inttable_next(upb_inttable_iter* i);
+bool upb_inttable_done(const upb_inttable_iter* i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter* i);
+void upb_inttable_iter_setdone(upb_inttable_iter* i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter* i1,
+                               const upb_inttable_iter* i2);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
 
-#endif  /* UPB_TABLE_H_ */
+#endif /* UPB_TABLE_H_ */
 
 /* Must be last. */
 
@@ -1075,110 +1118,196 @@
 extern "C" {
 #endif
 
-/** upb_msglayout *************************************************************/
+/** upb_MiniTable *************************************************************/
 
-/* upb_msglayout represents the memory layout of a given upb_msgdef.  The
+/* upb_MiniTable represents the memory layout of a given upb_MessageDef.  The
  * members are public so generated code can initialize them, but users MUST NOT
  * read or write any of its members. */
 
-/* These aren't real labels according to descriptor.proto, but in the table we
- * use these for map/packed fields instead of UPB_LABEL_REPEATED. */
-enum {
-  _UPB_LABEL_MAP = 4,
-  _UPB_LABEL_PACKED = 7  /* Low 3 bits are common with UPB_LABEL_REPEATED. */
-};
-
 typedef struct {
   uint32_t number;
   uint16_t offset;
-  int16_t presence;       /* If >0, hasbit_index.  If <0, ~oneof_index. */
-  uint16_t submsg_index;  /* undefined if descriptortype != MESSAGE or GROUP. */
+  int16_t presence;       // If >0, hasbit_index.  If <0, ~oneof_index
+  uint16_t submsg_index;  // undefined if descriptortype != MESSAGE/GROUP/ENUM
   uint8_t descriptortype;
-  int8_t mode;            /* upb_fieldmode, with flags from upb_labelflags */
-} upb_msglayout_field;
+  uint8_t mode; /* upb_FieldMode | upb_LabelFlags |
+                   (upb_FieldRep << upb_FieldRep_Shift) */
+} upb_MiniTable_Field;
 
 typedef enum {
-  _UPB_MODE_MAP = 0,
-  _UPB_MODE_ARRAY = 1,
-  _UPB_MODE_SCALAR = 2,
-} upb_fieldmode;
+  kUpb_FieldMode_Map = 0,
+  kUpb_FieldMode_Array = 1,
+  kUpb_FieldMode_Scalar = 2,
+
+  kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */
+} upb_FieldMode;
 
 /* Extra flags on the mode field. */
-enum upb_labelflags {
-  _UPB_MODE_IS_PACKED = 4,
+enum upb_LabelFlags {
+  upb_LabelFlags_IsPacked = 4,
+  upb_LabelFlags_IsExtension = 8,
 };
 
-UPB_INLINE upb_fieldmode _upb_getmode(const upb_msglayout_field *field) {
-  return (upb_fieldmode)(field->mode & 3);
+/* Representation in the message.  Derivable from descriptortype and mode, but
+ * fast access helps the serializer. */
+enum upb_FieldRep {
+  upb_FieldRep_1Byte = 0,
+  upb_FieldRep_4Byte = 1,
+  upb_FieldRep_8Byte = 2,
+  upb_FieldRep_StringView = 3,
+
+#if UINTPTR_MAX == 0xffffffff
+  upb_FieldRep_Pointer = upb_FieldRep_4Byte,
+#else
+  upb_FieldRep_Pointer = upb_FieldRep_8Byte,
+#endif
+
+  upb_FieldRep_Shift =
+      6, /* Bit offset of the rep in upb_MiniTable_Field.mode */
+};
+
+UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) {
+  return (upb_FieldMode)(field->mode & 3);
 }
 
-UPB_INLINE bool _upb_repeated_or_map(const upb_msglayout_field *field) {
-  /* This works because upb_fieldmode has no value 3. */
-  return !(field->mode & _UPB_MODE_SCALAR);
+UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTable_Field* field) {
+  /* This works because upb_FieldMode has no value 3. */
+  return !(field->mode & kUpb_FieldMode_Scalar);
 }
 
-UPB_INLINE bool _upb_issubmsg(const upb_msglayout_field *field) {
-  return field->descriptortype == UPB_DTYPE_MESSAGE ||
-         field->descriptortype == UPB_DTYPE_GROUP;
+UPB_INLINE bool upb_IsSubMessage(const upb_MiniTable_Field* field) {
+  return field->descriptortype == kUpb_FieldType_Message ||
+         field->descriptortype == kUpb_FieldType_Group;
 }
 
-struct upb_decstate;
-struct upb_msglayout;
+struct upb_Decoder;
+struct upb_MiniTable;
 
-typedef const char *_upb_field_parser(struct upb_decstate *d, const char *ptr,
-                                      upb_msg *msg, intptr_t table,
-                                      uint64_t hasbits, uint64_t data);
+typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
+                                     upb_Message* msg, intptr_t table,
+                                     uint64_t hasbits, uint64_t data);
 
 typedef struct {
   uint64_t field_data;
-  _upb_field_parser *field_parser;
-} _upb_fasttable_entry;
+  _upb_FieldParser* field_parser;
+} _upb_FastTable_Entry;
 
-struct upb_msglayout {
-  const struct upb_msglayout *const* submsgs;
-  const upb_msglayout_field *fields;
+typedef struct {
+  const int32_t* values;  // List of values <0 or >63
+  uint64_t mask;          // Bits are set for acceptable value 0 <= x < 64
+  int value_count;
+} upb_MiniTable_Enum;
+
+UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e,
+                                              int32_t val) {
+  uint32_t uval = (uint32_t)val;
+  if (uval < 64) return e->mask & (1 << uval);
+  // OPT: binary search long lists?
+  int n = e->value_count;
+  for (int i = 0; i < n; i++) {
+    if (e->values[i] == val) return true;
+  }
+  return false;
+}
+
+typedef union {
+  const struct upb_MiniTable* submsg;
+  const upb_MiniTable_Enum* subenum;
+} upb_MiniTable_Sub;
+
+typedef enum {
+  upb_ExtMode_NonExtendable = 0,  // Non-extendable message.
+  upb_ExtMode_Extendable = 1,     // Normal extendable message.
+  upb_ExtMode_IsMessageSet = 2,   // MessageSet message.
+  upb_ExtMode_IsMessageSet_ITEM =
+      3,  // MessageSet item (temporary only, see decode.c)
+} upb_ExtMode;
+
+/* MessageSet wire format is:
+ *   message MessageSet {
+ *     repeated group Item = 1 {
+ *       required int32 type_id = 2;
+ *       required string message = 3;
+ *     }
+ *   }
+ */
+typedef enum {
+  _UPB_MSGSET_ITEM = 1,
+  _UPB_MSGSET_TYPEID = 2,
+  _UPB_MSGSET_MESSAGE = 3,
+} upb_msgext_fieldnum;
+
+struct upb_MiniTable {
+  const upb_MiniTable_Sub* subs;
+  const upb_MiniTable_Field* fields;
   /* Must be aligned to sizeof(void*).  Doesn't include internal members like
    * unknown fields, extension dict, pointer to msglayout, etc. */
   uint16_t size;
   uint16_t field_count;
-  bool extendable;
+  uint8_t ext;  // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
   uint8_t dense_below;
   uint8_t table_mask;
-  /* To constant-initialize the tables of variable length, we need a flexible
-   * array member, and we need to compile in C99 mode. */
-  _upb_fasttable_entry fasttable[];
+  uint8_t required_count;  // Required fields have the lowest hasbits.
+  /* To statically initialize the tables of variable length, we need a flexible
+   * array member, and we need to compile in gnu99 mode (constant initialization
+   * of flexible array members is a GNU extension, not in C99 unfortunately. */
+  _upb_FastTable_Entry fasttable[];
 };
 
 typedef struct {
-  upb_msglayout_field field;
-  const upb_msglayout *extendee;
-  const upb_msglayout *submsg;   /* NULL for non-submessage fields. */
-} upb_msglayout_ext;
+  upb_MiniTable_Field field;
+  const upb_MiniTable* extendee;
+  upb_MiniTable_Sub sub; /* NULL unless submessage or proto2 enum */
+} upb_MiniTable_Extension;
 
-/** upb_extreg ****************************************************************/
+typedef struct {
+  const upb_MiniTable** msgs;
+  const upb_MiniTable_Enum** enums;
+  const upb_MiniTable_Extension** exts;
+  int msg_count;
+  int enum_count;
+  int ext_count;
+} upb_MiniTable_File;
+
+// Computes a bitmask in which the |l->required_count| lowest bits are set,
+// except that we skip the lowest bit (because upb never uses hasbit 0).
+//
+// Sample output:
+//    requiredmask(1) => 0b10 (0x2)
+//    requiredmask(5) => 0b111110 (0x3e)
+UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) {
+  int n = l->required_count;
+  assert(0 < n && n <= 63);
+  return ((1ULL << n) - 1) << 1;
+}
+
+/** upb_ExtensionRegistry
+ * ****************************************************************/
 
 /* Adds the given extension info for message type |l| and field number |num|
  * into the registry. Returns false if this message type and field number were
  * already in the map, or if memory allocation fails. */
-bool _upb_extreg_add(upb_extreg *r, const upb_msglayout_ext *e, size_t count);
+bool _upb_extreg_add(upb_ExtensionRegistry* r,
+                     const upb_MiniTable_Extension** e, size_t count);
 
 /* Looks up the extension (if any) defined for message type |l| and field
  * number |num|.  If an extension was found, copies the field info into |*ext|
  * and returns true. Otherwise returns false. */
-const upb_msglayout_field *_upb_extreg_get(const upb_extreg *r,
-                                           const upb_msglayout *l,
-                                           uint32_t num);
+const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r,
+                                               const upb_MiniTable* l,
+                                               uint32_t num);
 
-/** upb_msg *******************************************************************/
+/** upb_Message
+ * *******************************************************************/
 
-/* Internal members of a upb_msg that track unknown fields and/or extensions.
- * We can change this without breaking binary compatibility.  We put these
- * before the user's data.  The user's upb_msg* points after the
- * upb_msg_internal. */
+/* Internal members of a upb_Message that track unknown fields and/or
+ * extensions. We can change this without breaking binary compatibility.  We put
+ * these before the user's data.  The user's upb_Message* points after the
+ * upb_Message_Internal. */
 
 typedef struct {
   /* Total size of this structure, including the data that follows.
-   * Must be aligned to 8, which is alignof(upb_msg_ext) */
+   * Must be aligned to 8, which is alignof(upb_Message_Extension) */
   uint32_t size;
 
   /* Offsets relative to the beginning of this structure.
@@ -1188,160 +1317,176 @@
    * When the two meet, we're out of data and have to realloc.
    *
    * If we imagine that the final member of this struct is:
-   *   char data[size - overhead];  // overhead = sizeof(upb_msg_internaldata)
-   * 
+   *   char data[size - overhead];  // overhead =
+   * sizeof(upb_Message_InternalData)
+   *
    * Then we have:
    *   unknown data: data[0 .. (unknown_end - overhead)]
    *   extensions data: data[(ext_begin - overhead) .. (size - overhead)] */
   uint32_t unknown_end;
   uint32_t ext_begin;
   /* Data follows, as if there were an array:
-   *   char data[size - sizeof(upb_msg_internaldata)]; */
-} upb_msg_internaldata;
+   *   char data[size - sizeof(upb_Message_InternalData)]; */
+} upb_Message_InternalData;
 
 typedef struct {
-  upb_msg_internaldata *internal;
-} upb_msg_internal;
+  upb_Message_InternalData* internal;
+  /* Message data follows. */
+} upb_Message_Internal;
 
-/* Maps upb_fieldtype_t -> memory size. */
-extern char _upb_fieldtype_to_size[12];
+/* Maps upb_CType -> memory size. */
+extern char _upb_CTypeo_size[12];
 
-UPB_INLINE size_t upb_msg_sizeof(const upb_msglayout *l) {
-  return l->size + sizeof(upb_msg_internal);
+UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) {
+  return l->size + sizeof(upb_Message_Internal);
 }
 
-UPB_INLINE upb_msg *_upb_msg_new_inl(const upb_msglayout *l, upb_arena *a) {
+UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l,
+                                             upb_Arena* a) {
   size_t size = upb_msg_sizeof(l);
-  void *mem = upb_arena_malloc(a, size);
-  upb_msg *msg;
+  void* mem = upb_Arena_Malloc(a, size);
+  upb_Message* msg;
   if (UPB_UNLIKELY(!mem)) return NULL;
-  msg = UPB_PTR_AT(mem, sizeof(upb_msg_internal), upb_msg);
+  msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message);
   memset(mem, 0, size);
   return msg;
 }
 
 /* Creates a new messages with the given layout on the given arena. */
-upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a);
+upb_Message* _upb_Message_New(const upb_MiniTable* l, upb_Arena* a);
 
-UPB_INLINE upb_msg_internal *upb_msg_getinternal(upb_msg *msg) {
-  ptrdiff_t size = sizeof(upb_msg_internal);
-  return (upb_msg_internal*)((char*)msg - size);
+UPB_INLINE upb_Message_Internal* upb_Message_Getinternal(upb_Message* msg) {
+  ptrdiff_t size = sizeof(upb_Message_Internal);
+  return (upb_Message_Internal*)((char*)msg - size);
 }
 
 /* Clears the given message. */
-void _upb_msg_clear(upb_msg *msg, const upb_msglayout *l);
+void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l);
 
 /* Discards the unknown fields for this message only. */
-void _upb_msg_discardunknown_shallow(upb_msg *msg);
+void _upb_Message_DiscardUnknown_shallow(upb_Message* msg);
 
 /* Adds unknown data (serialized protobuf data) to the given message.  The data
  * is copied into the message instance. */
-bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len,
-                         upb_arena *arena);
+bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len,
+                             upb_Arena* arena);
 
-/** upb_msg_ext ***************************************************************/
+/** upb_Message_Extension
+ * ***************************************************************/
 
 /* The internal representation of an extension is self-describing: it contains
  * enough information that we can serialize it to binary format without needing
- * to look it up in a registry. */
+ * to look it up in a upb_ExtensionRegistry.
+ *
+ * This representation allocates 16 bytes to data on 64-bit platforms.  This is
+ * rather wasteful for scalars (in the extreme case of bool, it wastes 15
+ * bytes). We accept this because we expect messages to be the most common
+ * extension type. */
 typedef struct {
-  const upb_msglayout_ext *ext;
+  const upb_MiniTable_Extension* ext;
   union {
-    upb_strview str;
-    void *ptr;
-    double dbl;
+    upb_StringView str;
+    void* ptr;
     char scalar_data[8];
   } data;
-} upb_msg_ext;
+} upb_Message_Extension;
 
-/* Adds the given extension data to the given message. The returned extension will
- * have its "ext" member initialized according to |ext|. */
-upb_msg_ext *_upb_msg_getorcreateext(upb_msg *msg, const upb_msglayout_ext *ext,
-                                     upb_arena *arena);
+/* Adds the given extension data to the given message. |ext| is copied into the
+ * message instance. This logically replaces any previously-added extension with
+ * this number */
+upb_Message_Extension* _upb_Message_Getorcreateext(
+    upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena);
 
 /* Returns an array of extensions for this message. Note: the array is
  * ordered in reverse relative to the order of creation. */
-const upb_msg_ext *_upb_msg_getexts(const upb_msg *msg, size_t *count);
+const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg,
+                                                  size_t* count);
 
 /* Returns an extension for the given field number, or NULL if no extension
  * exists for this field number. */
-const upb_msg_ext *_upb_msg_getext(const upb_msg *msg,
-                                   const upb_msglayout_ext *ext);
+const upb_Message_Extension* _upb_Message_Getext(
+    const upb_Message* msg, const upb_MiniTable_Extension* ext);
+
+void _upb_Message_Clearext(upb_Message* msg,
+                           const upb_MiniTable_Extension* ext);
+
+void _upb_Message_Clearext(upb_Message* msg,
+                           const upb_MiniTable_Extension* ext);
 
 /** Hasbit access *************************************************************/
 
-UPB_INLINE bool _upb_hasbit(const upb_msg *msg, size_t idx) {
+UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) {
   return (*UPB_PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0;
 }
 
-UPB_INLINE void _upb_sethas(const upb_msg *msg, size_t idx) {
+UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) {
   (*UPB_PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8));
 }
 
-UPB_INLINE void _upb_clearhas(const upb_msg *msg, size_t idx) {
+UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) {
   (*UPB_PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8)));
 }
 
-UPB_INLINE size_t _upb_msg_hasidx(const upb_msglayout_field *f) {
+UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTable_Field* f) {
   UPB_ASSERT(f->presence > 0);
   return f->presence;
 }
 
-UPB_INLINE bool _upb_hasbit_field(const upb_msg *msg,
-                                  const upb_msglayout_field *f) {
-  return _upb_hasbit(msg, _upb_msg_hasidx(f));
+UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg,
+                                  const upb_MiniTable_Field* f) {
+  return _upb_hasbit(msg, _upb_Message_Hasidx(f));
 }
 
-UPB_INLINE void _upb_sethas_field(const upb_msg *msg,
-                                  const upb_msglayout_field *f) {
-  _upb_sethas(msg, _upb_msg_hasidx(f));
+UPB_INLINE void _upb_sethas_field(const upb_Message* msg,
+                                  const upb_MiniTable_Field* f) {
+  _upb_sethas(msg, _upb_Message_Hasidx(f));
 }
 
-UPB_INLINE void _upb_clearhas_field(const upb_msg *msg,
-                                    const upb_msglayout_field *f) {
-  _upb_clearhas(msg, _upb_msg_hasidx(f));
+UPB_INLINE void _upb_clearhas_field(const upb_Message* msg,
+                                    const upb_MiniTable_Field* f) {
+  _upb_clearhas(msg, _upb_Message_Hasidx(f));
 }
 
 /** Oneof case access *********************************************************/
 
-UPB_INLINE uint32_t *_upb_oneofcase(upb_msg *msg, size_t case_ofs) {
+UPB_INLINE uint32_t* _upb_oneofcase(upb_Message* msg, size_t case_ofs) {
   return UPB_PTR_AT(msg, case_ofs, uint32_t);
 }
 
-UPB_INLINE uint32_t _upb_getoneofcase(const void *msg, size_t case_ofs) {
+UPB_INLINE uint32_t _upb_getoneofcase(const void* msg, size_t case_ofs) {
   return *UPB_PTR_AT(msg, case_ofs, uint32_t);
 }
 
-UPB_INLINE size_t _upb_oneofcase_ofs(const upb_msglayout_field *f) {
+UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTable_Field* f) {
   UPB_ASSERT(f->presence < 0);
   return ~(ptrdiff_t)f->presence;
 }
 
-UPB_INLINE uint32_t *_upb_oneofcase_field(upb_msg *msg,
-                                          const upb_msglayout_field *f) {
+UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg,
+                                          const upb_MiniTable_Field* f) {
   return _upb_oneofcase(msg, _upb_oneofcase_ofs(f));
 }
 
-UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_msg *msg,
-                                            const upb_msglayout_field *f) {
+UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg,
+                                            const upb_MiniTable_Field* f) {
   return _upb_getoneofcase(msg, _upb_oneofcase_ofs(f));
 }
 
-UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_msg *msg, size_t ofs) {
-  return *UPB_PTR_AT(msg, ofs, const upb_msg*) != NULL;
+UPB_INLINE bool _upb_has_submsg_nohasbit(const upb_Message* msg, size_t ofs) {
+  return *UPB_PTR_AT(msg, ofs, const upb_Message*) != NULL;
 }
 
-/** upb_array *****************************************************************/
+/** upb_Array *****************************************************************/
 
 /* Our internal representation for repeated fields.  */
 typedef struct {
-  uintptr_t data;   /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */
-  size_t len;   /* Measured in elements. */
-  size_t size;  /* Measured in elements. */
+  uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */
+  size_t len;     /* Measured in elements. */
+  size_t size;    /* Measured in elements. */
   uint64_t junk;
-} upb_array;
+} upb_Array;
 
-UPB_INLINE const void *_upb_array_constptr(const upb_array *arr) {
+UPB_INLINE const void* _upb_array_constptr(const upb_Array* arr) {
   UPB_ASSERT((arr->data & 7) <= 4);
   return (void*)(arr->data & ~(uintptr_t)7);
 }
@@ -1351,7 +1496,7 @@
   return (uintptr_t)ptr | elem_size_lg2;
 }
 
-UPB_INLINE void *_upb_array_ptr(upb_array *arr) {
+UPB_INLINE void* _upb_array_ptr(upb_Array* arr) {
   return (void*)_upb_array_constptr(arr);
 }
 
@@ -1361,11 +1506,11 @@
   return (uintptr_t)ptr | (unsigned)elem_size_lg2;
 }
 
-UPB_INLINE upb_array *_upb_array_new(upb_arena *a, size_t init_size,
+UPB_INLINE upb_Array* _upb_Array_New(upb_Arena* a, size_t init_size,
                                      int elem_size_lg2) {
-  const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_array), 8);
-  const size_t bytes = sizeof(upb_array) + (init_size << elem_size_lg2);
-  upb_array *arr = (upb_array*)upb_arena_malloc(a, bytes);
+  const size_t arr_size = UPB_ALIGN_UP(sizeof(upb_Array), 8);
+  const size_t bytes = sizeof(upb_Array) + (init_size << elem_size_lg2);
+  upb_Array* arr = (upb_Array*)upb_Arena_Malloc(a, bytes);
   if (!arr) return NULL;
   arr->data = _upb_tag_arrptr(UPB_PTR_AT(arr, arr_size, void), elem_size_lg2);
   arr->len = 0;
@@ -1374,30 +1519,30 @@
 }
 
 /* Resizes the capacity of the array to be at least min_size. */
-bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena);
+bool _upb_array_realloc(upb_Array* arr, size_t min_size, upb_Arena* arena);
 
 /* Fallback functions for when the accessors require a resize. */
-void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size,
-                                 int elem_size_lg2, upb_arena *arena);
-bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value,
-                                int elem_size_lg2, upb_arena *arena);
+void* _upb_Array_Resize_fallback(upb_Array** arr_ptr, size_t size,
+                                 int elem_size_lg2, upb_Arena* arena);
+bool _upb_Array_Append_fallback(upb_Array** arr_ptr, const void* value,
+                                int elem_size_lg2, upb_Arena* arena);
 
-UPB_INLINE bool _upb_array_reserve(upb_array *arr, size_t size,
-                                   upb_arena *arena) {
+UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size,
+                                   upb_Arena* arena) {
   if (arr->size < size) return _upb_array_realloc(arr, size, arena);
   return true;
 }
 
-UPB_INLINE bool _upb_array_resize(upb_array *arr, size_t size,
-                                  upb_arena *arena) {
+UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size,
+                                  upb_Arena* arena) {
   if (!_upb_array_reserve(arr, size, arena)) return false;
   arr->len = size;
   return true;
 }
 
-UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs,
-                                           size_t *size) {
-  const upb_array *arr = *UPB_PTR_AT(msg, ofs, const upb_array*);
+UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs,
+                                           size_t* size) {
+  const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*);
   if (arr) {
     if (size) *size = arr->len;
     return _upb_array_constptr(arr);
@@ -1407,9 +1552,9 @@
   }
 }
 
-UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs,
-                                             size_t *size) {
-  upb_array *arr = *UPB_PTR_AT(msg, ofs, upb_array*);
+UPB_INLINE void* _upb_array_mutable_accessor(void* msg, size_t ofs,
+                                             size_t* size) {
+  upb_Array* arr = *UPB_PTR_AT(msg, ofs, upb_Array*);
   if (arr) {
     if (size) *size = arr->len;
     return _upb_array_ptr(arr);
@@ -1419,28 +1564,28 @@
   }
 }
 
-UPB_INLINE void *_upb_array_resize_accessor2(void *msg, size_t ofs, size_t size,
+UPB_INLINE void* _upb_Array_Resize_accessor2(void* msg, size_t ofs, size_t size,
                                              int elem_size_lg2,
-                                             upb_arena *arena) {
-  upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *);
-  upb_array *arr = *arr_ptr;
+                                             upb_Arena* arena) {
+  upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*);
+  upb_Array* arr = *arr_ptr;
   if (!arr || arr->size < size) {
-    return _upb_array_resize_fallback(arr_ptr, size, elem_size_lg2, arena);
+    return _upb_Array_Resize_fallback(arr_ptr, size, elem_size_lg2, arena);
   }
   arr->len = size;
   return _upb_array_ptr(arr);
 }
 
-UPB_INLINE bool _upb_array_append_accessor2(void *msg, size_t ofs,
+UPB_INLINE bool _upb_Array_Append_accessor2(void* msg, size_t ofs,
                                             int elem_size_lg2,
-                                            const void *value,
-                                            upb_arena *arena) {
-  upb_array **arr_ptr = UPB_PTR_AT(msg, ofs, upb_array *);
+                                            const void* value,
+                                            upb_Arena* arena) {
+  upb_Array** arr_ptr = UPB_PTR_AT(msg, ofs, upb_Array*);
   size_t elem_size = 1 << elem_size_lg2;
-  upb_array *arr = *arr_ptr;
-  void *ptr;
+  upb_Array* arr = *arr_ptr;
+  void* ptr;
   if (!arr || arr->len == arr->size) {
-    return _upb_array_append_fallback(arr_ptr, value, elem_size_lg2, arena);
+    return _upb_Array_Append_fallback(arr_ptr, value, elem_size_lg2, arena);
   }
   ptr = _upb_array_ptr(arr);
   memcpy(UPB_PTR_AT(ptr, arr->len * elem_size, char), value, elem_size);
@@ -1449,42 +1594,41 @@
 }
 
 /* Used by old generated code, remove once all code has been regenerated. */
-UPB_INLINE int _upb_sizelg2(upb_fieldtype_t type) {
+UPB_INLINE int _upb_sizelg2(upb_CType type) {
   switch (type) {
-    case UPB_TYPE_BOOL:
+    case kUpb_CType_Bool:
       return 0;
-    case UPB_TYPE_FLOAT:
-    case UPB_TYPE_INT32:
-    case UPB_TYPE_UINT32:
-    case UPB_TYPE_ENUM:
+    case kUpb_CType_Float:
+    case kUpb_CType_Int32:
+    case kUpb_CType_UInt32:
+    case kUpb_CType_Enum:
       return 2;
-    case UPB_TYPE_MESSAGE:
+    case kUpb_CType_Message:
       return UPB_SIZE(2, 3);
-    case UPB_TYPE_DOUBLE:
-    case UPB_TYPE_INT64:
-    case UPB_TYPE_UINT64:
+    case kUpb_CType_Double:
+    case kUpb_CType_Int64:
+    case kUpb_CType_UInt64:
       return 3;
-    case UPB_TYPE_STRING:
-    case UPB_TYPE_BYTES:
+    case kUpb_CType_String:
+    case kUpb_CType_Bytes:
       return UPB_SIZE(3, 4);
   }
   UPB_UNREACHABLE();
 }
-UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size,
-                                             upb_fieldtype_t type,
-                                             upb_arena *arena) {
-  return _upb_array_resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena);
+UPB_INLINE void* _upb_Array_Resize_accessor(void* msg, size_t ofs, size_t size,
+                                            upb_CType type, upb_Arena* arena) {
+  return _upb_Array_Resize_accessor2(msg, ofs, size, _upb_sizelg2(type), arena);
 }
-UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs,
-                                            size_t elem_size, upb_fieldtype_t type,
-                                            const void *value,
-                                            upb_arena *arena) {
+UPB_INLINE bool _upb_Array_Append_accessor(void* msg, size_t ofs,
+                                           size_t elem_size, upb_CType type,
+                                           const void* value,
+                                           upb_Arena* arena) {
   (void)elem_size;
-  return _upb_array_append_accessor2(msg, ofs, _upb_sizelg2(type), value,
+  return _upb_Array_Append_accessor2(msg, ofs, _upb_sizelg2(type), value,
                                      arena);
 }
 
-/** upb_map *******************************************************************/
+/** upb_Map *******************************************************************/
 
 /* Right now we use strmaps for everything.  We'll likely want to use
  * integer-specific maps for integer-keyed maps.*/
@@ -1495,25 +1639,25 @@
   char val_size;
 
   upb_strtable table;
-} upb_map;
+} upb_Map;
 
 /* Map entries aren't actually stored, they are only used during parsing.  For
  * parsing, it helps a lot if all map entry messages have the same layout.
  * The compiler and def.c must ensure that all map entries have this layout. */
 typedef struct {
-  upb_msg_internal internal;
+  upb_Message_Internal internal;
   union {
-    upb_strview str;  /* For str/bytes. */
-    upb_value val;    /* For all other types. */
+    upb_StringView str; /* For str/bytes. */
+    upb_value val;      /* For all other types. */
   } k;
   union {
-    upb_strview str;  /* For str/bytes. */
-    upb_value val;    /* For all other types. */
+    upb_StringView str; /* For str/bytes. */
+    upb_value val;      /* For all other types. */
   } v;
-} upb_map_entry;
+} upb_MapEntry;
 
 /* Creates a new map on the given arena with this key/value type. */
-upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size);
+upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size);
 
 /* Converting between internal table representation and user values.
  *
@@ -1524,15 +1668,15 @@
  * from other types when stored in a map.
  */
 
-UPB_INLINE upb_strview _upb_map_tokey(const void *key, size_t size) {
+UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) {
   if (size == UPB_MAPTYPE_STRING) {
-    return *(upb_strview*)key;
+    return *(upb_StringView*)key;
   } else {
-    return upb_strview_make((const char*)key, size);
+    return upb_StringView_FromDataAndSize((const char*)key, size);
   }
 }
 
-UPB_INLINE void _upb_map_fromkey(upb_strview key, void* out, size_t size) {
+UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) {
   if (size == UPB_MAPTYPE_STRING) {
     memcpy(out, &key, sizeof(key));
   } else {
@@ -1540,12 +1684,12 @@
   }
 }
 
-UPB_INLINE bool _upb_map_tovalue(const void *val, size_t size, upb_value *msgval,
-                                 upb_arena *a) {
+UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size,
+                                 upb_value* msgval, upb_Arena* a) {
   if (size == UPB_MAPTYPE_STRING) {
-    upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp));
+    upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp));
     if (!strp) return false;
-    *strp = *(upb_strview*)val;
+    *strp = *(upb_StringView*)val;
     *msgval = upb_value_ptr(strp);
   } else {
     memcpy(msgval, val, size);
@@ -1555,8 +1699,8 @@
 
 UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) {
   if (size == UPB_MAPTYPE_STRING) {
-    const upb_strview *strp = (const upb_strview*)upb_value_getptr(val);
-    memcpy(out, strp, sizeof(upb_strview));
+    const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val);
+    memcpy(out, strp, sizeof(upb_StringView));
   } else {
     memcpy(out, &val, size);
   }
@@ -1564,14 +1708,14 @@
 
 /* Map operations, shared by reflection and generated code. */
 
-UPB_INLINE size_t _upb_map_size(const upb_map *map) {
+UPB_INLINE size_t _upb_Map_Size(const upb_Map* map) {
   return map->table.t.count;
 }
 
-UPB_INLINE bool _upb_map_get(const upb_map *map, const void *key,
-                             size_t key_size, void *val, size_t val_size) {
+UPB_INLINE bool _upb_Map_Get(const upb_Map* map, const void* key,
+                             size_t key_size, void* val, size_t val_size) {
   upb_value tabval;
-  upb_strview k = _upb_map_tokey(key, key_size);
+  upb_StringView k = _upb_map_tokey(key, key_size);
   bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval);
   if (ret && val) {
     _upb_map_fromvalue(tabval, val, val_size);
@@ -1579,7 +1723,7 @@
   return ret;
 }
 
-UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) {
+UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) {
   upb_strtable_iter it;
   it.t = &map->table;
   it.index = *iter;
@@ -1589,108 +1733,111 @@
   return (void*)str_tabent(&it);
 }
 
-UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size,
-                             void *val, size_t val_size, upb_arena *a) {
-  upb_strview strkey = _upb_map_tokey(key, key_size);
+UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size,
+                             void* val, size_t val_size, upb_Arena* a) {
+  upb_StringView strkey = _upb_map_tokey(key, key_size);
   upb_value tabval = {0};
   if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false;
 
   /* TODO(haberman): add overwrite operation to minimize number of lookups. */
-  upb_strtable_remove(&map->table, strkey.data, strkey.size, NULL);
+  upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL);
   return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a);
 }
 
-UPB_INLINE bool _upb_map_delete(upb_map *map, const void *key, size_t key_size) {
-  upb_strview k = _upb_map_tokey(key, key_size);
-  return upb_strtable_remove(&map->table, k.data, k.size, NULL);
+UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key,
+                                size_t key_size) {
+  upb_StringView k = _upb_map_tokey(key, key_size);
+  return upb_strtable_remove2(&map->table, k.data, k.size, NULL);
 }
 
-UPB_INLINE void _upb_map_clear(upb_map *map) {
+UPB_INLINE void _upb_Map_Clear(upb_Map* map) {
   upb_strtable_clear(&map->table);
 }
 
 /* Message map operations, these get the map from the message first. */
 
-UPB_INLINE size_t _upb_msg_map_size(const upb_msg *msg, size_t ofs) {
-  upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *);
-  return map ? _upb_map_size(map) : 0;
+UPB_INLINE size_t _upb_msg_map_size(const upb_Message* msg, size_t ofs) {
+  upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*);
+  return map ? _upb_Map_Size(map) : 0;
 }
 
-UPB_INLINE bool _upb_msg_map_get(const upb_msg *msg, size_t ofs,
-                                 const void *key, size_t key_size, void *val,
+UPB_INLINE bool _upb_msg_map_get(const upb_Message* msg, size_t ofs,
+                                 const void* key, size_t key_size, void* val,
                                  size_t val_size) {
-  upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *);
+  upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*);
   if (!map) return false;
-  return _upb_map_get(map, key, key_size, val, val_size);
+  return _upb_Map_Get(map, key, key_size, val, val_size);
 }
 
-UPB_INLINE void *_upb_msg_map_next(const upb_msg *msg, size_t ofs,
-                                   size_t *iter) {
-  upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *);
+UPB_INLINE void* _upb_msg_map_next(const upb_Message* msg, size_t ofs,
+                                   size_t* iter) {
+  upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*);
   if (!map) return NULL;
   return _upb_map_next(map, iter);
 }
 
-UPB_INLINE bool _upb_msg_map_set(upb_msg *msg, size_t ofs, const void *key,
-                                 size_t key_size, void *val, size_t val_size,
-                                 upb_arena *arena) {
-  upb_map **map = UPB_PTR_AT(msg, ofs, upb_map *);
+UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key,
+                                 size_t key_size, void* val, size_t val_size,
+                                 upb_Arena* arena) {
+  upb_Map** map = UPB_PTR_AT(msg, ofs, upb_Map*);
   if (!*map) {
-    *map = _upb_map_new(arena, key_size, val_size);
+    *map = _upb_Map_New(arena, key_size, val_size);
   }
-  return _upb_map_set(*map, key, key_size, val, val_size, arena);
+  return _upb_Map_Set(*map, key, key_size, val, val_size, arena);
 }
 
-UPB_INLINE bool _upb_msg_map_delete(upb_msg *msg, size_t ofs, const void *key,
-                                    size_t key_size) {
-  upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *);
+UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs,
+                                    const void* key, size_t key_size) {
+  upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*);
   if (!map) return false;
-  return _upb_map_delete(map, key, key_size);
+  return _upb_Map_Delete(map, key, key_size);
 }
 
-UPB_INLINE void _upb_msg_map_clear(upb_msg *msg, size_t ofs) {
-  upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *);
+UPB_INLINE void _upb_msg_map_clear(upb_Message* msg, size_t ofs) {
+  upb_Map* map = *UPB_PTR_AT(msg, ofs, upb_Map*);
   if (!map) return;
-  _upb_map_clear(map);
+  _upb_Map_Clear(map);
 }
 
 /* Accessing map key/value from a pointer, used by generated code only. */
 
 UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) {
-  const upb_tabent *ent = (const upb_tabent*)msg;
+  const upb_tabent* ent = (const upb_tabent*)msg;
   uint32_t u32len;
-  upb_strview k;
+  upb_StringView k;
   k.data = upb_tabstr(ent->key, &u32len);
   k.size = u32len;
   _upb_map_fromkey(k, key, size);
 }
 
 UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) {
-  const upb_tabent *ent = (const upb_tabent*)msg;
+  const upb_tabent* ent = (const upb_tabent*)msg;
   upb_value v = {ent->val.val};
   _upb_map_fromvalue(v, val, size);
 }
 
-UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) {
-  upb_tabent *ent = (upb_tabent*)msg;
+UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val,
+                                       size_t size) {
+  upb_tabent* ent = (upb_tabent*)msg;
   /* This is like _upb_map_tovalue() except the entry already exists so we can
-   * reuse the allocated upb_strview for string fields. */
+   * reuse the allocated upb_StringView for string fields. */
   if (size == UPB_MAPTYPE_STRING) {
-    upb_strview *strp = (upb_strview*)(uintptr_t)ent->val.val;
+    upb_StringView* strp = (upb_StringView*)(uintptr_t)ent->val.val;
     memcpy(strp, val, sizeof(*strp));
   } else {
     memcpy(&ent->val.val, val, size);
   }
 }
 
-/** _upb_mapsorter *************************************************************/
+/** _upb_mapsorter
+ * *************************************************************/
 
 /* _upb_mapsorter sorts maps and provides ordered iteration over the entries.
- * Since maps can be recursive (map values can be messages which contain other maps).
- * _upb_mapsorter can contain a stack of maps. */
+ * Since maps can be recursive (map values can be messages which contain other
+ * maps). _upb_mapsorter can contain a stack of maps. */
 
 typedef struct {
-  upb_tabent const**entries;
+  upb_tabent const** entries;
   int size;
   int cap;
 } _upb_mapsorter;
@@ -1701,29 +1848,29 @@
   int end;
 } _upb_sortedmap;
 
-UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter *s) {
+UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) {
   s->entries = NULL;
   s->size = 0;
   s->cap = 0;
 }
 
-UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter *s) {
+UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) {
   if (s->entries) free(s->entries);
 }
 
-bool _upb_mapsorter_pushmap(_upb_mapsorter *s, upb_descriptortype_t key_type,
-                            const upb_map *map, _upb_sortedmap *sorted);
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+                            const upb_Map* map, _upb_sortedmap* sorted);
 
-UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter *s, _upb_sortedmap *sorted) {
+UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s,
+                                      _upb_sortedmap* sorted) {
   s->size = sorted->start;
 }
 
-UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter *s, const upb_map *map,
-                                    _upb_sortedmap *sorted,
-                                    upb_map_entry *ent) {
+UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map,
+                                    _upb_sortedmap* sorted, upb_MapEntry* ent) {
   if (sorted->pos == sorted->end) return false;
-  const upb_tabent *tabent = s->entries[sorted->pos++];
-  upb_strview key = upb_tabstrview(tabent->key);
+  const upb_tabent* tabent = s->entries[sorted->pos++];
+  upb_StringView key = upb_tabstrview(tabent->key);
   _upb_map_fromkey(key, &ent->k, map->key_size);
   upb_value val = {tabent->val.val};
   _upb_map_fromvalue(val, &ent->v, map->val_size);
@@ -1731,7 +1878,7 @@
 }
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
 
@@ -1745,8 +1892,8 @@
 struct mem_block;
 typedef struct mem_block mem_block;
 
-struct upb_arena {
-  _upb_arena_head head;
+struct upb_Arena {
+  _upb_ArenaHead head;
   /* Stores cleanup metadata for this arena.
    * - a pointer to the current cleanup counter.
    * - a boolean indicating if there is an unowned initial block.  */
@@ -1754,38 +1901,58 @@
 
   /* Allocator to allocate arena blocks.  We are responsible for freeing these
    * when we are destroyed. */
-  upb_alloc *block_alloc;
+  upb_alloc* block_alloc;
   uint32_t last_size;
 
   /* When multiple arenas are fused together, each arena points to a parent
    * arena (root points to itself). The root tracks how many live arenas
    * reference it. */
-  uint32_t refcount;  /* Only used when a->parent == a */
-  struct upb_arena *parent;
+  uint32_t refcount; /* Only used when a->parent == a */
+  struct upb_Arena* parent;
 
   /* Linked list of blocks to free/cleanup. */
   mem_block *freelist, *freelist_tail;
 };
 
-#endif  /* UPB_INT_H_ */
+// Encodes a float or double that is round-trippable, but as short as possible.
+// These routines are not fully optimal (not guaranteed to be shortest), but are
+// short-ish and match the implementation that has been used in protobuf since
+// the beginning.
+//
+// The given buffer size must be at least kUpb_RoundTripBufferSize.
+enum {
+  kUpb_RoundTripBufferSize = 32
+};
+void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size);
+void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size);
+
+#endif /* UPB_INT_H_ */
 
 /* Must be last. */
 
-#define DECODE_NOGROUP (uint32_t)-1
+#define DECODE_NOGROUP (uint32_t) - 1
 
-typedef struct upb_decstate {
-  const char *end;         /* Can read up to 16 bytes slop beyond this. */
-  const char *limit_ptr;   /* = end + UPB_MIN(limit, 0) */
-  upb_msg *unknown_msg;    /* If non-NULL, add unknown data at buffer flip. */
-  const char *unknown;     /* Start of unknown data. */
-  int limit;               /* Submessage limit relative to end. */
-  int depth;
-  uint32_t end_group;   /* field number of END_GROUP tag, else DECODE_NOGROUP */
-  bool alias;
+typedef struct upb_Decoder {
+  const char* end;          /* Can read up to 16 bytes slop beyond this. */
+  const char* limit_ptr;    /* = end + UPB_MIN(limit, 0) */
+  upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */
+  const char* unknown;      /* Start of unknown data. */
+  const upb_ExtensionRegistry*
+      extreg;         /* For looking up extensions during the parse. */
+  int limit;          /* Submessage limit relative to end. */
+  int depth;          /* Tracks recursion depth to bound stack usage. */
+  uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */
+  uint16_t options;
+  bool missing_required;
   char patch[32];
-  upb_arena arena;
+  upb_Arena arena;
   jmp_buf err;
-} upb_decstate;
+
+#ifndef NDEBUG
+  const char* debug_tagstart;
+  const char* debug_valstart;
+#endif
+} upb_Decoder;
 
 /* Error function that will abort decoding with longjmp(). We can't declare this
  * UPB_NORETURN, even though it is appropriate, because if we do then compilers
@@ -1794,50 +1961,58 @@
  * of our optimizations. That is also why we must declare it in a separate file,
  * otherwise the compiler will see that it calls longjmp() and deduce that it is
  * noreturn. */
-const char *fastdecode_err(upb_decstate *d);
+const char* fastdecode_err(upb_Decoder* d, int status);
 
 extern const uint8_t upb_utf8_offsets[];
 
 UPB_INLINE
-bool decode_verifyutf8_inl(const char *buf, int len) {
-  int i, j;
-  uint8_t offset;
+bool decode_verifyutf8_inl(const char* ptr, int len) {
+  const char* end = ptr + len;
 
-  i = 0;
-  while (i < len) {
-    offset = upb_utf8_offsets[(uint8_t)buf[i]];
-    if (offset == 0 || i + offset > len) {
-      return false;
-    }
-    for (j = i + 1; j < i + offset; j++) {
-      if ((buf[j] & 0xc0) != 0x80) {
-        return false;
-      }
-    }
-    i += offset;
+  // Check 8 bytes at a time for any non-ASCII char.
+  while (end - ptr >= 8) {
+    uint64_t data;
+    memcpy(&data, ptr, 8);
+    if (data & 0x8080808080808080) goto non_ascii;
+    ptr += 8;
   }
-  return i == len;
+
+  // Check one byte at a time for non-ASCII.
+  while (ptr < end) {
+    if (*ptr & 0x80) goto non_ascii;
+    ptr++;
+  }
+
+  return true;
+
+non_ascii:
+  return utf8_range2((const unsigned char*)ptr, end - ptr) == 0;
 }
 
+const char* decode_checkrequired(upb_Decoder* d, const char* ptr,
+                                 const upb_Message* msg,
+                                 const upb_MiniTable* l);
+
 /* x86-64 pointers always have the high 16 bits matching. So we can shift
  * left 8 and right 8 without loss of information. */
-UPB_INLINE intptr_t decode_totable(const upb_msglayout *tablep) {
+UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) {
   return ((intptr_t)tablep << 8) | tablep->table_mask;
 }
 
-UPB_INLINE const upb_msglayout *decode_totablep(intptr_t table) {
-  return (const upb_msglayout*)(table >> 8);
+UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) {
+  return (const upb_MiniTable*)(table >> 8);
 }
 
 UPB_INLINE
-const char *decode_isdonefallback_inl(upb_decstate *d, const char *ptr,
-                                      int overrun) {
+const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr,
+                                      int overrun, int* status) {
   if (overrun < d->limit) {
     /* Need to copy remaining data into patch buffer. */
     UPB_ASSERT(overrun < 16);
     if (d->unknown_msg) {
-      if (!_upb_msg_addunknown(d->unknown_msg, d->unknown, ptr - d->unknown,
-                               &d->arena)) {
+      if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown,
+                                   &d->arena)) {
+        *status = kUpb_DecodeStatus_OutOfMemory;
         return NULL;
       }
       d->unknown = &d->patch[0] + overrun;
@@ -1848,19 +2023,19 @@
     d->end = &d->patch[16];
     d->limit -= 16;
     d->limit_ptr = d->end + d->limit;
-    d->alias = false;
+    d->options &= ~kUpb_DecodeOption_AliasString;
     UPB_ASSERT(ptr < d->limit_ptr);
     return ptr;
   } else {
+    *status = kUpb_DecodeStatus_Malformed;
     return NULL;
   }
 }
 
-const char *decode_isdonefallback(upb_decstate *d, const char *ptr,
-                                  int overrun);
+const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun);
 
 UPB_INLINE
-bool decode_isdone(upb_decstate *d, const char **ptr) {
+bool decode_isdone(upb_Decoder* d, const char** ptr) {
   int overrun = *ptr - d->end;
   if (UPB_LIKELY(*ptr < d->limit_ptr)) {
     return false;
@@ -1874,10 +2049,10 @@
 
 #if UPB_FASTTABLE
 UPB_INLINE
-const char *fastdecode_tagdispatch(upb_decstate *d, const char *ptr,
-                                    upb_msg *msg, intptr_t table,
-                                    uint64_t hasbits, uint64_t tag) {
-  const upb_msglayout *table_p = decode_totablep(table);
+const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr,
+                                   upb_Message* msg, intptr_t table,
+                                   uint64_t hasbits, uint64_t tag) {
+  const upb_MiniTable* table_p = decode_totablep(table);
   uint8_t mask = table;
   uint64_t data;
   size_t idx = tag & mask;
@@ -1895,11 +2070,11 @@
   return tag;
 }
 
-UPB_INLINE void decode_checklimit(upb_decstate *d) {
+UPB_INLINE void decode_checklimit(upb_Decoder* d) {
   UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
 }
 
-UPB_INLINE int decode_pushlimit(upb_decstate *d, const char *ptr, int size) {
+UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) {
   int limit = size + (int)(ptr - d->end);
   int delta = d->limit - limit;
   decode_checklimit(d);
@@ -1909,7 +2084,7 @@
   return delta;
 }
 
-UPB_INLINE void decode_poplimit(upb_decstate *d, const char *ptr,
+UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr,
                                 int saved_delta) {
   UPB_ASSERT(ptr - d->end == d->limit);
   decode_checklimit(d);
@@ -1919,11 +2094,11 @@
 }
 
 
-#endif  /* UPB_DECODE_INT_H_ */
+#endif /* UPB_DECODE_INT_H_ */
 
 /** upb/encode.h ************************************************************/
 /*
- * upb_encode: parsing into a upb_msg using a upb_msglayout.
+ * upb_Encode: parsing into a upb_Message using a upb_MiniTable.
  */
 
 #ifndef UPB_ENCODE_H_
@@ -1943,28 +2118,26 @@
    *
    * If your proto contains maps, the encoder will need to malloc()/free()
    * memory during encode. */
-  UPB_ENCODE_DETERMINISTIC = 1,
+  kUpb_Encode_Deterministic = 1,
 
   /* When set, unknown fields are not printed. */
-  UPB_ENCODE_SKIPUNKNOWN = 2,
+  kUpb_Encode_SkipUnknown = 2,
+
+  /* When set, the encode will fail if any required fields are missing. */
+  kUpb_Encode_CheckRequired = 4,
 };
 
 #define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16)
 
-char *upb_encode_ex(const void *msg, const upb_msglayout *l, int options,
-                    upb_arena *arena, size_t *size);
-
-UPB_INLINE char *upb_encode(const void *msg, const upb_msglayout *l,
-                            upb_arena *arena, size_t *size) {
-  return upb_encode_ex(msg, l, 0, arena, size);
-}
+char* upb_Encode(const void* msg, const upb_MiniTable* l, int options,
+                 upb_Arena* arena, size_t* size);
 
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
-#endif  /* UPB_ENCODE_H_ */
+#endif /* UPB_ENCODE_H_ */
 
 /** upb/decode_fast.h ************************************************************/
 // These are the specialized field parser functions for the fast parser.
@@ -2005,22 +2178,22 @@
 #define UPB_DECODE_FAST_H_
 
 
-struct upb_decstate;
+struct upb_Decoder;
 
 // The fallback, generic parsing function that can handle any field type.
 // This just uses the regular (non-fast) parser to parse a single field.
-const char *fastdecode_generic(struct upb_decstate *d, const char *ptr,
-                               upb_msg *msg, intptr_t table, uint64_t hasbits,
-                               uint64_t data);
+const char* fastdecode_generic(struct upb_Decoder* d, const char* ptr,
+                               upb_Message* msg, intptr_t table,
+                               uint64_t hasbits, uint64_t data);
 
-#define UPB_PARSE_PARAMS                                                 \
-  struct upb_decstate *d, const char *ptr, upb_msg *msg, intptr_t table, \
+#define UPB_PARSE_PARAMS                                                    \
+  struct upb_Decoder *d, const char *ptr, upb_Message *msg, intptr_t table, \
       uint64_t hasbits, uint64_t data
 
 /* primitive fields ***********************************************************/
 
 #define F(card, type, valbytes, tagbytes) \
-  const char *upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS);
+  const char* upb_p##card##type##valbytes##_##tagbytes##bt(UPB_PARSE_PARAMS);
 
 #define TYPES(card, tagbytes) \
   F(card, b, 1, tagbytes)     \
@@ -2047,8 +2220,8 @@
 /* string fields **************************************************************/
 
 #define F(card, tagbytes, type)                                     \
-  const char *upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \
-  const char *upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS);
+  const char* upb_p##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS); \
+  const char* upb_c##card##type##_##tagbytes##bt(UPB_PARSE_PARAMS);
 
 #define UTF8(card, tagbytes) \
   F(card, tagbytes, s)       \
@@ -2068,17 +2241,17 @@
 /* sub-message fields *********************************************************/
 
 #define F(card, tagbytes, size_ceil, ceil_arg) \
-  const char *upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS);
+  const char* upb_p##card##m_##tagbytes##bt_max##size_ceil##b(UPB_PARSE_PARAMS);
 
 #define SIZES(card, tagbytes) \
-  F(card, tagbytes, 64, 64) \
+  F(card, tagbytes, 64, 64)   \
   F(card, tagbytes, 128, 128) \
   F(card, tagbytes, 192, 192) \
   F(card, tagbytes, 256, 256) \
   F(card, tagbytes, max, -1)
 
 #define TAGBYTES(card) \
-  SIZES(card, 1) \
+  SIZES(card, 1)       \
   SIZES(card, 2)
 
 TAGBYTES(s)
@@ -2091,7 +2264,7 @@
 
 #undef UPB_PARSE_PARAMS
 
-#endif  /* UPB_DECODE_FAST_H_ */
+#endif /* UPB_DECODE_FAST_H_ */
 
 /** google/protobuf/descriptor.upb.h ************************************************************//* This file was generated by upbc (the upb compiler) from the input
  * file:
@@ -2164,33 +2337,33 @@
 typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location;
 typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo;
 typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation;
-extern const upb_msglayout google_protobuf_FileDescriptorSet_msginit;
-extern const upb_msglayout google_protobuf_FileDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_DescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit;
-extern const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit;
-extern const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit;
-extern const upb_msglayout google_protobuf_FieldDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_OneofDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_EnumDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit;
-extern const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_MethodDescriptorProto_msginit;
-extern const upb_msglayout google_protobuf_FileOptions_msginit;
-extern const upb_msglayout google_protobuf_MessageOptions_msginit;
-extern const upb_msglayout google_protobuf_FieldOptions_msginit;
-extern const upb_msglayout google_protobuf_OneofOptions_msginit;
-extern const upb_msglayout google_protobuf_EnumOptions_msginit;
-extern const upb_msglayout google_protobuf_EnumValueOptions_msginit;
-extern const upb_msglayout google_protobuf_ServiceOptions_msginit;
-extern const upb_msglayout google_protobuf_MethodOptions_msginit;
-extern const upb_msglayout google_protobuf_UninterpretedOption_msginit;
-extern const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit;
-extern const upb_msglayout google_protobuf_SourceCodeInfo_msginit;
-extern const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit;
-extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit;
-extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit;
+extern const upb_MiniTable google_protobuf_FileDescriptorSet_msginit;
+extern const upb_MiniTable google_protobuf_FileDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_DescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_DescriptorProto_ExtensionRange_msginit;
+extern const upb_MiniTable google_protobuf_DescriptorProto_ReservedRange_msginit;
+extern const upb_MiniTable google_protobuf_ExtensionRangeOptions_msginit;
+extern const upb_MiniTable google_protobuf_FieldDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_OneofDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_EnumDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit;
+extern const upb_MiniTable google_protobuf_EnumValueDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_ServiceDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_MethodDescriptorProto_msginit;
+extern const upb_MiniTable google_protobuf_FileOptions_msginit;
+extern const upb_MiniTable google_protobuf_MessageOptions_msginit;
+extern const upb_MiniTable google_protobuf_FieldOptions_msginit;
+extern const upb_MiniTable google_protobuf_OneofOptions_msginit;
+extern const upb_MiniTable google_protobuf_EnumOptions_msginit;
+extern const upb_MiniTable google_protobuf_EnumValueOptions_msginit;
+extern const upb_MiniTable google_protobuf_ServiceOptions_msginit;
+extern const upb_MiniTable google_protobuf_MethodOptions_msginit;
+extern const upb_MiniTable google_protobuf_UninterpretedOption_msginit;
+extern const upb_MiniTable google_protobuf_UninterpretedOption_NamePart_msginit;
+extern const upb_MiniTable google_protobuf_SourceCodeInfo_msginit;
+extern const upb_MiniTable google_protobuf_SourceCodeInfo_Location_msginit;
+extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_msginit;
+extern const upb_MiniTable google_protobuf_GeneratedCodeInfo_Annotation_msginit;
 
 typedef enum {
   google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1,
@@ -2244,44 +2417,56 @@
 } google_protobuf_MethodOptions_IdempotencyLevel;
 
 
+extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Label_enuminit;
+extern const upb_MiniTable_Enum google_protobuf_FieldDescriptorProto_Type_enuminit;
+extern const upb_MiniTable_Enum google_protobuf_FieldOptions_CType_enuminit;
+extern const upb_MiniTable_Enum google_protobuf_FieldOptions_JSType_enuminit;
+extern const upb_MiniTable_Enum google_protobuf_FileOptions_OptimizeMode_enuminit;
+extern const upb_MiniTable_Enum google_protobuf_MethodOptions_IdempotencyLevel_enuminit;
+
 /* google.protobuf.FileDescriptorSet */
 
-UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_new(upb_arena *arena) {
-  return (google_protobuf_FileDescriptorSet *)_upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena);
+UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_new(upb_Arena* arena) {
+  return (google_protobuf_FileDescriptorSet*)_upb_Message_New(&google_protobuf_FileDescriptorSet_msginit, arena);
 }
-UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_FileDescriptorSet *ret = google_protobuf_FileDescriptorSet_new(arena);
+UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_FileDescriptorSet *ret = google_protobuf_FileDescriptorSet_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, arena, len);
+UPB_INLINE google_protobuf_FileDescriptorSet* google_protobuf_FileDescriptorSet_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_FileDescriptorSet* ret = google_protobuf_FileDescriptorSet_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_FileDescriptorSet_serialize_ex(const google_protobuf_FileDescriptorSet* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileDescriptorSet_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
 UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg, size_t *len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
 UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet *msg, size_t *len) {
   return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_FileDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_arena *arena) {
-  struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_Arena *arena) {
+  struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2289,35 +2474,44 @@
 
 /* google.protobuf.FileDescriptorProto */
 
-UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_FileDescriptorProto *)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_FileDescriptorProto*)_upb_Message_New(&google_protobuf_FileDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_FileDescriptorProto *ret = google_protobuf_FileDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_FileDescriptorProto *ret = google_protobuf_FileDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_FileDescriptorProto* ret = google_protobuf_FileDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_FileDescriptorProto_serialize_ex(const google_protobuf_FileDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileDescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE upb_strview const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
+UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView);
+}
+UPB_INLINE upb_StringView const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); }
 UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); }
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); }
@@ -2327,41 +2521,47 @@
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); }
 UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); }
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); }
+UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*);
+}
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); }
+UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*);
+}
 UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); }
 UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); }
 UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView);
+}
 
-UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value;
 }
-UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
+UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) {
+  return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
 }
-UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena);
+UPB_INLINE upb_StringView* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(3, 4), arena);
 }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val,
+UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_StringView val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(36, 72), UPB_SIZE(3, 4), &val,
       arena);
 }
 UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
 }
-UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2369,12 +2569,12 @@
 UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
 }
-UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(44, 88), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2382,12 +2582,12 @@
 UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len);
 }
-UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_ServiceDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(48, 96), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(48, 96), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2395,12 +2595,12 @@
 UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len);
 }
-UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(52, 104), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(52, 104), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2409,10 +2609,10 @@
   _upb_sethas(msg, 3);
   *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_FileOptions*)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena);
+    sub = (struct google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_FileDescriptorProto_set_options(msg, sub);
   }
@@ -2422,10 +2622,10 @@
   _upb_sethas(msg, 4);
   *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value;
 }
-UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_SourceCodeInfo*)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena);
+    sub = (struct google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub);
   }
@@ -2434,56 +2634,63 @@
 UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len);
 }
-UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena);
+UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 112), len, 2, arena);
 }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(56, 112), 2, &val,
+UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(56, 112), 2, &val,
       arena);
 }
 UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) {
   return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len);
 }
-UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena);
+UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(60, 120), len, 2, arena);
 }
-UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(60, 120), 2, &val,
+UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(60, 120), 2, &val,
       arena);
 }
-UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 5);
-  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value;
 }
 
 /* google.protobuf.DescriptorProto */
 
-UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_DescriptorProto *)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_DescriptorProto *ret = google_protobuf_DescriptorProto_new(arena);
+UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_DescriptorProto *ret = google_protobuf_DescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_DescriptorProto* ret = google_protobuf_DescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_DescriptorProto_serialize_ex(const google_protobuf_DescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
 UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
 UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); }
@@ -2495,26 +2702,28 @@
 UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); }
 UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); }
 UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); }
+UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); }
 UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); }
 UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); }
 UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); }
-UPB_INLINE upb_strview const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); }
+UPB_INLINE upb_StringView const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); }
 
-UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
 UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
 }
-UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2522,12 +2731,12 @@
 UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
 }
-UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_DescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_Message_New(&google_protobuf_DescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2535,12 +2744,12 @@
 UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
 }
-UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_EnumDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(24, 48), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2548,12 +2757,12 @@
 UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
 }
-UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(28, 56), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2561,12 +2770,12 @@
 UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len);
 }
-UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_FieldDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(32, 64), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(32, 64), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2575,10 +2784,10 @@
   _upb_sethas(msg, 2);
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_MessageOptions*)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena);
+    sub = (struct google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_DescriptorProto_set_options(msg, sub);
   }
@@ -2587,12 +2796,12 @@
 UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len);
 }
-UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_OneofDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(36, 72), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(36, 72), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2600,59 +2809,70 @@
 UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto *msg, size_t *len) {
   return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len);
 }
-UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_DescriptorProto_ReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(40, 80), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(40, 80), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
-UPB_INLINE upb_strview* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
+UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) {
+  return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len);
 }
-UPB_INLINE upb_strview* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena);
+UPB_INLINE upb_StringView* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(44, 88), len, UPB_SIZE(3, 4), arena);
 }
-UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val,
+UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_StringView val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(44, 88), UPB_SIZE(3, 4), &val,
       arena);
 }
 
 /* google.protobuf.DescriptorProto.ExtensionRange */
 
-UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_new(upb_arena *arena) {
-  return (google_protobuf_DescriptorProto_ExtensionRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena);
+UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_new(upb_Arena* arena) {
+  return (google_protobuf_DescriptorProto_ExtensionRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena);
 }
-UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_DescriptorProto_ExtensionRange *ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
+UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_DescriptorProto_ExtensionRange *ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, len);
+UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_ExtensionRange_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_DescriptorProto_ExtensionRange* ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_DescriptorProto_ExtensionRange_serialize_ex(const google_protobuf_DescriptorProto_ExtensionRange* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); }
+UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*);
+}
 
 UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) {
   _upb_sethas(msg, 1);
@@ -2666,10 +2886,10 @@
   _upb_sethas(msg, 3);
   *UPB_PTR_AT(msg, UPB_SIZE(12, 16), google_protobuf_ExtensionRangeOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_Arena *arena) {
   struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena);
+    sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub);
   }
@@ -2678,34 +2898,43 @@
 
 /* google.protobuf.DescriptorProto.ReservedRange */
 
-UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_new(upb_arena *arena) {
-  return (google_protobuf_DescriptorProto_ReservedRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena);
+UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_new(upb_Arena* arena) {
+  return (google_protobuf_DescriptorProto_ReservedRange*)_upb_Message_New(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena);
 }
-UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_DescriptorProto_ReservedRange *ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
+UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_DescriptorProto_ReservedRange *ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena, len);
+UPB_INLINE google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_ReservedRange_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_DescriptorProto_ReservedRange* ret = google_protobuf_DescriptorProto_ReservedRange_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_DescriptorProto_ReservedRange_serialize_ex(const google_protobuf_DescriptorProto_ReservedRange* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t);
+}
 
 UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) {
   _upb_sethas(msg, 1);
@@ -2718,42 +2947,47 @@
 
 /* google.protobuf.ExtensionRangeOptions */
 
-UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_new(upb_arena *arena) {
-  return (google_protobuf_ExtensionRangeOptions *)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena);
+UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_new(upb_Arena* arena) {
+  return (google_protobuf_ExtensionRangeOptions*)_upb_Message_New(&google_protobuf_ExtensionRangeOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_ExtensionRangeOptions *ret = google_protobuf_ExtensionRangeOptions_new(arena);
+UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_ExtensionRangeOptions *ret = google_protobuf_ExtensionRangeOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_ExtensionRangeOptions* google_protobuf_ExtensionRangeOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_ExtensionRangeOptions* ret = google_protobuf_ExtensionRangeOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_ExtensionRangeOptions_serialize_ex(const google_protobuf_ExtensionRangeOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2761,60 +2995,87 @@
 
 /* google.protobuf.FieldDescriptorProto */
 
-UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_FieldDescriptorProto *)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_FieldDescriptorProto*)_upb_Message_New(&google_protobuf_FieldDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_FieldDescriptorProto *ret = google_protobuf_FieldDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_FieldDescriptorProto *ret = google_protobuf_FieldDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_FieldDescriptorProto* google_protobuf_FieldDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_FieldDescriptorProto* ret = google_protobuf_FieldDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_FieldDescriptorProto_serialize_ex(const google_protobuf_FieldDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FieldDescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); }
-UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); }
-UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); }
-UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_strview); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); }
-UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); }
-
-UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
-  _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_strview) = value;
+UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView);
 }
-UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), int32_t);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto* msg) {
+  return google_protobuf_FieldDescriptorProto_has_label(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1;
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto* msg) {
+  return google_protobuf_FieldDescriptorProto_has_type(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) : 1;
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 6); }
+UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 7); }
+UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 8); }
+UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(64, 104), const google_protobuf_FieldOptions*);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 9); }
+UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 10); }
+UPB_INLINE upb_StringView google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_hasbit(msg, 11); }
+UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool);
+}
+
+UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) {
+  _upb_sethas(msg, 1);
+  *UPB_PTR_AT(msg, UPB_SIZE(24, 24), upb_StringView) = value;
+}
+UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 40), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
   _upb_sethas(msg, 3);
@@ -2828,22 +3089,22 @@
   _upb_sethas(msg, 5);
   *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
 }
-UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 6);
-  *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(40, 56), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 7);
-  *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(48, 72), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) {
   _upb_sethas(msg, 8);
   *UPB_PTR_AT(msg, UPB_SIZE(64, 104), google_protobuf_FieldOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_FieldOptions*)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena);
+    sub = (struct google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_FieldDescriptorProto_set_options(msg, sub);
   }
@@ -2853,9 +3114,9 @@
   _upb_sethas(msg, 9);
   *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value;
 }
-UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 10);
-  *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(56, 88), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) {
   _upb_sethas(msg, 11);
@@ -2864,47 +3125,56 @@
 
 /* google.protobuf.OneofDescriptorProto */
 
-UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_OneofDescriptorProto *)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_OneofDescriptorProto*)_upb_Message_New(&google_protobuf_OneofDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_OneofDescriptorProto *ret = google_protobuf_OneofDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_OneofDescriptorProto *ret = google_protobuf_OneofDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_OneofDescriptorProto* google_protobuf_OneofDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_OneofDescriptorProto* ret = google_protobuf_OneofDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
+}
+UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_OneofDescriptorProto_serialize_ex(const google_protobuf_OneofDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_OneofDescriptorProto_msginit, options, arena, len);
+}
+UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE upb_StringView google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*);
 }
 
-UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); }
-
-UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) {
   _upb_sethas(msg, 2);
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_OneofOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_OneofOptions*)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena);
+    sub = (struct google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_OneofDescriptorProto_set_options(msg, sub);
   }
@@ -2913,53 +3183,62 @@
 
 /* google.protobuf.EnumDescriptorProto */
 
-UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_EnumDescriptorProto *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_EnumDescriptorProto*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_EnumDescriptorProto *ret = google_protobuf_EnumDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_EnumDescriptorProto *ret = google_protobuf_EnumDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_EnumDescriptorProto* google_protobuf_EnumDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_EnumDescriptorProto* ret = google_protobuf_EnumDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_EnumDescriptorProto_serialize_ex(const google_protobuf_EnumDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
 UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); }
+UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*);
+}
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); }
 UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
-UPB_INLINE upb_strview const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
+UPB_INLINE upb_StringView const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
 
-UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
 UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto *msg, size_t *len) {
   return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
 }
-UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_EnumValueDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -2968,10 +3247,10 @@
   _upb_sethas(msg, 2);
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_EnumOptions*)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena);
+    sub = (struct google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_EnumDescriptorProto_set_options(msg, sub);
   }
@@ -2980,57 +3259,66 @@
 UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t *len) {
   return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
 }
-UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(20, 40), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
-UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
+UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) {
+  return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
 }
-UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena);
+UPB_INLINE upb_StringView* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, UPB_SIZE(3, 4), arena);
 }
-UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val,
+UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_StringView val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), UPB_SIZE(3, 4), &val,
       arena);
 }
 
 /* google.protobuf.EnumDescriptorProto.EnumReservedRange */
 
-UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_arena *arena) {
-  return (google_protobuf_EnumDescriptorProto_EnumReservedRange *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_Arena* arena) {
+  return (google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_Message_New(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena);
 }
-UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_EnumDescriptorProto_EnumReservedRange *ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
+UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_EnumDescriptorProto_EnumReservedRange *ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena, len);
+UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_EnumReservedRange_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_EnumDescriptorProto_EnumReservedRange* ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize_ex(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t);
+}
 
 UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) {
   _upb_sethas(msg, 1);
@@ -3043,40 +3331,51 @@
 
 /* google.protobuf.EnumValueDescriptorProto */
 
-UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_EnumValueDescriptorProto *)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_EnumValueDescriptorProto*)_upb_Message_New(&google_protobuf_EnumValueDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_EnumValueDescriptorProto *ret = google_protobuf_EnumValueDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_EnumValueDescriptorProto *ret = google_protobuf_EnumValueDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumValueDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_EnumValueDescriptorProto* ret = google_protobuf_EnumValueDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
+}
+UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_EnumValueDescriptorProto_serialize_ex(const google_protobuf_EnumValueDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, options, arena, len);
+}
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE upb_StringView google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
+UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
+UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*);
 }
 
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
-UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); }
-
-UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) {
   _upb_sethas(msg, 2);
@@ -3086,10 +3385,10 @@
   _upb_sethas(msg, 3);
   *UPB_PTR_AT(msg, UPB_SIZE(16, 24), google_protobuf_EnumValueOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_EnumValueOptions*)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena);
+    sub = (struct google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_EnumValueDescriptorProto_set_options(msg, sub);
   }
@@ -3098,50 +3397,59 @@
 
 /* google.protobuf.ServiceDescriptorProto */
 
-UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_ServiceDescriptorProto *)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_ServiceDescriptorProto*)_upb_Message_New(&google_protobuf_ServiceDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_ServiceDescriptorProto *ret = google_protobuf_ServiceDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_ServiceDescriptorProto *ret = google_protobuf_ServiceDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_ServiceDescriptorProto* google_protobuf_ServiceDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_ServiceDescriptorProto* ret = google_protobuf_ServiceDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_ServiceDescriptorProto_serialize_ex(const google_protobuf_ServiceDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); }
 UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); }
 UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); }
+UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*);
+}
 
-UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
 UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto *msg, size_t *len) {
   return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len);
 }
-UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_MethodDescriptorProto**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 32), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) {
-  struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) {
+  struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(16, 32), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3150,10 +3458,10 @@
   _upb_sethas(msg, 2);
   *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_ServiceOptions*)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena);
+    sub = (struct google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_ServiceDescriptorProto_set_options(msg, sub);
   }
@@ -3162,63 +3470,80 @@
 
 /* google.protobuf.MethodDescriptorProto */
 
-UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_new(upb_arena *arena) {
-  return (google_protobuf_MethodDescriptorProto *)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena);
+UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_new(upb_Arena* arena) {
+  return (google_protobuf_MethodDescriptorProto*)_upb_Message_New(&google_protobuf_MethodDescriptorProto_msginit, arena);
 }
-UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_MethodDescriptorProto *ret = google_protobuf_MethodDescriptorProto_new(arena);
+UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_MethodDescriptorProto *ret = google_protobuf_MethodDescriptorProto_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, arena, len);
+UPB_INLINE google_protobuf_MethodDescriptorProto* google_protobuf_MethodDescriptorProto_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_MethodDescriptorProto* ret = google_protobuf_MethodDescriptorProto_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_MethodDescriptorProto_serialize_ex(const google_protobuf_MethodDescriptorProto* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MethodDescriptorProto_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); }
+UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
+}
 UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
+UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool);
+}
 
-UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_StringView value) {
   _upb_sethas(msg, 3);
-  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) {
   _upb_sethas(msg, 4);
   *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value;
 }
-UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_arena *arena) {
+UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_Arena *arena) {
   struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg);
   if (sub == NULL) {
-    sub = (struct google_protobuf_MethodOptions*)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena);
+    sub = (struct google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena);
     if (!sub) return NULL;
     google_protobuf_MethodDescriptorProto_set_options(msg, sub);
   }
@@ -3235,80 +3560,125 @@
 
 /* google.protobuf.FileOptions */
 
-UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_new(upb_arena *arena) {
-  return (google_protobuf_FileOptions *)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena);
+UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_new(upb_Arena* arena) {
+  return (google_protobuf_FileOptions*)_upb_Message_New(&google_protobuf_FileOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_FileOptions *ret = google_protobuf_FileOptions_new(arena);
+UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_FileOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_FileOptions *ret = google_protobuf_FileOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_FileOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_FileOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_FileOptions* google_protobuf_FileOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_FileOptions* ret = google_protobuf_FileOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_FileOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_FileOptions_serialize_ex(const google_protobuf_FileOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FileOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions* msg) {
+  return google_protobuf_FileOptions_has_optimize_for(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) : 1;
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(9, 9), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 7); }
-UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(10, 10), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 8); }
-UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(11, 11), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 9); }
-UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 10); }
-UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 11); }
-UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 12); }
-UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions* msg) {
+  return google_protobuf_FileOptions_has_cc_enable_arenas(msg) ? *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) : true;
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 13); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 14); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 15); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 16); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 17); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 18); }
-UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); }
+UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 19); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_hasbit(msg, 20); }
-UPB_INLINE upb_strview google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(100, 184)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(100, 184), len); }
 
-UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(20, 24), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(28, 40), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) {
   _upb_sethas(msg, 3);
@@ -3318,9 +3688,9 @@
   _upb_sethas(msg, 4);
   *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 5);
-  *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(36, 56), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) {
   _upb_sethas(msg, 6);
@@ -3350,47 +3720,47 @@
   _upb_sethas(msg, 12);
   *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 13);
-  *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(44, 72), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 14);
-  *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(52, 88), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 15);
-  *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(60, 104), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 16);
-  *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(68, 120), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 17);
-  *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(76, 136), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) {
   _upb_sethas(msg, 18);
   *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 19);
-  *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(84, 152), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_StringView value) {
   _upb_sethas(msg, 20);
-  *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(92, 168), upb_StringView) = value;
 }
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(100, 184), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(100, 184), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(100, 184), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3398,38 +3768,51 @@
 
 /* google.protobuf.MessageOptions */
 
-UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_new(upb_arena *arena) {
-  return (google_protobuf_MessageOptions *)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena);
+UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_new(upb_Arena* arena) {
+  return (google_protobuf_MessageOptions*)_upb_Message_New(&google_protobuf_MessageOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_MessageOptions *ret = google_protobuf_MessageOptions_new(arena);
+UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_MessageOptions *ret = google_protobuf_MessageOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_MessageOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_MessageOptions* google_protobuf_MessageOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_MessageOptions* ret = google_protobuf_MessageOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_MessageOptions_serialize_ex(const google_protobuf_MessageOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MessageOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
+}
 UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
+UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool);
+}
 UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); }
+UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool);
+}
 UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); }
+UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool);
+}
 UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); }
 
@@ -3452,12 +3835,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(8, 8), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(8, 8), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3465,42 +3848,59 @@
 
 /* google.protobuf.FieldOptions */
 
-UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_new(upb_arena *arena) {
-  return (google_protobuf_FieldOptions *)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena);
+UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_new(upb_Arena* arena) {
+  return (google_protobuf_FieldOptions*)_upb_Message_New(&google_protobuf_FieldOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_FieldOptions *ret = google_protobuf_FieldOptions_new(arena);
+UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_FieldOptions *ret = google_protobuf_FieldOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_FieldOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_FieldOptions* google_protobuf_FieldOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_FieldOptions* ret = google_protobuf_FieldOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_FieldOptions_serialize_ex(const google_protobuf_FieldOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_FieldOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 12), bool);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(13, 13), bool);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(14, 14), bool);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool); }
+UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(15, 15), bool);
+}
 UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 16)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(16, 16), len); }
 
@@ -3531,12 +3931,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 16), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(16, 16), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(16, 16), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(16, 16), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3544,42 +3944,47 @@
 
 /* google.protobuf.OneofOptions */
 
-UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_new(upb_arena *arena) {
-  return (google_protobuf_OneofOptions *)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena);
+UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_new(upb_Arena* arena) {
+  return (google_protobuf_OneofOptions*)_upb_Message_New(&google_protobuf_OneofOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_OneofOptions *ret = google_protobuf_OneofOptions_new(arena);
+UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_OneofOptions *ret = google_protobuf_OneofOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_OneofOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_OneofOptions* google_protobuf_OneofOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_OneofOptions* ret = google_protobuf_OneofOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_OneofOptions_serialize_ex(const google_protobuf_OneofOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_OneofOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3587,34 +3992,43 @@
 
 /* google.protobuf.EnumOptions */
 
-UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_new(upb_arena *arena) {
-  return (google_protobuf_EnumOptions *)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena);
+UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_new(upb_Arena* arena) {
+  return (google_protobuf_EnumOptions*)_upb_Message_New(&google_protobuf_EnumOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_EnumOptions *ret = google_protobuf_EnumOptions_new(arena);
+UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_EnumOptions *ret = google_protobuf_EnumOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_EnumOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_EnumOptions* google_protobuf_EnumOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_EnumOptions* ret = google_protobuf_EnumOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_EnumOptions_serialize_ex(const google_protobuf_EnumOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
+}
 UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); }
+UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool);
+}
 UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
 
@@ -3629,12 +4043,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3642,32 +4056,39 @@
 
 /* google.protobuf.EnumValueOptions */
 
-UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_new(upb_arena *arena) {
-  return (google_protobuf_EnumValueOptions *)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena);
+UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_new(upb_Arena* arena) {
+  return (google_protobuf_EnumValueOptions*)_upb_Message_New(&google_protobuf_EnumValueOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_EnumValueOptions *ret = google_protobuf_EnumValueOptions_new(arena);
+UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_EnumValueOptions *ret = google_protobuf_EnumValueOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_EnumValueOptions* google_protobuf_EnumValueOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_EnumValueOptions* ret = google_protobuf_EnumValueOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_EnumValueOptions_serialize_ex(const google_protobuf_EnumValueOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_EnumValueOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
+}
 UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
 
@@ -3678,12 +4099,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3691,32 +4112,39 @@
 
 /* google.protobuf.ServiceOptions */
 
-UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_new(upb_arena *arena) {
-  return (google_protobuf_ServiceOptions *)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena);
+UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_new(upb_Arena* arena) {
+  return (google_protobuf_ServiceOptions*)_upb_Message_New(&google_protobuf_ServiceOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_ServiceOptions *ret = google_protobuf_ServiceOptions_new(arena);
+UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_ServiceOptions *ret = google_protobuf_ServiceOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_ServiceOptions* google_protobuf_ServiceOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_ServiceOptions* ret = google_protobuf_ServiceOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_ServiceOptions_serialize_ex(const google_protobuf_ServiceOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_ServiceOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
+UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
+}
 UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); }
 
@@ -3727,12 +4155,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(4, 8), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(4, 8), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3740,34 +4168,43 @@
 
 /* google.protobuf.MethodOptions */
 
-UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_new(upb_arena *arena) {
-  return (google_protobuf_MethodOptions *)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena);
+UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_new(upb_Arena* arena) {
+  return (google_protobuf_MethodOptions*)_upb_Message_New(&google_protobuf_MethodOptions_msginit, arena);
 }
-UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_MethodOptions *ret = google_protobuf_MethodOptions_new(arena);
+UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_MethodOptions *ret = google_protobuf_MethodOptions_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_MethodOptions_msginit, arena, len);
+UPB_INLINE google_protobuf_MethodOptions* google_protobuf_MethodOptions_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_MethodOptions* ret = google_protobuf_MethodOptions_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_MethodOptions_serialize_ex(const google_protobuf_MethodOptions* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_MethodOptions_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool); }
+UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), bool);
+}
 UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(12, 16)); }
 UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(12, 16), len); }
 
@@ -3782,12 +4219,12 @@
 UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(12, 16), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(12, 16), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(12, 16), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3795,61 +4232,78 @@
 
 /* google.protobuf.UninterpretedOption */
 
-UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_new(upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption *)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena);
+UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_new(upb_Arena* arena) {
+  return (google_protobuf_UninterpretedOption*)_upb_Message_New(&google_protobuf_UninterpretedOption_msginit, arena);
 }
-UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_UninterpretedOption *ret = google_protobuf_UninterpretedOption_new(arena);
+UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_UninterpretedOption *ret = google_protobuf_UninterpretedOption_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, arena, len);
+UPB_INLINE google_protobuf_UninterpretedOption* google_protobuf_UninterpretedOption_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_UninterpretedOption* ret = google_protobuf_UninterpretedOption_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_UninterpretedOption_serialize_ex(const google_protobuf_UninterpretedOption* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_UninterpretedOption_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); }
 UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); }
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); }
+UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); }
+UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 4); }
-UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); }
+UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 5); }
-UPB_INLINE upb_strview google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_hasbit(msg, 6); }
-UPB_INLINE upb_strview google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView);
+}
 
 UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) {
   return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len);
 }
-UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_UninterpretedOption_NamePart**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(56, 80), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_arena *arena) {
-  struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_Arena *arena) {
+  struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(56, 80), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
 }
-UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) {
   _upb_sethas(msg, 2);
@@ -3863,49 +4317,58 @@
   _upb_sethas(msg, 4);
   *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value;
 }
-UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) {
   _upb_sethas(msg, 5);
-  *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_StringView value) {
   _upb_sethas(msg, 6);
-  *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_StringView) = value;
 }
 
 /* google.protobuf.UninterpretedOption.NamePart */
 
-UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_new(upb_arena *arena) {
-  return (google_protobuf_UninterpretedOption_NamePart *)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena);
+UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_new(upb_Arena* arena) {
+  return (google_protobuf_UninterpretedOption_NamePart*)_upb_Message_New(&google_protobuf_UninterpretedOption_NamePart_msginit, arena);
 }
-UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_UninterpretedOption_NamePart *ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
+UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_UninterpretedOption_NamePart *ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, arena, len);
+UPB_INLINE google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_NamePart_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_UninterpretedOption_NamePart* ret = google_protobuf_UninterpretedOption_NamePart_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
+}
+UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_UninterpretedOption_NamePart_serialize_ex(const google_protobuf_UninterpretedOption_NamePart* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, options, arena, len);
+}
+UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); }
+UPB_INLINE upb_StringView google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
+UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); }
+UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool);
 }
 
-UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); }
-
-UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) {
   _upb_sethas(msg, 2);
@@ -3914,42 +4377,47 @@
 
 /* google.protobuf.SourceCodeInfo */
 
-UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_new(upb_arena *arena) {
-  return (google_protobuf_SourceCodeInfo *)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena);
+UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_new(upb_Arena* arena) {
+  return (google_protobuf_SourceCodeInfo*)_upb_Message_New(&google_protobuf_SourceCodeInfo_msginit, arena);
 }
-UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_SourceCodeInfo *ret = google_protobuf_SourceCodeInfo_new(arena);
+UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_SourceCodeInfo *ret = google_protobuf_SourceCodeInfo_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, arena, len);
+UPB_INLINE google_protobuf_SourceCodeInfo* google_protobuf_SourceCodeInfo_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_SourceCodeInfo* ret = google_protobuf_SourceCodeInfo_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_SourceCodeInfo_serialize_ex(const google_protobuf_SourceCodeInfo* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_SourceCodeInfo_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
 UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg, size_t *len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
 UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo *msg, size_t *len) {
   return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_SourceCodeInfo_Location**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_arena *arena) {
-  struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_Arena *arena) {
+  struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -3957,115 +4425,129 @@
 
 /* google.protobuf.SourceCodeInfo.Location */
 
-UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_new(upb_arena *arena) {
-  return (google_protobuf_SourceCodeInfo_Location *)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena);
+UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_new(upb_Arena* arena) {
+  return (google_protobuf_SourceCodeInfo_Location*)_upb_Message_New(&google_protobuf_SourceCodeInfo_Location_msginit, arena);
 }
-UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_SourceCodeInfo_Location *ret = google_protobuf_SourceCodeInfo_Location_new(arena);
+UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_SourceCodeInfo_Location *ret = google_protobuf_SourceCodeInfo_Location_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, arena, len);
+UPB_INLINE google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_Location_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_SourceCodeInfo_Location* ret = google_protobuf_SourceCodeInfo_Location_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_SourceCodeInfo_Location_serialize_ex(const google_protobuf_SourceCodeInfo_Location* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, options, arena, len);
+}
 UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); }
 UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); }
 UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); }
-UPB_INLINE upb_strview const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
+UPB_INLINE upb_StringView google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView);
+}
+UPB_INLINE upb_StringView const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_StringView const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); }
 
 UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) {
   return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len);
 }
-UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
-  return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena);
+UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) {
+  return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 40), len, 2, arena);
 }
-UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(20, 40), 2, &val,
+UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 40), 2, &val,
       arena);
 }
 UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) {
   return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len);
 }
-UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
-  return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena);
+UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) {
+  return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(24, 48), len, 2, arena);
 }
-UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(24, 48), 2, &val,
+UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(24, 48), 2, &val,
       arena);
 }
-UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_StringView) = value;
 }
-UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView value) {
   _upb_sethas(msg, 2);
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_StringView) = value;
 }
-UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) {
-  return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
+UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) {
+  return (upb_StringView*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len);
 }
-UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) {
-  return (upb_strview*)_upb_array_resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
+UPB_INLINE upb_StringView* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_Arena *arena) {
+  return (upb_StringView*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(28, 56), len, UPB_SIZE(3, 4), arena);
 }
-UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
+UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_StringView val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(28, 56), UPB_SIZE(3, 4), &val,
       arena);
 }
 
 /* google.protobuf.GeneratedCodeInfo */
 
-UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_new(upb_arena *arena) {
-  return (google_protobuf_GeneratedCodeInfo *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena);
+UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_new(upb_Arena* arena) {
+  return (google_protobuf_GeneratedCodeInfo*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_msginit, arena);
 }
-UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_GeneratedCodeInfo *ret = google_protobuf_GeneratedCodeInfo_new(arena);
+UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_GeneratedCodeInfo *ret = google_protobuf_GeneratedCodeInfo_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, arena, len);
+UPB_INLINE google_protobuf_GeneratedCodeInfo* google_protobuf_GeneratedCodeInfo_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_GeneratedCodeInfo* ret = google_protobuf_GeneratedCodeInfo_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_GeneratedCodeInfo_serialize_ex(const google_protobuf_GeneratedCodeInfo* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, options, arena, len);
+}
 UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); }
 UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg, size_t *len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); }
 
 UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t *len) {
   return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len);
 }
-UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_arena *arena) {
-  return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
+UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_Arena *arena) {
+  return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_Array_Resize_accessor2(msg, UPB_SIZE(0, 0), len, UPB_SIZE(2, 3), arena);
 }
-UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena) {
-  struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena);
-  bool ok = _upb_array_append_accessor2(
+UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_Arena *arena) {
+  struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena);
+  bool ok = _upb_Array_Append_accessor2(
       msg, UPB_SIZE(0, 0), UPB_SIZE(2, 3), &sub, arena);
   if (!ok) return NULL;
   return sub;
@@ -4073,51 +4555,62 @@
 
 /* google.protobuf.GeneratedCodeInfo.Annotation */
 
-UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_new(upb_arena *arena) {
-  return (google_protobuf_GeneratedCodeInfo_Annotation *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena);
+UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_new(upb_Arena* arena) {
+  return (google_protobuf_GeneratedCodeInfo_Annotation*)_upb_Message_New(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena);
 }
-UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parse(const char *buf, size_t size,
-                        upb_arena *arena) {
-  google_protobuf_GeneratedCodeInfo_Annotation *ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
+UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse(const char* buf, size_t size, upb_Arena* arena) {
+  google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
   if (!ret) return NULL;
-  if (!upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena)) return NULL;
-  return ret;
-}
-UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char *buf, size_t size,
-                           const upb_extreg *extreg, int options,
-                           upb_arena *arena) {
-  google_protobuf_GeneratedCodeInfo_Annotation *ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
-  if (!ret) return NULL;
-  if (!_upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, extreg, options, arena)) {
+  if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
     return NULL;
   }
   return ret;
 }
-UPB_INLINE char *google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_arena *arena, size_t *len) {
-  return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena, len);
+UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_Annotation_parse_ex(const char* buf, size_t size,
+                           const upb_ExtensionRegistry* extreg,
+                           int options, upb_Arena* arena) {
+  google_protobuf_GeneratedCodeInfo_Annotation* ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena);
+  if (!ret) return NULL;
+  if (upb_Decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, extreg, options, arena) !=
+      kUpb_DecodeStatus_Ok) {
+    return NULL;
+  }
+  return ret;
 }
-
+UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation* msg, upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, 0, arena, len);
+}
+UPB_INLINE char* google_protobuf_GeneratedCodeInfo_Annotation_serialize_ex(const google_protobuf_GeneratedCodeInfo_Annotation* msg, int options,
+                                 upb_Arena* arena, size_t* len) {
+  return upb_Encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, options, arena, len);
+}
 UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); }
 UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 1); }
-UPB_INLINE upb_strview google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview); }
+UPB_INLINE upb_StringView google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView);
+}
 UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 2); }
-UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); }
+UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t);
+}
 UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_hasbit(msg, 3); }
-UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); }
+UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation* msg) {
+  return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t);
+}
 
 UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) {
   return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len);
 }
-UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_arena *arena) {
-  return (int32_t*)_upb_array_resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena);
+UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_Arena *arena) {
+  return (int32_t*)_upb_Array_Resize_accessor2(msg, UPB_SIZE(20, 32), len, 2, arena);
 }
-UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_arena *arena) {
-  return _upb_array_append_accessor2(msg, UPB_SIZE(20, 32), 2, &val,
+UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_Arena *arena) {
+  return _upb_Array_Append_accessor2(msg, UPB_SIZE(20, 32), 2, &val,
       arena);
 }
-UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_strview value) {
+UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_StringView value) {
   _upb_sethas(msg, 1);
-  *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview) = value;
+  *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_StringView) = value;
 }
 UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) {
   _upb_sethas(msg, 2);
@@ -4128,6 +4621,12 @@
   *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value;
 }
 
+extern const upb_MiniTable_File google_protobuf_descriptor_proto_upb_file_layout;
+
+/* Max size 32 is google.protobuf.FileOptions */
+/* Max size 64 is google.protobuf.FileOptions */
+#define _UPB_MAXOPT_SIZE UPB_SIZE(104, 192)
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
@@ -4136,19 +4635,6 @@
 #endif  /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */
 
 /** upb/def.h ************************************************************/
-/*
- * Defs are upb's internal representation of the constructs that can appear
- * in a .proto file:
- *
- * - upb_msgdef: describes a "message" construct.
- * - upb_fielddef: describes a message field.
- * - upb_filedef: describes a .proto file and its defs.
- * - upb_enumdef: describes an enum.
- * - upb_oneofdef: describes a oneof.
- *
- * TODO: definitions of services.
- */
-
 #ifndef UPB_DEF_H_
 #define UPB_DEF_H_
 
@@ -4157,288 +4643,364 @@
 
 #ifdef __cplusplus
 extern "C" {
-#endif  /* __cplusplus */
+#endif /* __cplusplus */
 
-struct upb_enumdef;
-typedef struct upb_enumdef upb_enumdef;
-struct upb_fielddef;
-typedef struct upb_fielddef upb_fielddef;
-struct upb_filedef;
-typedef struct upb_filedef upb_filedef;
-struct upb_msgdef;
-typedef struct upb_msgdef upb_msgdef;
-struct upb_oneofdef;
-typedef struct upb_oneofdef upb_oneofdef;
-struct upb_symtab;
-typedef struct upb_symtab upb_symtab;
+struct upb_EnumDef;
+typedef struct upb_EnumDef upb_EnumDef;
+struct upb_EnumValueDef;
+typedef struct upb_EnumValueDef upb_EnumValueDef;
+struct upb_ExtensionRange;
+typedef struct upb_ExtensionRange upb_ExtensionRange;
+struct upb_FieldDef;
+typedef struct upb_FieldDef upb_FieldDef;
+struct upb_FileDef;
+typedef struct upb_FileDef upb_FileDef;
+struct upb_MethodDef;
+typedef struct upb_MethodDef upb_MethodDef;
+struct upb_MessageDef;
+typedef struct upb_MessageDef upb_MessageDef;
+struct upb_OneofDef;
+typedef struct upb_OneofDef upb_OneofDef;
+struct upb_ServiceDef;
+typedef struct upb_ServiceDef upb_ServiceDef;
+struct upb_streamdef;
+typedef struct upb_streamdef upb_streamdef;
+struct upb_DefPool;
+typedef struct upb_DefPool upb_DefPool;
 
-typedef enum {
-  UPB_SYNTAX_PROTO2 = 2,
-  UPB_SYNTAX_PROTO3 = 3
-} upb_syntax_t;
+typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax;
 
 /* All the different kind of well known type messages. For simplicity of check,
  * number wrappers and string wrappers are grouped together. Make sure the
  * order and merber of these groups are not changed.
  */
 typedef enum {
-  UPB_WELLKNOWN_UNSPECIFIED,
-  UPB_WELLKNOWN_ANY,
-  UPB_WELLKNOWN_FIELDMASK,
-  UPB_WELLKNOWN_DURATION,
-  UPB_WELLKNOWN_TIMESTAMP,
+  kUpb_WellKnown_Unspecified,
+  kUpb_WellKnown_Any,
+  kUpb_WellKnown_FieldMask,
+  kUpb_WellKnown_Duration,
+  kUpb_WellKnown_Timestamp,
   /* number wrappers */
-  UPB_WELLKNOWN_DOUBLEVALUE,
-  UPB_WELLKNOWN_FLOATVALUE,
-  UPB_WELLKNOWN_INT64VALUE,
-  UPB_WELLKNOWN_UINT64VALUE,
-  UPB_WELLKNOWN_INT32VALUE,
-  UPB_WELLKNOWN_UINT32VALUE,
+  kUpb_WellKnown_DoubleValue,
+  kUpb_WellKnown_FloatValue,
+  kUpb_WellKnown_Int64Value,
+  kUpb_WellKnown_UInt64Value,
+  kUpb_WellKnown_Int32Value,
+  kUpb_WellKnown_UInt32Value,
   /* string wrappers */
-  UPB_WELLKNOWN_STRINGVALUE,
-  UPB_WELLKNOWN_BYTESVALUE,
-  UPB_WELLKNOWN_BOOLVALUE,
-  UPB_WELLKNOWN_VALUE,
-  UPB_WELLKNOWN_LISTVALUE,
-  UPB_WELLKNOWN_STRUCT
-} upb_wellknowntype_t;
+  kUpb_WellKnown_StringValue,
+  kUpb_WellKnown_BytesValue,
+  kUpb_WellKnown_BoolValue,
+  kUpb_WellKnown_Value,
+  kUpb_WellKnown_ListValue,
+  kUpb_WellKnown_Struct
+} upb_WellKnown;
 
-/* upb_fielddef ***************************************************************/
+/* upb_FieldDef ***************************************************************/
 
 /* Maximum field number allowed for FieldDefs.  This is an inherent limit of the
  * protobuf wire format. */
-#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
+#define kUpb_MaxFieldNumber ((1 << 29) - 1)
 
-const char *upb_fielddef_fullname(const upb_fielddef *f);
-upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
-upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
-upb_label_t upb_fielddef_label(const upb_fielddef *f);
-uint32_t upb_fielddef_number(const upb_fielddef *f);
-const char *upb_fielddef_name(const upb_fielddef *f);
-const char *upb_fielddef_jsonname(const upb_fielddef *f);
-bool upb_fielddef_isextension(const upb_fielddef *f);
-bool upb_fielddef_lazy(const upb_fielddef *f);
-bool upb_fielddef_packed(const upb_fielddef *f);
-const upb_filedef *upb_fielddef_file(const upb_fielddef *f);
-const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
-const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
-const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f);
-uint32_t upb_fielddef_index(const upb_fielddef *f);
-bool upb_fielddef_issubmsg(const upb_fielddef *f);
-bool upb_fielddef_isstring(const upb_fielddef *f);
-bool upb_fielddef_isseq(const upb_fielddef *f);
-bool upb_fielddef_isprimitive(const upb_fielddef *f);
-bool upb_fielddef_ismap(const upb_fielddef *f);
-int64_t upb_fielddef_defaultint64(const upb_fielddef *f);
-int32_t upb_fielddef_defaultint32(const upb_fielddef *f);
-uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f);
-uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f);
-bool upb_fielddef_defaultbool(const upb_fielddef *f);
-float upb_fielddef_defaultfloat(const upb_fielddef *f);
-double upb_fielddef_defaultdouble(const upb_fielddef *f);
-const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
-bool upb_fielddef_hassubdef(const upb_fielddef *f);
-bool upb_fielddef_haspresence(const upb_fielddef *f);
-const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
-const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
-const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f);
+const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f);
+bool upb_FieldDef_HasOptions(const upb_FieldDef* f);
+const char* upb_FieldDef_FullName(const upb_FieldDef* f);
+upb_CType upb_FieldDef_CType(const upb_FieldDef* f);
+upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f);
+upb_Label upb_FieldDef_Label(const upb_FieldDef* f);
+uint32_t upb_FieldDef_Number(const upb_FieldDef* f);
+const char* upb_FieldDef_Name(const upb_FieldDef* f);
+const char* upb_FieldDef_JsonName(const upb_FieldDef* f);
+bool upb_FieldDef_HasJsonName(const upb_FieldDef* f);
+bool upb_FieldDef_IsExtension(const upb_FieldDef* f);
+bool upb_FieldDef_IsPacked(const upb_FieldDef* f);
+const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f);
+const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f);
+const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f);
+const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f);
+const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f);
+uint32_t upb_FieldDef_Index(const upb_FieldDef* f);
+bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f);
+bool upb_FieldDef_IsString(const upb_FieldDef* f);
+bool upb_FieldDef_IsRepeated(const upb_FieldDef* f);
+bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f);
+bool upb_FieldDef_IsMap(const upb_FieldDef* f);
+bool upb_FieldDef_HasDefault(const upb_FieldDef* f);
+bool upb_FieldDef_HasSubDef(const upb_FieldDef* f);
+bool upb_FieldDef_HasPresence(const upb_FieldDef* f);
+const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f);
+const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f);
+const upb_MiniTable_Field* upb_FieldDef_MiniTable(const upb_FieldDef* f);
+const upb_MiniTable_Extension* _upb_FieldDef_ExtensionMiniTable(
+    const upb_FieldDef* f);
+bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f);
 
-/* upb_oneofdef ***************************************************************/
+/* upb_OneofDef ***************************************************************/
 
-typedef upb_inttable_iter upb_oneof_iter;
-
-const char *upb_oneofdef_name(const upb_oneofdef *o);
-const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
-uint32_t upb_oneofdef_index(const upb_oneofdef *o);
-bool upb_oneofdef_issynthetic(const upb_oneofdef *o);
-int upb_oneofdef_fieldcount(const upb_oneofdef *o);
-const upb_fielddef *upb_oneofdef_field(const upb_oneofdef *o, int i);
+const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o);
+bool upb_OneofDef_HasOptions(const upb_OneofDef* o);
+const char* upb_OneofDef_Name(const upb_OneofDef* o);
+const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o);
+uint32_t upb_OneofDef_Index(const upb_OneofDef* o);
+bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o);
+int upb_OneofDef_FieldCount(const upb_OneofDef* o);
+const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i);
 
 /* Oneof lookups:
  * - ntof:  look up a field by name.
  * - ntofz: look up a field by name (as a null-terminated string).
  * - itof:  look up a field by number. */
-const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
-                                      const char *name, size_t length);
-UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
-                                                  const char *name) {
-  return upb_oneofdef_ntof(o, name, strlen(name));
+const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o,
+                                                    const char* name,
+                                                    size_t length);
+UPB_INLINE const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o,
+                                                       const char* name) {
+  return upb_OneofDef_LookupNameWithSize(o, name, strlen(name));
 }
-const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
+const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o,
+                                              uint32_t num);
 
-/* DEPRECATED, slated for removal. */
-int upb_oneofdef_numfields(const upb_oneofdef *o);
-void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
-void upb_oneof_next(upb_oneof_iter *iter);
-bool upb_oneof_done(upb_oneof_iter *iter);
-upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
-void upb_oneof_iter_setdone(upb_oneof_iter *iter);
-bool upb_oneof_iter_isequal(const upb_oneof_iter *iter1,
-                            const upb_oneof_iter *iter2);
-/* END DEPRECATED */
-
-/* upb_msgdef *****************************************************************/
-
-typedef upb_inttable_iter upb_msg_field_iter;
-typedef upb_strtable_iter upb_msg_oneof_iter;
+/* upb_MessageDef *************************************************************/
 
 /* Well-known field tag numbers for map-entry messages. */
-#define UPB_MAPENTRY_KEY   1
-#define UPB_MAPENTRY_VALUE 2
+#define kUpb_MapEntry_KeyFieldNumber 1
+#define kUpb_MapEntry_ValueFieldNumber 2
 
 /* Well-known field tag numbers for Any messages. */
-#define UPB_ANY_TYPE 1
-#define UPB_ANY_VALUE 2
+#define kUpb_Any_TypeFieldNumber 1
+#define kUpb_Any_ValueFieldNumber 2
 
 /* Well-known field tag numbers for timestamp messages. */
-#define UPB_DURATION_SECONDS 1
-#define UPB_DURATION_NANOS 2
+#define kUpb_Duration_SecondsFieldNumber 1
+#define kUpb_Duration_NanosFieldNumber 2
 
 /* Well-known field tag numbers for duration messages. */
-#define UPB_TIMESTAMP_SECONDS 1
-#define UPB_TIMESTAMP_NANOS 2
+#define kUpb_Timestamp_SecondsFieldNumber 1
+#define kUpb_Timestamp_NanosFieldNumber 2
 
-const char *upb_msgdef_fullname(const upb_msgdef *m);
-const upb_filedef *upb_msgdef_file(const upb_msgdef *m);
-const char *upb_msgdef_name(const upb_msgdef *m);
-upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m);
-bool upb_msgdef_mapentry(const upb_msgdef *m);
-upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m);
-bool upb_msgdef_iswrapper(const upb_msgdef *m);
-bool upb_msgdef_isnumberwrapper(const upb_msgdef *m);
-int upb_msgdef_fieldcount(const upb_msgdef *m);
-int upb_msgdef_oneofcount(const upb_msgdef *m);
-const upb_fielddef *upb_msgdef_field(const upb_msgdef *m, int i);
-const upb_oneofdef *upb_msgdef_oneof(const upb_msgdef *m, int i);
-const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
-const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
-                                    size_t len);
-const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
-                                    size_t len);
-const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m);
+const google_protobuf_MessageOptions* upb_MessageDef_Options(
+    const upb_MessageDef* m);
+bool upb_MessageDef_HasOptions(const upb_MessageDef* m);
+const char* upb_MessageDef_FullName(const upb_MessageDef* m);
+const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m);
+const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m);
+const char* upb_MessageDef_Name(const upb_MessageDef* m);
+upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m);
+upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m);
+int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m);
+int upb_MessageDef_FieldCount(const upb_MessageDef* m);
+int upb_MessageDef_OneofCount(const upb_MessageDef* m);
+const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m,
+                                                        int i);
+const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i);
+const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i);
+const upb_FieldDef* upb_MessageDef_FindFieldByNumberWithSize(
+    const upb_MessageDef* m, uint32_t i);
+const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len);
+const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len);
+const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m);
 
-UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
-                                               const char *name) {
-  return upb_msgdef_ntoo(m, name, strlen(name));
+UPB_INLINE const upb_OneofDef* upb_MessageDef_FindOneofByName(
+    const upb_MessageDef* m, const char* name) {
+  return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name));
 }
 
-UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
-                                                const char *name) {
-  return upb_msgdef_ntof(m, name, strlen(name));
+UPB_INLINE const upb_FieldDef* upb_MessageDef_FindFieldByName(
+    const upb_MessageDef* m, const char* name) {
+  return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name));
 }
 
+UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) {
+  return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m));
+}
+
+/* Nested entities. */
+int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m);
+int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m);
+int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m);
+const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m,
+                                                   int i);
+const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i);
+const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m,
+                                                   int i);
+
 /* Lookup of either field or oneof by name.  Returns whether either was found.
  * If the return is true, then the found def will be set, and the non-found
  * one set to NULL. */
-bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
-                           const upb_fielddef **f, const upb_oneofdef **o);
+bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m,
+                                       const char* name, size_t len,
+                                       const upb_FieldDef** f,
+                                       const upb_OneofDef** o);
 
-UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name,
-                                       const upb_fielddef **f,
-                                       const upb_oneofdef **o) {
-  return upb_msgdef_lookupname(m, name, strlen(name), f, o);
+UPB_INLINE bool upb_MessageDef_FindByName(const upb_MessageDef* m,
+                                          const char* name,
+                                          const upb_FieldDef** f,
+                                          const upb_OneofDef** o) {
+  return upb_MessageDef_FindByNameWithSize(m, name, strlen(name), f, o);
 }
 
 /* Returns a field by either JSON name or regular proto name. */
-const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m,
-                                              const char *name, size_t len);
-
-/* DEPRECATED, slated for removal */
-int upb_msgdef_numfields(const upb_msgdef *m);
-int upb_msgdef_numoneofs(const upb_msgdef *m);
-int upb_msgdef_numrealoneofs(const upb_msgdef *m);
-void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
-void upb_msg_field_next(upb_msg_field_iter *iter);
-bool upb_msg_field_done(const upb_msg_field_iter *iter);
-upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
-void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
-bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1,
-                                const upb_msg_field_iter * iter2);
-void upb_msg_oneof_begin(upb_msg_oneof_iter * iter, const upb_msgdef *m);
-void upb_msg_oneof_next(upb_msg_oneof_iter * iter);
-bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
-const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
-void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter * iter);
-bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1,
-                                const upb_msg_oneof_iter *iter2);
-/* END DEPRECATED */
-
-/* upb_enumdef ****************************************************************/
-
-typedef upb_strtable_iter upb_enum_iter;
-
-const char *upb_enumdef_fullname(const upb_enumdef *e);
-const char *upb_enumdef_name(const upb_enumdef *e);
-const upb_filedef *upb_enumdef_file(const upb_enumdef *e);
-int32_t upb_enumdef_default(const upb_enumdef *e);
-int upb_enumdef_numvals(const upb_enumdef *e);
-
-/* Enum lookups:
- * - ntoi:  look up a name with specified length.
- * - ntoiz: look up a name provided as a null-terminated string.
- * - iton:  look up an integer, returning the name as a null-terminated
- *          string. */
-bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
-                      int32_t *num);
-UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
-                                  const char *name, int32_t *num) {
-  return upb_enumdef_ntoi(e, name, strlen(name), num);
+const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize(
+    const upb_MessageDef* m, const char* name, size_t len);
+UPB_INLINE const upb_FieldDef* upb_MessageDef_FindByJsonName(
+    const upb_MessageDef* m, const char* name) {
+  return upb_MessageDef_FindByJsonNameWithSize(m, name, strlen(name));
 }
-const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
 
-void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
-void upb_enum_next(upb_enum_iter *iter);
-bool upb_enum_done(upb_enum_iter *iter);
-const char *upb_enum_iter_name(upb_enum_iter *iter);
-int32_t upb_enum_iter_number(upb_enum_iter *iter);
+/* upb_ExtensionRange *********************************************************/
 
-/* upb_filedef ****************************************************************/
+const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options(
+    const upb_ExtensionRange* r);
+bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r);
+int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r);
+int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r);
 
-const char *upb_filedef_name(const upb_filedef *f);
-const char *upb_filedef_package(const upb_filedef *f);
-const char *upb_filedef_phpprefix(const upb_filedef *f);
-const char *upb_filedef_phpnamespace(const upb_filedef *f);
-upb_syntax_t upb_filedef_syntax(const upb_filedef *f);
-int upb_filedef_depcount(const upb_filedef *f);
-int upb_filedef_msgcount(const upb_filedef *f);
-int upb_filedef_enumcount(const upb_filedef *f);
-const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i);
-const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i);
-const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i);
-const upb_symtab *upb_filedef_symtab(const upb_filedef *f);
+/* upb_EnumDef ****************************************************************/
 
-/* upb_symtab *****************************************************************/
+const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e);
+bool upb_EnumDef_HasOptions(const upb_EnumDef* e);
+const char* upb_EnumDef_FullName(const upb_EnumDef* e);
+const char* upb_EnumDef_Name(const upb_EnumDef* e);
+const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e);
+const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e);
+int32_t upb_EnumDef_Default(const upb_EnumDef* e);
+int upb_EnumDef_ValueCount(const upb_EnumDef* e);
+const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i);
 
-upb_symtab *upb_symtab_new(void);
-void upb_symtab_free(upb_symtab* s);
-const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
-const upb_msgdef *upb_symtab_lookupmsg2(
-    const upb_symtab *s, const char *sym, size_t len);
-const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
-const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name);
-const upb_filedef *upb_symtab_lookupfile2(
-    const upb_symtab *s, const char *name, size_t len);
-int upb_symtab_filecount(const upb_symtab *s);
-const upb_filedef *upb_symtab_addfile(
-    upb_symtab *s, const google_protobuf_FileDescriptorProto *file,
-    upb_status *status);
-size_t _upb_symtab_bytesloaded(const upb_symtab *s);
-upb_arena *_upb_symtab_arena(const upb_symtab *s);
+const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize(
+    const upb_EnumDef* e, const char* name, size_t len);
+const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e,
+                                                      int32_t num);
+bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num);
+
+// Convenience wrapper.
+UPB_INLINE const upb_EnumValueDef* upb_EnumDef_FindValueByName(
+    const upb_EnumDef* e, const char* name) {
+  return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name));
+}
+
+/* upb_EnumValueDef ***********************************************************/
+
+const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options(
+    const upb_EnumValueDef* e);
+bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* e);
+const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* e);
+const char* upb_EnumValueDef_Name(const upb_EnumValueDef* e);
+int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* e);
+uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* e);
+const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* e);
+
+/* upb_FileDef ****************************************************************/
+
+const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f);
+bool upb_FileDef_HasOptions(const upb_FileDef* f);
+const char* upb_FileDef_Name(const upb_FileDef* f);
+const char* upb_FileDef_Package(const upb_FileDef* f);
+upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f);
+int upb_FileDef_DependencyCount(const upb_FileDef* f);
+int upb_FileDef_PublicDependencyCount(const upb_FileDef* f);
+int upb_FileDef_WeakDependencyCount(const upb_FileDef* f);
+int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f);
+int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f);
+int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f);
+int upb_FileDef_ServiceCount(const upb_FileDef* f);
+const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i);
+const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i);
+const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i);
+const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i);
+const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i);
+const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i);
+const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i);
+const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f);
+const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f);
+const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f);
+
+/* upb_MethodDef **************************************************************/
+
+const google_protobuf_MethodOptions* upb_MethodDef_Options(
+    const upb_MethodDef* m);
+bool upb_MethodDef_HasOptions(const upb_MethodDef* m);
+const char* upb_MethodDef_FullName(const upb_MethodDef* m);
+const char* upb_MethodDef_Name(const upb_MethodDef* m);
+const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m);
+const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m);
+const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m);
+bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m);
+bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m);
+
+/* upb_ServiceDef *************************************************************/
+
+const google_protobuf_ServiceOptions* upb_ServiceDef_Options(
+    const upb_ServiceDef* s);
+bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s);
+const char* upb_ServiceDef_FullName(const upb_ServiceDef* s);
+const char* upb_ServiceDef_Name(const upb_ServiceDef* s);
+int upb_ServiceDef_Index(const upb_ServiceDef* s);
+const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s);
+int upb_ServiceDef_MethodCount(const upb_ServiceDef* s);
+const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i);
+const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s,
+                                                     const char* name);
+
+/* upb_DefPool ****************************************************************/
+
+upb_DefPool* upb_DefPool_New(void);
+void upb_DefPool_Free(upb_DefPool* s);
+const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s,
+                                                    const char* sym);
+const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize(
+    const upb_DefPool* s, const char* sym, size_t len);
+const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s,
+                                              const char* sym);
+const upb_EnumValueDef* upb_DefPool_FindEnumByNameval(const upb_DefPool* s,
+                                                      const char* sym);
+const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s,
+                                                    const char* sym);
+const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize(
+    const upb_DefPool* s, const char* sym, size_t len);
+const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s,
+                                              const char* name);
+const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s,
+                                                    const char* name);
+const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize(
+    const upb_DefPool* s, const char* name, size_t size);
+const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s,
+                                                        const char* name);
+const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s,
+                                                      const char* name,
+                                                      size_t len);
+const upb_FileDef* upb_DefPool_AddFile(
+    upb_DefPool* s, const google_protobuf_FileDescriptorProto* file,
+    upb_Status* status);
+size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s);
+upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s);
+const upb_FieldDef* _upb_DefPool_FindExtensionByMiniTable(
+    const upb_DefPool* s, const upb_MiniTable_Extension* ext);
+const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s,
+                                                      const upb_MessageDef* m,
+                                                      int32_t fieldnum);
+const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry(
+    const upb_DefPool* s);
+const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s,
+                                                  const upb_MessageDef* m,
+                                                  size_t* count);
 
 /* For generated code only: loads a generated descriptor. */
-typedef struct upb_def_init {
-  struct upb_def_init **deps;     /* Dependencies of this file. */
-  const upb_msglayout **layouts;  /* Pre-order layouts of all messages. */
-  const char *filename;
-  upb_strview descriptor;         /* Serialized descriptor. */
-} upb_def_init;
+typedef struct _upb_DefPool_Init {
+  struct _upb_DefPool_Init** deps; /* Dependencies of this file. */
+  const upb_MiniTable_File* layout;
+  const char* filename;
+  upb_StringView descriptor; /* Serialized descriptor. */
+} _upb_DefPool_Init;
 
-bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init);
+bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init);
 
 
 #ifdef __cplusplus
-}  /* extern "C" */
-#endif  /* __cplusplus */
+} /* extern "C" */
+#endif /* __cplusplus */
 
 #endif /* UPB_DEF_H_ */
 
@@ -4447,7 +5009,6 @@
 #define UPB_REFLECTION_H_
 
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -4460,57 +5021,63 @@
   int64_t int64_val;
   uint32_t uint32_val;
   uint64_t uint64_val;
-  const upb_map* map_val;
-  const upb_msg* msg_val;
-  const upb_array* array_val;
-  upb_strview str_val;
-} upb_msgval;
+  const upb_Map* map_val;
+  const upb_Message* msg_val;
+  const upb_Array* array_val;
+  upb_StringView str_val;
+} upb_MessageValue;
 
 typedef union {
-  upb_map* map;
-  upb_msg* msg;
-  upb_array* array;
-} upb_mutmsgval;
+  upb_Map* map;
+  upb_Message* msg;
+  upb_Array* array;
+} upb_MutableMessageValue;
 
-upb_msgval upb_fielddef_default(const upb_fielddef *f);
+upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f);
 
-/** upb_msg *******************************************************************/
+/** upb_Message
+ * *******************************************************************/
 
 /* Creates a new message of the given type in the given arena. */
-upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a);
+upb_Message* upb_Message_New(const upb_MessageDef* m, upb_Arena* a);
 
 /* Returns the value associated with this field. */
-upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f);
+upb_MessageValue upb_Message_Get(const upb_Message* msg, const upb_FieldDef* f);
 
 /* Returns a mutable pointer to a map, array, or submessage value.  If the given
  * arena is non-NULL this will construct a new object if it was not previously
  * present.  May not be called for primitive fields. */
-upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a);
+upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg,
+                                            const upb_FieldDef* f,
+                                            upb_Arena* a);
 
-/* May only be called for fields where upb_fielddef_haspresence(f) == true. */
-bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f);
+/* May only be called for fields where upb_FieldDef_HasPresence(f) == true. */
+bool upb_Message_Has(const upb_Message* msg, const upb_FieldDef* f);
 
 /* Returns the field that is set in the oneof, or NULL if none are set. */
-const upb_fielddef *upb_msg_whichoneof(const upb_msg *msg,
-                                       const upb_oneofdef *o);
+const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg,
+                                           const upb_OneofDef* o);
 
 /* Sets the given field to the given value.  For a msg/array/map/string, the
- * value must be in the same arena.  */
-void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val,
-                 upb_arena *a);
+ * caller must ensure that the target data outlives |msg| (by living either in
+ * the same arena or a different arena that outlives it).
+ *
+ * Returns false if allocation fails. */
+bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f,
+                     upb_MessageValue val, upb_Arena* a);
 
 /* Clears any field presence and sets the value back to its default. */
-void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f);
+void upb_Message_ClearField(upb_Message* msg, const upb_FieldDef* f);
 
 /* Clear all data and unknown fields. */
-void upb_msg_clear(upb_msg *msg, const upb_msgdef *m);
+void upb_Message_Clear(upb_Message* msg, const upb_MessageDef* m);
 
 /* Iterate over present fields.
  *
- * size_t iter = UPB_MSG_BEGIN;
- * const upb_fielddef *f;
- * upb_msgval val;
- * while (upb_msg_next(msg, m, ext_pool, &f, &val, &iter)) {
+ * size_t iter = kUpb_Message_Begin;
+ * const upb_FieldDef *f;
+ * upb_MessageValue val;
+ * while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) {
  *   process_field(f, val);
  * }
  *
@@ -4519,90 +5086,109 @@
  * will be skipped.
  */
 
-#define UPB_MSG_BEGIN -1
-bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m,
-                  const upb_symtab *ext_pool, const upb_fielddef **f,
-                  upb_msgval *val, size_t *iter);
+#define kUpb_Message_Begin -1
+bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m,
+                      const upb_DefPool* ext_pool, const upb_FieldDef** f,
+                      upb_MessageValue* val, size_t* iter);
 
 /* Clears all unknown field data from this message and all submessages. */
-bool upb_msg_discardunknown(upb_msg *msg, const upb_msgdef *m, int maxdepth);
+bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m,
+                                int maxdepth);
 
-/** upb_array *****************************************************************/
+/** upb_Array *****************************************************************/
 
 /* Creates a new array on the given arena that holds elements of this type. */
-upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type);
+upb_Array* upb_Array_New(upb_Arena* a, upb_CType type);
 
 /* Returns the size of the array. */
-size_t upb_array_size(const upb_array *arr);
+size_t upb_Array_Size(const upb_Array* arr);
 
 /* Returns the given element, which must be within the array's current size. */
-upb_msgval upb_array_get(const upb_array *arr, size_t i);
+upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i);
 
 /* Sets the given element, which must be within the array's current size. */
-void upb_array_set(upb_array *arr, size_t i, upb_msgval val);
+void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val);
 
 /* Appends an element to the array.  Returns false on allocation failure. */
-bool upb_array_append(upb_array *array, upb_msgval val, upb_arena *arena);
+bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena);
+
+/* Moves elements within the array using memmove(). Like memmove(), the source
+ * and destination elements may be overlapping. */
+void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx,
+                    size_t count);
+
+/* Inserts one or more empty elements into the array.  Existing elements are
+ * shifted right.  The new elements have undefined state and must be set with
+ * `upb_Array_Set()`.
+ * REQUIRES: `i <= upb_Array_Size(arr)` */
+bool upb_Array_Insert(upb_Array* array, size_t i, size_t count,
+                      upb_Arena* arena);
+
+/* Deletes one or more elements from the array.  Existing elements are shifted
+ * left.
+ * REQUIRES: `i + count <= upb_Array_Size(arr)` */
+void upb_Array_Delete(upb_Array* array, size_t i, size_t count);
 
 /* Changes the size of a vector.  New elements are initialized to empty/0.
  * Returns false on allocation failure. */
-bool upb_array_resize(upb_array *array, size_t size, upb_arena *arena);
+bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena);
 
-/** upb_map *******************************************************************/
+/** upb_Map *******************************************************************/
 
 /* Creates a new map on the given arena with the given key/value size. */
-upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type,
-                     upb_fieldtype_t value_type);
+upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type);
 
 /* Returns the number of entries in the map. */
-size_t upb_map_size(const upb_map *map);
+size_t upb_Map_Size(const upb_Map* map);
 
 /* Stores a value for the given key into |*val| (or the zero value if the key is
  * not present).  Returns whether the key was present.  The |val| pointer may be
  * NULL, in which case the function tests whether the given key is present.  */
-bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val);
+bool upb_Map_Get(const upb_Map* map, upb_MessageValue key,
+                 upb_MessageValue* val);
 
 /* Removes all entries in the map. */
-void upb_map_clear(upb_map *map);
+void upb_Map_Clear(upb_Map* map);
 
 /* Sets the given key to the given value.  Returns true if this was a new key in
  * the map, or false if an existing key was replaced. */
-bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val,
-                 upb_arena *arena);
+bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val,
+                 upb_Arena* arena);
 
 /* Deletes this key from the table.  Returns true if the key was present. */
-bool upb_map_delete(upb_map *map, upb_msgval key);
+bool upb_Map_Delete(upb_Map* map, upb_MessageValue key);
 
 /* Map iteration:
  *
- * size_t iter = UPB_MAP_BEGIN;
- * while (upb_mapiter_next(map, &iter)) {
- *   upb_msgval key = upb_mapiter_key(map, iter);
- *   upb_msgval val = upb_mapiter_value(map, iter);
+ * size_t iter = kUpb_Map_Begin;
+ * while (upb_MapIterator_Next(map, &iter)) {
+ *   upb_MessageValue key = upb_MapIterator_Key(map, iter);
+ *   upb_MessageValue val = upb_MapIterator_Value(map, iter);
  *
  *   // If mutating is desired.
- *   upb_mapiter_setvalue(map, iter, value2);
+ *   upb_MapIterator_SetValue(map, iter, value2);
  * }
  */
 
 /* Advances to the next entry.  Returns false if no more entries are present. */
-bool upb_mapiter_next(const upb_map *map, size_t *iter);
+bool upb_MapIterator_Next(const upb_Map* map, size_t* iter);
 
 /* Returns true if the iterator still points to a valid entry, or false if the
  * iterator is past the last element. It is an error to call this function with
- * UPB_MAP_BEGIN (you must call next() at least once first). */
-bool upb_mapiter_done(const upb_map *map, size_t iter);
+ * kUpb_Map_Begin (you must call next() at least once first). */
+bool upb_MapIterator_Done(const upb_Map* map, size_t iter);
 
 /* Returns the key and value for this entry of the map. */
-upb_msgval upb_mapiter_key(const upb_map *map, size_t iter);
-upb_msgval upb_mapiter_value(const upb_map *map, size_t iter);
+upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter);
+upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter);
 
 /* Sets the value for this entry.  The iterator must not be done, and the
  * iterator must not have been initialized const. */
-void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value);
+void upb_MapIterator_SetValue(upb_Map* map, size_t iter,
+                              upb_MessageValue value);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
 
@@ -4617,19 +5203,17 @@
 extern "C" {
 #endif
 
-enum {
-  UPB_JSONDEC_IGNOREUNKNOWN = 1
-};
+enum { upb_JsonDecode_IgnoreUnknown = 1 };
 
-bool upb_json_decode(const char *buf, size_t size, upb_msg *msg,
-                     const upb_msgdef *m, const upb_symtab *any_pool,
-                     int options, upb_arena *arena, upb_status *status);
+bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg,
+                    const upb_MessageDef* m, const upb_DefPool* symtab,
+                    int options, upb_Arena* arena, upb_Status* status);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
-#endif  /* UPB_JSONDECODE_H_ */
+#endif /* UPB_JSONDECODE_H_ */
 
 /** upb/json_encode.h ************************************************************/
 #ifndef UPB_JSONENCODE_H_
@@ -4642,11 +5226,11 @@
 
 enum {
   /* When set, emits 0/default values.  TODO(haberman): proto3 only? */
-  UPB_JSONENC_EMITDEFAULTS = 1,
+  upb_JsonEncode_EmitDefaults = 1,
 
   /* When set, use normal (snake_caes) field names instead of JSON (camelCase)
      names. */
-  UPB_JSONENC_PROTONAMES = 2
+  upb_JsonEncode_UseProtoNames = 2
 };
 
 /* Encodes the given |msg| to JSON format.  The message's reflection is given in
@@ -4657,15 +5241,15 @@
  * size (excluding NULL) is returned.  This means that a return value >= |size|
  * implies that the output was truncated.  (These are the same semantics as
  * snprintf()). */
-size_t upb_json_encode(const upb_msg *msg, const upb_msgdef *m,
-                       const upb_symtab *ext_pool, int options, char *buf,
-                       size_t size, upb_status *status);
+size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m,
+                      const upb_DefPool* ext_pool, int options, char* buf,
+                      size_t size, upb_Status* status);
 
 #ifdef __cplusplus
-}  /* extern "C" */
+} /* extern "C" */
 #endif
 
-#endif  /* UPB_JSONENCODE_H_ */
+#endif /* UPB_JSONENCODE_H_ */
 
 /** upb/port_undef.inc ************************************************************/
 /* See port_def.inc.  This should #undef all macros #defined there. */
diff --git a/ruby/ext/google/protobuf_c/wrap_memcpy.c b/ruby/ext/google/protobuf_c/wrap_memcpy.c
index 18c0367..6bbd4ba 100644
--- a/ruby/ext/google/protobuf_c/wrap_memcpy.c
+++ b/ruby/ext/google/protobuf_c/wrap_memcpy.c
@@ -33,7 +33,8 @@
 // On x86-64 Linux with glibc, we link against the 2.2.5 version of memcpy so
 // that we avoid depending on the 2.14 version of the symbol. This way,
 // distributions that are using pre-2.14 versions of glibc can successfully use
-// the gem we distribute (https://github.com/protocolbuffers/protobuf/issues/2783).
+// the gem we distribute
+// (https://github.com/protocolbuffers/protobuf/issues/2783).
 //
 // This wrapper is enabled by passing the linker flags -Wl,-wrap,memcpy in
 // extconf.rb.
@@ -41,11 +42,11 @@
 #if defined(__x86_64__) && defined(__GNU_LIBRARY__)
 __asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
 void *__wrap_memcpy(void *dest, const void *src, size_t n) {
-    return memcpy(dest, src, n);
+  return memcpy(dest, src, n);
 }
 #else
 void *__wrap_memcpy(void *dest, const void *src, size_t n) {
-    return memmove(dest, src, n);
+  return memmove(dest, src, n);
 }
 #endif
 #endif
diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec
index 7a9e3f3..87d75a3 100644
--- a/ruby/google-protobuf.gemspec
+++ b/ruby/google-protobuf.gemspec
@@ -1,6 +1,6 @@
 Gem::Specification.new do |s|
   s.name        = "google-protobuf"
-  s.version     = "3.18.1"
+  s.version     = "3.19.4"
   git_tag       = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag
   s.licenses    = ["BSD-3-Clause"]
   s.summary     = "Protocol Buffers"
@@ -17,7 +17,7 @@
   else
     s.files     += Dir.glob('ext/**/*')
     s.extensions= ["ext/google/protobuf_c/extconf.rb"]
-    s.add_development_dependency "rake-compiler-dock", ">= 1.1.0", "< 2.0"
+    s.add_development_dependency "rake-compiler-dock", "= 1.1.0"
   end
   s.test_files  = ["tests/basic.rb",
                   "tests/stress.rb",
@@ -25,5 +25,4 @@
   s.required_ruby_version = '>= 2.3'
   s.add_development_dependency "rake-compiler", "~> 1.1.0"
   s.add_development_dependency "test-unit", '~> 3.0', '>= 3.0.9'
-  s.add_development_dependency "rubygems-tasks", "~> 0.2.4"
 end
diff --git a/ruby/lib/google/protobuf/well_known_types.rb b/ruby/lib/google/protobuf/well_known_types.rb
index 37f8d5b..2d06ca2 100755
--- a/ruby/lib/google/protobuf/well_known_types.rb
+++ b/ruby/lib/google/protobuf/well_known_types.rb
@@ -82,9 +82,14 @@
         end
       end
 
+      def self.from_time(time)
+        new.from_time(time)
+      end
+
       def from_time(time)
         self.seconds = time.to_i
         self.nanos = time.nsec
+        self
       end
 
       def to_i
@@ -132,10 +137,14 @@
         end
       end
 
+      def self.from_ruby(value)
+        self.new.from_ruby(value)
+      end
+
       def from_ruby(value)
         case value
         when NilClass
-          self.null_value = 0
+          self.null_value = :NULL_VALUE
         when Numeric
           self.number_value = value
         when String
@@ -155,6 +164,8 @@
         else
           raise UnexpectedStructType
         end
+
+        self
       end
     end
 
@@ -225,6 +236,5 @@
         ret
       end
     end
-
   end
 end
diff --git a/ruby/pom.xml b/ruby/pom.xml
index 0b13996..c9ae9e6 100644
--- a/ruby/pom.xml
+++ b/ruby/pom.xml
@@ -9,7 +9,7 @@
 
     <groupId>com.google.protobuf.jruby</groupId>
     <artifactId>protobuf-jruby</artifactId>
-    <version>3.18.1</version>
+    <version>3.19.4</version>
     <name>Protocol Buffer JRuby native extension</name>
     <description>
       Protocol Buffers are a way of encoding structured data in an efficient yet
@@ -19,7 +19,7 @@
     <url>https://developers.google.com/protocol-buffers/</url>
     <licenses>
       <license>
-        <name>3-Clause BSD License</name>
+        <name>BSD-3-Clause</name>
         <url>https://opensource.org/licenses/BSD-3-Clause</url>
         <distribution>repo</distribution>
       </license>
@@ -76,7 +76,7 @@
         <dependency>
           <groupId>com.google.protobuf</groupId>
           <artifactId>protobuf-java-util</artifactId>
-          <version>3.18.1</version>
+          <version>3.19.4</version>
         </dependency>
         <dependency>
             <groupId>org.jruby</groupId>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
index 8140ec5..f7379b1 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java
@@ -332,7 +332,7 @@
      *
      * Returns the number of entries (key-value pairs) in the map.
      */
-    @JRubyMethod
+    @JRubyMethod(name = {"length", "size"})
     public IRubyObject length(ThreadContext context) {
         return context.runtime.newFixnum(this.table.size());
     }
diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb
index 2a7a251..b9d1554 100755
--- a/ruby/tests/basic.rb
+++ b/ruby/tests/basic.rb
@@ -71,6 +71,14 @@
       TestMessage.encode(msg)
     end
 
+    def test_issue_9440
+      msg = HelloRequest.new
+      msg.id = 8
+      assert_equal 8, msg.id
+      msg.version = '1'
+      assert_equal 8, msg.id
+    end
+
     def test_has_field
       m = TestSingularFields.new
       assert !m.has_singular_msg?
@@ -620,5 +628,21 @@
       assert_raise(FrozenErrorType) { m.map_string_int32.delete('a') }
       assert_raise(FrozenErrorType) { m.map_string_int32.clear }
     end
+
+    def test_map_length
+      m = proto_module::MapMessage.new
+      assert_equal 0, m.map_string_int32.length
+      assert_equal 0, m.map_string_msg.length
+      assert_equal 0, m.map_string_int32.size
+      assert_equal 0, m.map_string_msg.size
+
+      m.map_string_int32['a'] = 1
+      m.map_string_int32['b'] = 2
+      m.map_string_msg['a'] = proto_module::TestMessage2.new
+      assert_equal 2, m.map_string_int32.length
+      assert_equal 1, m.map_string_msg.length
+      assert_equal 2, m.map_string_int32.size
+      assert_equal 1, m.map_string_msg.size
+    end
   end
 end
diff --git a/ruby/tests/basic_test.proto b/ruby/tests/basic_test.proto
index bca172a..fb70f47 100644
--- a/ruby/tests/basic_test.proto
+++ b/ruby/tests/basic_test.proto
@@ -215,3 +215,38 @@
   optional int32 foo_bar = 1 [json_name="jsonFooBar"];
   repeated WithJsonName baz = 2 [json_name="jsonBaz"];
 }
+
+message HelloRequest {
+  optional uint32 id = 1;
+  optional uint32 random_name_a0 = 2;
+  optional uint32 random_name_a1 = 3;
+  optional uint32 random_name_a2 = 4;
+  optional uint32 random_name_a3 = 5;
+  optional uint32 random_name_a4 = 6;
+  optional uint32 random_name_a5 = 7;
+  optional uint32 random_name_a6 = 8;
+  optional uint32 random_name_a7 = 9;
+  optional uint32 random_name_a8 = 10;
+  optional uint32 random_name_a9 = 11;
+  optional uint32 random_name_b0 = 12;
+  optional uint32 random_name_b1 = 13;
+  optional uint32 random_name_b2 = 14;
+  optional uint32 random_name_b3 = 15;
+  optional uint32 random_name_b4 = 16;
+  optional uint32 random_name_b5 = 17;
+  optional uint32 random_name_b6 = 18;
+  optional uint32 random_name_b7 = 19;
+  optional uint32 random_name_b8 = 20;
+  optional uint32 random_name_b9 = 21;
+  optional uint32 random_name_c0 = 22;
+  optional uint32 random_name_c1 = 23;
+  optional uint32 random_name_c2 = 24;
+  optional uint32 random_name_c3 = 25;
+  optional uint32 random_name_c4 = 26;
+  optional uint32 random_name_c5 = 27;
+  optional uint32 random_name_c6 = 28;
+  optional uint32 random_name_c7 = 29;
+  optional uint32 random_name_c8 = 30;
+  optional uint32 random_name_c9 = 31;
+  optional string version = 32;
+}
diff --git a/ruby/tests/common_tests.rb b/ruby/tests/common_tests.rb
index 3d9f67e..3ab9a0c 100644
--- a/ruby/tests/common_tests.rb
+++ b/ruby/tests/common_tests.rb
@@ -816,11 +816,17 @@
                                       :optional_enum => :B,
                                       :repeated_string => ["a", "b", "c"],
                                       :repeated_int32 => [42, 43, 44],
-                                      :repeated_enum => [:A, :B, :C, 100],
+                                      :repeated_enum => [:A, :B, :C],
                                       :repeated_msg => [proto_module::TestMessage2.new(:foo => 1),
                                                         proto_module::TestMessage2.new(:foo => 2)])
+    if proto_module == ::BasicTest
+      # For proto3 we can add an unknown enum value safely.
+      m.repeated_enum << 100
+    end
+
     data = proto_module::TestMessage.encode m
     m2 = proto_module::TestMessage.decode data
+
     assert_equal m, m2
 
     data = Google::Protobuf.encode m
diff --git a/ruby/tests/well_known_types_test.rb b/ruby/tests/well_known_types_test.rb
index ea042eb..fbdee38 100755
--- a/ruby/tests/well_known_types_test.rb
+++ b/ruby/tests/well_known_types_test.rb
@@ -15,16 +15,30 @@
 
     # millisecond accuracy
     time = Time.at(123456, 654321)
-    ts.from_time(time)
+    resp = ts.from_time(time)
     assert_equal 123456, ts.seconds
     assert_equal 654321000, ts.nanos
     assert_equal time, ts.to_time
+    assert_equal resp, ts
 
     # nanosecond accuracy
     time = Time.at(123456, Rational(654321321, 1000))
-    ts.from_time(time)
+    resp = ts.from_time(time)
+    assert_equal 123456, ts.seconds
     assert_equal 654321321, ts.nanos
     assert_equal time, ts.to_time
+    assert_equal resp, ts
+
+    # Class based initialisation using from_time
+    time = Time.at(123456, Rational(654321321, 1000))
+    ts = Google::Protobuf::Timestamp.from_time(time)
+    assert_equal 123456, ts.seconds
+    assert_equal 654321321, ts.nanos
+    assert_equal time, ts.to_time
+
+      # Instance method returns the same value as class method
+    assert_equal Google::Protobuf::Timestamp.new.from_time(time),
+                 Google::Protobuf::Timestamp.from_time(time)
   end
 
   def test_duration
@@ -201,4 +215,33 @@
     )
     assert_equal '[<Google::Protobuf::Value: string_value: "Hello">]', value_field.get(proto).inspect
   end
+
+  def test_from_ruby
+    pb = Google::Protobuf::Value.from_ruby(nil)
+    assert_equal pb.null_value, :NULL_VALUE
+
+    pb = Google::Protobuf::Value.from_ruby(1.23)
+    assert_equal pb.number_value, 1.23
+
+    pb = Google::Protobuf::Value.from_ruby('1.23')
+    assert_equal pb.string_value, '1.23'
+
+    pb = Google::Protobuf::Value.from_ruby(true)
+    assert_equal pb.bool_value, true
+
+    pb = Google::Protobuf::Value.from_ruby(false)
+    assert_equal pb.bool_value, false
+
+    pb = Google::Protobuf::Value.from_ruby(Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true }))
+    assert_equal pb.struct_value, Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
+
+    pb = Google::Protobuf::Value.from_ruby({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
+    assert_equal pb.struct_value, Google::Protobuf::Struct.from_hash({ 'a' => 1, 'b' => '2', 'c' => [1, 2, 3], 'd' => nil, 'e' => true })
+
+    pb = Google::Protobuf::Value.from_ruby(Google::Protobuf::ListValue.from_a([1, 2, 3]))
+    assert_equal pb.list_value, Google::Protobuf::ListValue.from_a([1, 2, 3])
+
+    pb = Google::Protobuf::Value.from_ruby([1, 2, 3])
+    assert_equal pb.list_value, Google::Protobuf::ListValue.from_a([1, 2, 3])
+  end
 end
diff --git a/src/Makefile.am b/src/Makefile.am
index 232955f..ca9b81b 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/README.md b/src/README.md
index 9db40fd..80e8668 100644
--- a/src/README.md
+++ b/src/README.md
@@ -48,7 +48,7 @@
 
 
      ./configure
-     make
+     make -j$(nproc) # $(nproc) ensures it uses all cores for compilation
      make check
      sudo make install
      sudo ldconfig # refresh shared library cache.
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 60308ff..034b7e1 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 e614f07..fd834c7 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 6dd6467..2b93a41 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -55,6 +55,7 @@
 #include <google/protobuf/arena_impl.h>
 #include <google/protobuf/port.h>
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
@@ -83,10 +84,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
@@ -316,6 +318,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);`).
@@ -532,6 +548,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) {
@@ -622,7 +642,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>
@@ -765,17 +785,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);
     }
   }
 
@@ -786,7 +807,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),
@@ -796,18 +817,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..4c19c91 100644
--- a/src/google/protobuf/arenastring.cc
+++ b/src/google/protobuf/arenastring.cc
@@ -32,11 +32,11 @@
 
 #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 +47,25 @@
 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__;
+#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 +80,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 +160,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 +169,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 +205,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 +215,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 +228,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 +264,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 +279,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 +294,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 bfc6b05..3dff6c5 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;
@@ -1946,11 +1948,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()) {
@@ -1979,8 +1981,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;
       }
@@ -2136,7 +2138,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"))
@@ -2317,7 +2319,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.",
@@ -2347,7 +2349,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 130e90e..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()->FindFieldByName("key");
-  const FieldDescriptor* val =
-      descriptor->message_type()->FindFieldByName("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()->FindFieldByName("key");
-  const FieldDescriptor* value_field =
-      descriptor_->message_type()->FindFieldByName("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 70d8a57..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>
 
 
@@ -276,8 +275,8 @@
                     std::map<std::string, std::string>* variables) {
   GOOGLE_CHECK(IsMapEntryMessage(descriptor));
   std::map<std::string, std::string>& vars = *variables;
-  const FieldDescriptor* key = descriptor->FindFieldByName("key");
-  const FieldDescriptor* val = descriptor->FindFieldByName("value");
+  const FieldDescriptor* key = descriptor->map_key();
+  const FieldDescriptor* val = descriptor->map_value();
   vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
   switch (val->cpp_type()) {
     case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -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 810f240..43a5ade 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;
 
@@ -77,163 +77,314 @@
   return tag_size == 1 ? "uint8_t" : "uint16_t";
 }
 
-const char* TagType(const FieldDescriptor* field) {
-  return CodedTagType(TagSize(field->number()));
-}
+std::string FieldParseFunctionName(
+    const TailCallTableInfo::FieldEntryInfo& entry, const Options& options);
 
-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, continguous 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 +403,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 +417,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 +443,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 +470,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 +492,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 +514,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 +532,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 +543,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 +571,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 +593,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 +621,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 +636,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 +660,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 +1007,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 +1021,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 +1057,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 +1082,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 +1115,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 +1127,7 @@
         break;
       case FieldDescriptor::TYPE_MESSAGE: {
         if (field->is_map()) {
-          const FieldDescriptor* val =
-              field->message_type()->FindFieldByName("value");
+          const FieldDescriptor* val = field->message_type()->map_value();
           GOOGLE_CHECK(val);
           if (val->type() == FieldDescriptor::TYPE_ENUM &&
               !HasPreservingUnknownEnumSemantics(field)) {
@@ -768,6 +1143,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 +1175,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 +1211,7 @@
               "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
               "ptr);\n");
         }
+        format("CHK_(ptr);\n");
         break;
       }
       default:
@@ -925,7 +1318,6 @@
     }
     case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
       GenerateLengthDelim(format, field);
-      format("CHK_(ptr);\n");
       break;
     }
     case WireFormatLite::WIRETYPE_START_GROUP: {
@@ -983,13 +1375,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 +1433,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 +1491,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 +1561,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/csharp/csharp_bootstrap_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
index 86bacf8..84aacca 100644
--- a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
@@ -110,13 +110,14 @@
 class GenerateAndTest {
  public:
   GenerateAndTest() {}
-  void Run(const FileDescriptor* proto_file, std::string file1, std::string file2) {
+  void Run(const FileDescriptor* proto_file, std::string file1,
+           std::string file2) {
     ASSERT_TRUE(proto_file != NULL) << TestSourceDir();
     ASSERT_TRUE(generator_.Generate(proto_file, parameter_,
                                     &context_, &error_));
     context_.ExpectFileMatches(file1, file2);
   }
-  void SetParameter(string parameter) {
+  void SetParameter(std::string parameter) {
     parameter_ = parameter;
   }
 
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
index 477b49e..146ca9e 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -61,7 +61,7 @@
     part_tag_size /= 2;
   }
   uint tag = internal::WireFormat::MakeTag(descriptor_);
-  uint8 tag_array[5];
+  uint8_t tag_array[5];
   io::CodedOutputStream::WriteTagToArray(tag, tag_array);
   std::string tag_bytes = StrCat(tag_array[0]);
   for (int i = 1; i < part_tag_size; i++) {
diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
index 5755fee..e21eff1 100644
--- a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc
@@ -30,14 +30,14 @@
 
 #include <memory>
 
+#include <google/protobuf/any.pb.h>
 #include <google/protobuf/compiler/command_line_interface.h>
 #include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/printer.h>
 
-#include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/testing/file.h>
 
 namespace google {
 namespace protobuf {
@@ -63,6 +63,17 @@
   EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2"));
 }
 
+TEST(DescriptorProtoHelpers, IsDescriptorProto) {
+  EXPECT_TRUE(IsDescriptorProto(DescriptorProto::descriptor()->file()));
+  EXPECT_FALSE(IsDescriptorProto(google::protobuf::Any::descriptor()->file()));
+}
+
+TEST(DescriptorProtoHelpers, IsDescriptorOptionMessage) {
+  EXPECT_TRUE(IsDescriptorOptionMessage(FileOptions::descriptor()));
+  EXPECT_FALSE(IsDescriptorOptionMessage(google::protobuf::Any::descriptor()));
+  EXPECT_FALSE(IsDescriptorOptionMessage(DescriptorProto::descriptor()));
+}
+
 }  // namespace
 }  // namespace csharp
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
index a6009c8..619e7db 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.h
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -130,7 +130,8 @@
 // descriptors etc, for use in the runtime. This is the only type which is
 // allowed to use proto2 syntax, and it generates internal classes.
 inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
-  return descriptor->name() == "google/protobuf/descriptor.proto";
+  return descriptor->name() == "google/protobuf/descriptor.proto" ||
+         descriptor->name() == "net/proto2/proto/descriptor.proto";
 }
 
 // Determines whether the given message is an options message within descriptor.proto.
@@ -138,15 +139,15 @@
   if (!IsDescriptorProto(descriptor->file())) {
     return false;
   }
-  const std::string name = descriptor->full_name();
-  return name == "google.protobuf.FileOptions" ||
-      name == "google.protobuf.MessageOptions" ||
-      name == "google.protobuf.FieldOptions" ||
-      name == "google.protobuf.OneofOptions" ||
-      name == "google.protobuf.EnumOptions" ||
-      name == "google.protobuf.EnumValueOptions" ||
-      name == "google.protobuf.ServiceOptions" ||
-      name == "google.protobuf.MethodOptions";
+  const std::string name = descriptor->name();
+  return name == "FileOptions" ||
+      name == "MessageOptions" ||
+      name == "FieldOptions" ||
+      name == "OneofOptions" ||
+      name == "EnumOptions" ||
+      name == "EnumValueOptions" ||
+      name == "ServiceOptions" ||
+      name == "MethodOptions";
 }
 
 inline bool IsWrapperType(const FieldDescriptor* descriptor) {
diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
index 44c13e2..a13b995 100644
--- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc
@@ -57,9 +57,9 @@
 
 void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
   const FieldDescriptor* key_descriptor =
-      descriptor_->message_type()->FindFieldByName("key");
+      descriptor_->message_type()->map_key();
   const FieldDescriptor* value_descriptor =
-      descriptor_->message_type()->FindFieldByName("value");
+      descriptor_->message_type()->map_value();
   variables_["key_type_name"] = type_name(key_descriptor);
   variables_["value_type_name"] = type_name(value_descriptor);
   std::unique_ptr<FieldGeneratorBase> key_generator(
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
index 9980874..9dbce03 100644
--- a/src/google/protobuf/compiler/csharp/csharp_message.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -717,7 +717,7 @@
     const FieldDescriptor* field = fields_by_number()[i];
     internal::WireFormatLite::WireType wt =
         internal::WireFormat::WireTypeForFieldType(field->type());
-    uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt);
+    uint32_t tag = internal::WireFormatLite::MakeTag(field->number(), wt);
     // Handle both packed and unpacked repeated fields with the same Read*Array call;
     // the two generated cases are the packed and unpacked tags.
     // TODO(jonskeet): Check that is_packable is equivalent to
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 f37ecde..c66da52 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 {
@@ -1049,8 +1049,7 @@
 
   if (field->is_map()) {
     if (!SupportUnknownEnumValue(field)) {
-      const FieldDescriptor* value =
-          field->message_type()->FindFieldByName("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 8a89100..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 {
@@ -47,14 +47,14 @@
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
   const Descriptor* message = descriptor->message_type();
   GOOGLE_CHECK(message->options().map_entry());
-  return message->FindFieldByName("key");
+  return message->map_key();
 }
 
 const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
   const Descriptor* message = descriptor->message_type();
   GOOGLE_CHECK(message->options().map_entry());
-  return message->FindFieldByName("value");
+  return message->map_value();
 }
 
 std::string TypeName(const FieldDescriptor* field,
@@ -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 e711168..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 {
@@ -49,14 +49,14 @@
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
   const Descriptor* message = descriptor->message_type();
   GOOGLE_CHECK(message->options().map_entry());
-  return message->FindFieldByName("key");
+  return message->map_key();
 }
 
 const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
   const Descriptor* message = descriptor->message_type();
   GOOGLE_CHECK(message->options().map_entry());
-  return message->FindFieldByName("value");
+  return message->map_value();
 }
 
 std::string TypeName(const FieldDescriptor* field,
@@ -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 27d1014..b2a236f 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 {
@@ -67,7 +67,7 @@
 namespace {
 std::string MapValueImmutableClassdName(const Descriptor* descriptor,
                                         ClassNameResolver* name_resolver) {
-  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  const FieldDescriptor* value_field = descriptor->map_value();
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
   return name_resolver->GetImmutableClassName(value_field->message_type());
 }
@@ -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(
@@ -1504,7 +1526,7 @@
   printer->Print(
       "@Suppress(\"UNCHECKED_CAST\")\n"
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <T> get(extension: "
+      "public operator fun <T : Any> get(extension: "
       "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
       "  return if (extension.isRepeated) {\n"
       "    get(extension as com.google.protobuf.ExtensionLite<$message$, "
@@ -1520,7 +1542,7 @@
       "@kotlin.OptIn"
       "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
       "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
-      "public operator fun <E> get(\n"
+      "public operator fun <E : Any> get(\n"
       "  extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
       "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
       "  return com.google.protobuf.kotlin.ExtensionList(extension, "
@@ -1549,7 +1571,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@kotlin.PublishedApi\n"
-      "internal fun <T> setExtension(extension: "
+      "internal fun <T : Any> setExtension(extension: "
       "com.google.protobuf.ExtensionLite<$message$, T>, "
       "value: T) {\n"
       "  _builder.setExtension(extension, value)\n"
@@ -1592,7 +1614,7 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public fun <E : Any> com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.add(value: E) {\n"
       "  _builder.addExtension(this.extension, value)\n"
       "}\n\n",
@@ -1601,7 +1623,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@Suppress(\"NOTHING_TO_INLINE\")\n"
-      "public inline operator fun <E> "
+      "public inline operator fun <E : Any> "
       "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.plusAssign"
       "(value: E) {\n"
@@ -1611,7 +1633,7 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public fun <E : Any> com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.addAll(values: Iterable<E>) {\n"
       "  for (value in values) {\n"
       "    add(value)\n"
@@ -1622,7 +1644,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@Suppress(\"NOTHING_TO_INLINE\")\n"
-      "public inline operator fun <E> "
+      "public inline operator fun <E : Any> "
       "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.plusAssign(values: "
       "Iterable<E>) {\n"
@@ -1632,7 +1654,8 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public operator fun <E : Any> "
+      "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 320852b..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 {
@@ -61,7 +61,7 @@
 namespace {
 std::string MapValueImmutableClassdName(const Descriptor* descriptor,
                                         ClassNameResolver* name_resolver) {
-  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  const FieldDescriptor* value_field = descriptor->map_value();
   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
   return name_resolver->GetImmutableClassName(value_field->message_type());
 }
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..dd32c26 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(
@@ -826,7 +847,7 @@
   printer->Print(
       "@Suppress(\"UNCHECKED_CAST\")\n"
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <T> get(extension: "
+      "public operator fun <T : Any> get(extension: "
       "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
       "  return if (extension.isRepeated) {\n"
       "    get(extension as com.google.protobuf.ExtensionLite<$message$, "
@@ -842,7 +863,7 @@
       "@kotlin.OptIn"
       "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
       "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
-      "public operator fun <E> get(\n"
+      "public operator fun <E : Any> get(\n"
       "  extension: com.google.protobuf.ExtensionLite<$message$, List<E>>\n"
       "): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
       "  return com.google.protobuf.kotlin.ExtensionList(extension, "
@@ -871,7 +892,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@kotlin.PublishedApi\n"
-      "internal fun <T> setExtension(extension: "
+      "internal fun <T : Any> setExtension(extension: "
       "com.google.protobuf.ExtensionLite<$message$, T>, "
       "value: T) {\n"
       "  _builder.setExtension(extension, value)\n"
@@ -914,7 +935,7 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public fun<E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public fun<E : Any> com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.add(value: E) {\n"
       "  _builder.addExtension(this.extension, value)\n"
       "}\n\n",
@@ -923,7 +944,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@Suppress(\"NOTHING_TO_INLINE\")\n"
-      "public inline operator fun <E> "
+      "public inline operator fun <E : Any> "
       "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.plusAssign"
       "(value: E) {\n"
@@ -933,7 +954,7 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public fun<E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public fun<E : Any> com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.addAll(values: Iterable<E>) {\n"
       "  for (value in values) {\n"
       "    add(value)\n"
@@ -944,7 +965,7 @@
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
       "@Suppress(\"NOTHING_TO_INLINE\")\n"
-      "public inline operator fun <E> "
+      "public inline operator fun <E : Any> "
       "com.google.protobuf.kotlin.ExtensionList<E, "
       "$message$>.plusAssign(values: "
       "Iterable<E>) {\n"
@@ -954,7 +975,8 @@
 
   printer->Print(
       "@kotlin.jvm.JvmSynthetic\n"
-      "public operator fun <E> com.google.protobuf.kotlin.ExtensionList<E, "
+      "public operator fun <E : Any> "
+      "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 28164c7..409d528 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 {
@@ -968,16 +968,14 @@
 
   // property for List<String>
   WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
-  printer->Print(
-      variables_,
-      "public val $kt_name$: "
-      "com.google.protobuf.kotlin.DslList"
-      "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
-      "  @kotlin.OptIn"
-      "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
-      "  get() = com.google.protobuf.kotlin.DslList(\n"
-      "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
-      "  )\n");
+  printer->Print(variables_,
+                 "$kt_deprecation$public val $kt_name$: "
+                 "com.google.protobuf.kotlin.DslList"
+                 "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
+                 "  @kotlin.jvm.JvmSynthetic\n"
+                 "  get() = com.google.protobuf.kotlin.DslList(\n"
+                 "    $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+                 "  )\n");
 
   // List<String>.add(String)
   WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
@@ -997,10 +995,11 @@
   printer->Print(variables_,
                  "@kotlin.jvm.JvmSynthetic\n"
                  "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
-                 "public operator fun com.google.protobuf.kotlin.DslList"
+                 "@Suppress(\"NOTHING_TO_INLINE\")\n"
+                 "public inline operator fun com.google.protobuf.kotlin.DslList"
                  "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
                  "plusAssign(value: kotlin.String) {\n"
-                 "  $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+                 "  add(value)\n"
                  "}\n");
 
   // List<String>.addAll(Iterable<String>)
@@ -1023,10 +1022,11 @@
       variables_,
       "@kotlin.jvm.JvmSynthetic\n"
       "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
-      "public operator fun com.google.protobuf.kotlin.DslList"
+      "@Suppress(\"NOTHING_TO_INLINE\")\n"
+      "public inline operator fun com.google.protobuf.kotlin.DslList"
       "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>."
       "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n"
-      "  $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+      "  addAll(values)\n"
       "}\n");
 
   // List<String>[Int] = String
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 57cd436..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 {
@@ -755,7 +755,7 @@
   WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
   printer->Print(
       variables_,
-      "public val $kt_name$: "
+      "$kt_deprecation$public val $kt_name$: "
       "com.google.protobuf.kotlin.DslList"
       "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n"
       "  @kotlin.OptIn"
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index cfd0e03..2cee9da 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -3625,7 +3625,19 @@
     if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
       printer->Print("var proto = {};\n\n");
     } else {
-      printer->Print("var global = Function('return this')();\n\n");
+      // 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('') is almost the same as eval('')
+      printer->Print(
+          "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..7bddb31 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.");
+  // Pyton 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/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
index a03b860..713f93e 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc
@@ -110,6 +110,9 @@
       //   - Comments start with "#".
       //   - A comment can go on a line after a expected package/prefix pair.
       //     (i.e. - "package=prefix # comment")
+      //   - For files that do NOT have a proto package (not recommended), an
+      //     entry can be made as "no_package:PATH=prefix", where PATH is the
+      //     path for the .proto file.
       //
       // There is no validation that the prefixes are good prefixes, it is
       // assumed that they are when you create the file.
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
index 5f4b7f6..cf92607 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc
@@ -73,6 +73,14 @@
 
 namespace {
 
+bool BoolFromEnvVar(const char* env_var, bool default_value) {
+  const char* value = getenv(env_var);
+  if (value) {
+    return std::string("YES") == ToUpper(value);
+  }
+  return default_value;
+}
+
 class SimpleLineCollector : public LineConsumer {
  public:
   SimpleLineCollector(std::unordered_set<std::string>* inout_set)
@@ -102,9 +110,14 @@
 
   bool is_package_exempted(const std::string& package);
 
+  // When using a proto package as the prefix, this should be added as the
+  // prefix in front of it.
+  const std::string& forced_package_prefix() const { return forced_prefix_; }
+
  private:
   bool use_package_name_;
   std::string exception_path_;
+  std::string forced_prefix_;
   std::unordered_set<std::string> exceptions_;
 };
 
@@ -112,14 +125,19 @@
   // Even thought there are generation options, have an env back door since some
   // of these helpers could be used in other plugins.
 
-  const char* use_package_cstr = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX");
-  use_package_name_ =
-    (use_package_cstr && (std::string("YES") == ToUpper(use_package_cstr)));
+  use_package_name_ = BoolFromEnvVar("GPB_OBJC_USE_PACKAGE_AS_PREFIX", false);
 
   const char* exception_path = getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH");
   if (exception_path) {
     exception_path_ = exception_path;
   }
+
+  // This one is a not expected to be common, so it doesn't get a generation
+  // option, just the env var.
+  const char* prefix = getenv("GPB_OBJC_USE_PACKAGE_AS_PREFIX_PREFIX");
+  if (prefix) {
+    forced_prefix_ = prefix;
+  }
 }
 
 bool PrefixModeStorage::is_package_exempted(const std::string& package) {
@@ -168,7 +186,9 @@
 }
 
 Options::Options() {
-  // Default is the value of the env for the package prefixes.
+  // While there are generator options, also support env variables to help with
+  // build systems where it isn't as easy to hook in for add the generation
+  // options when invoking protoc.
   const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
   if (file_path) {
     expected_prefixes_path = file_path;
@@ -178,8 +198,9 @@
     expected_prefixes_suppressions =
         Split(suppressions, ";", true);
   }
-  prefixes_must_be_registered = false;
-  require_prefixes = false;
+  prefixes_must_be_registered =
+      BoolFromEnvVar("GPB_OBJC_PREFIXES_MUST_BE_REGISTERED", false);
+  require_prefixes = BoolFromEnvVar("GPB_OBJC_REQUIRE_PREFIXES", false);
 }
 
 namespace {
@@ -352,9 +373,9 @@
 }
 
 std::string SanitizeNameForObjC(const std::string& prefix,
-                           const std::string& input,
-                           const std::string& extension,
-                           std::string* out_suffix_added) {
+                                const std::string& input,
+                                const std::string& extension,
+                                std::string* out_suffix_added) {
   static const std::unordered_set<std::string> kReservedWords =
       MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
   static const std::unordered_set<std::string> kNSObjectMethods =
@@ -510,8 +531,8 @@
     return file->options().objc_class_prefix();
   }
 
-  // If package prefix isn't enabled or no package, done.
-  if (!g_prefix_mode.use_package_name() || file->package().empty()) {
+  // If package prefix isn't enabled, done.
+  if (!g_prefix_mode.use_package_name()) {
     return "";
   }
 
@@ -538,7 +559,7 @@
   if (!result.empty()) {
     result.append("_");
   }
-  return result;
+  return g_prefix_mode.forced_package_prefix() + result;
 }
 
 std::string FilePath(const FileDescriptor* file) {
@@ -1240,6 +1261,11 @@
 
   const std::string prefix = file->options().objc_class_prefix();
   const std::string package = file->package();
+  // For files without packages, the can be registered as "no_package:PATH",
+  // allowing the expected prefixes file.
+  static const std::string no_package_prefix("no_package:");
+  const std::string lookup_key =
+      package.empty() ? no_package_prefix + file->name() : package;
 
   // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
   // error cases, so it seems to be ok to use as a back door for warnings.
@@ -1247,7 +1273,7 @@
   // Check: Error - See if there was an expected prefix for the package and
   // report if it doesn't match (wrong or missing).
   std::map<std::string, std::string>::const_iterator package_match =
-      expected_package_prefixes.find(package);
+      expected_package_prefixes.find(lookup_key);
   if (package_match != expected_package_prefixes.end()) {
     // There was an entry, and...
     if (has_prefix && package_match->second == prefix) {
@@ -1256,8 +1282,11 @@
     } else {
       // ...it didn't match!
       *out_error = "error: Expected 'option objc_class_prefix = \"" +
-                   package_match->second + "\";' for package '" + package +
-                   "' in '" + file->name() + "'";
+                   package_match->second + "\";'";
+      if (!package.empty()) {
+        *out_error += " for package '" + package + "'";
+      }
+      *out_error += " in '" + file->name() + "'";
       if (has_prefix) {
         *out_error += "; but found '" + prefix + "' instead";
       }
@@ -1286,51 +1315,34 @@
          i != expected_package_prefixes.end(); ++i) {
       if (i->second == prefix) {
         other_package_for_prefix = i->first;
-        break;
+        // Stop on the first real package listing, if it was a no_package file
+        // specific entry, keep looking to try and find a package one.
+        if (!HasPrefixString(other_package_for_prefix, no_package_prefix)) {
+          break;
+        }
       }
     }
 
-    // Check: Warning - If the file does not have a package, check whether the
-    // prefix was declared is being used by another package or not. This is
-    // a special case for empty packages.
-    if (package.empty()) {
-      // The file does not have a package and ...
-      if (other_package_for_prefix.empty()) {
-        // ... no other package has declared that prefix.
-        std::cerr
-             << "protoc:0: warning: File '" << file->name() << "' has no "
-             << "package. Consider adding a new package to the proto and adding '"
-             << "new.package = " << prefix << "' to the expected prefixes file ("
-             << expected_prefixes_path << ")." << std::endl;
-        std::cerr.flush();
-      } else {
-        // ... another package has declared the same prefix.
-        std::cerr
-             << "protoc:0: warning: File '" << file->name() << "' has no package "
-             << "and package '" << other_package_for_prefix << "' already uses '"
-             << prefix << "' as its prefix. Consider either adding a new package "
-             << "to the proto, or reusing one of the packages already using this "
-             << "prefix in the expected prefixes file ("
-             << expected_prefixes_path << ")." << std::endl;
-        std::cerr.flush();
-      }
-      return true;
-    }
-
     // Check: Error - Make sure the prefix wasn't expected for a different
     // package (overlap is allowed, but it has to be listed as an expected
     // overlap).
     if (!other_package_for_prefix.empty()) {
       *out_error =
           "error: Found 'option objc_class_prefix = \"" + prefix +
-          "\";' in '" + file->name() +
-          "'; that prefix is already used for 'package " +
-          other_package_for_prefix + ";'. It can only be reused by listing " +
-          "it in the expected file (" +
-          expected_prefixes_path + ").";
+          "\";' in '" + file->name() + "'; that prefix is already used for ";
+      if (HasPrefixString(other_package_for_prefix, no_package_prefix)) {
+        *out_error += "file '" +
+          StripPrefixString(other_package_for_prefix, no_package_prefix) +
+          "'.";
+      } else {
+        *out_error += "'package " + other_package_for_prefix + ";'.";
+      }
+      *out_error +=
+        " It can only be reused by adding '" + lookup_key + " = " + prefix +
+        "' to the expected prefixes file (" + expected_prefixes_path + ").";
       return false;  // Only report first usage of the prefix.
     }
-  } // !prefix.empty()
+  } // !prefix.empty() && have_expected_prefix_file
 
   // Check: Warning - Make sure the prefix is is a reasonable value according
   // to Apple's rules (the checks above implicitly whitelist anything that
@@ -1359,17 +1371,18 @@
     if (prefixes_must_be_registered) {
       *out_error =
         "error: '" + file->name() + "' has 'option objc_class_prefix = \"" +
-        prefix + "\";', but it is not registered; add it to the expected " +
-        "prefixes file (" + expected_prefixes_path + ") for the package '" +
-        package + "'.";
+        prefix + "\";', but it is not registered. Add '" + lookup_key + " = " +
+        (prefix.empty() ? "\"\"" : prefix) +
+        "' to the expected prefixes file (" + expected_prefixes_path + ").";
       return false;
     }
 
     std::cerr
          << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
-         << prefix << "\";' in '" << file->name() << "';"
-         << " consider adding it to the expected prefixes file ("
-         << expected_prefixes_path << ")." << std::endl;
+         << prefix << "\";' in '" << file->name() << "'; consider adding '"
+         << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix)
+         << "' to the expected prefixes file (" << expected_prefixes_path
+         << ")." << std::endl;
     std::cerr.flush();
   }
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
index c5f948c..f4b71ce 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h
@@ -54,8 +54,8 @@
 bool PROTOC_EXPORT UseProtoPackageAsDefaultPrefix();
 void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off);
 // Get/Set the path to a file to load as exceptions when
-// `UseProtoPackageAsDefaultPrefixUseProtoPackageAsDefaultPrefix()` is `true`.
-// And empty string means there should be no exceptions loaded.
+// `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there
+// should be no exceptions.
 std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList();
 void PROTOC_EXPORT SetProtoPackagePrefixExceptionList(
     const std::string& file_path);
@@ -263,7 +263,7 @@
   TextFormatDecodeData(const TextFormatDecodeData&) = delete;
   TextFormatDecodeData& operator=(const TextFormatDecodeData&) = delete;
 
-  void AddString(int32 key, const std::string& input_for_decode,
+  void AddString(int32_t key, const std::string& input_for_decode,
                  const std::string& desired_output);
   size_t num_entries() const { return entries_.size(); }
   std::string Data() const;
@@ -272,7 +272,7 @@
                                          const std::string& desired_output);
 
  private:
-  typedef std::pair<int32, std::string> DataEntry;
+  typedef std::pair<int32_t, std::string> DataEntry;
   std::vector<DataEntry> entries_;
 };
 
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
index 3c5eda2..7ae6a92 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers_unittest.cc
@@ -30,7 +30,6 @@
 
 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
 namespace google {
@@ -154,7 +153,7 @@
 
   EXPECT_EQ(4, decode_data.num_entries());
 
-  uint8 expected_data[] = {
+  uint8_t expected_data[] = {
       0x4,
       0x1, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
       0x3, 0x0, 'a', 'b', 'c', 'd', 'e', 'z', 'g', 'h', 'I', 'J', 0x0,
@@ -179,7 +178,7 @@
 
   EXPECT_EQ(5, decode_data.num_entries());
 
-  uint8 expected_data[] = {
+  uint8_t expected_data[] = {
       0x5,
       // All as is (00 op)
       0x1,  0x0A, 0x0,
diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
index 746224f..c1b1f53 100644
--- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
+++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
@@ -153,7 +153,7 @@
   // Use the array_comment support in RepeatedFieldGenerator to output what the
   // values in the map are.
   const FieldDescriptor* value_descriptor =
-      descriptor_->message_type()->FindFieldByName("value");
+      descriptor_->message_type()->map_value();
   if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
     variables_["array_comment"] =
         "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
@@ -164,7 +164,7 @@
     std::set<std::string>* fwd_decls) const {
   RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
   const FieldDescriptor* value_descriptor =
-      descriptor_->message_type()->FindFieldByName("value");
+      descriptor_->message_type()->map_value();
   if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
     const std::string& value_storage_type =
         value_field_generator_->variable("storage_type");
@@ -176,7 +176,7 @@
     std::set<std::string>* fwd_decls) const {
   // Class name is already in "storage_type".
   const FieldDescriptor* value_descriptor =
-      descriptor_->message_type()->FindFieldByName("value");
+      descriptor_->message_type()->map_value();
   if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
     fwd_decls->insert(ObjCClassDeclaration(
         value_field_generator_->variable("storage_type")));
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/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc
index 05f8aca..6b8ee52 100644
--- a/src/google/protobuf/compiler/php/php_generator.cc
+++ b/src/google/protobuf/compiler/php/php_generator.cc
@@ -83,14 +83,14 @@
   bool is_descriptor = false;
   bool aggregate_metadata = false;
   bool gen_c_wkt = false;
-  std::set<string> aggregate_metadata_prefixes;
+  std::set<std::string> aggregate_metadata_prefixes;
 };
 
 namespace {
 
 // Forward decls.
 std::string PhpName(const std::string& full_name, const Options& options);
-std::string IntToString(int32 value);
+std::string IntToString(int32_t value);
 std::string FilenameToClassname(const std::string& filename);
 std::string GeneratedMetadataFileName(const FileDescriptor* file,
                                       const Options& options);
@@ -430,7 +430,7 @@
   return result + ".php";
 }
 
-std::string IntToString(int32 value) {
+std::string IntToString(int32_t value) {
   std::ostringstream os;
   os << value;
   return os.str();
@@ -741,8 +741,8 @@
   // Type check.
   if (field->is_map()) {
     const Descriptor* map_entry = field->message_type();
-    const FieldDescriptor* key = map_entry->FindFieldByName("key");
-    const FieldDescriptor* value = map_entry->FindFieldByName("value");
+    const FieldDescriptor* key = map_entry->map_key();
+    const FieldDescriptor* value = map_entry->map_value();
     printer->Print(
         "$arr = GPBUtil::checkMapField($var, "
         "\\Google\\Protobuf\\Internal\\GPBType::^key_type^, "
@@ -889,9 +889,9 @@
     const FieldDescriptor* field = message->field(i);
     if (field->is_map()) {
       const FieldDescriptor* key =
-          field->message_type()->FindFieldByName("key");
+          field->message_type()->map_key();
       const FieldDescriptor* val =
-          field->message_type()->FindFieldByName("value");
+          field->message_type()->map_value();
       printer->Print(
           "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, "
           "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\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 76c3da1..204e42a 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/ruby/ruby_generated_code_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
index 4cf4866..256ac7c 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_pb.rb
@@ -1,9 +1,10 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: ruby_generated_code.proto
 
-require 'ruby_generated_code_proto2_import_pb'
 require 'google/protobuf'
 
+require 'ruby_generated_code_proto2_import_pb'
+
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_file("ruby_generated_code.proto", :syntax => :proto3) do
     add_message "A.B.C.TestMessage" do
diff --git a/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
index e331e9b..44d3196 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
+++ b/src/google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb
@@ -1,9 +1,10 @@
 # Generated by the protocol buffer compiler.  DO NOT EDIT!
 # source: ruby_generated_code_proto2.proto
 
-require 'ruby_generated_code_proto2_import_pb'
 require 'google/protobuf'
 
+require 'ruby_generated_code_proto2_import_pb'
+
 Google::Protobuf::DescriptorPool.generated_pool.build do
   add_file("ruby_generated_code_proto2.proto", :syntax => :proto2) do
     add_message "A.B.C.TestMessage" do
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
index c1a5c67..2bda459 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -421,7 +421,7 @@
     //    -> A.B.C
     if (package_name.find("::") != std::string::npos) {
       need_change_to_module = false;
-    } else {
+    } else if (package_name.find(".") != std::string::npos) {
       GOOGLE_LOG(WARNING) << "ruby_package option should be in the form of:"
                           << " 'A::B::C' and not 'A.B.C'";
     }
@@ -467,8 +467,6 @@
 
 bool GenerateDslDescriptor(const FileDescriptor* file, io::Printer* printer,
                            std::string* error) {
-  printer->Print(
-    "require 'google/protobuf'\n\n");
   printer->Print("Google::Protobuf::DescriptorPool.generated_pool.build do\n");
   printer->Indent();
   printer->Print("add_file(\"$filename$\", :syntax => :$syntax$) do\n",
@@ -509,8 +507,13 @@
     "\n",
     "filename", file->name());
 
-  for (int i = 0; i < file->dependency_count(); i++) {
-    printer->Print("require '$name$'\n", "name", GetRequireName(file->dependency(i)->name()));
+  printer->Print("require 'google/protobuf'\n\n");
+
+  if (file->dependency_count() != 0) {
+    for (int i = 0; i < file->dependency_count(); i++) {
+      printer->Print("require '$name$'\n", "name", GetRequireName(file->dependency(i)->name()));
+    }
+    printer->Print("\n");
   }
 
   // TODO: Remove this when ruby supports extensions for proto2 syntax.
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index 040b6c9..c3ce1d3 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -57,7 +57,7 @@
 // Some day, we may integrate build systems between protoc and the language
 // extensions to the point where we can do this test in a more automated way.
 
-void RubyTest(string proto_file, string import_proto_file = "") {
+void RubyTest(std::string proto_file, std::string import_proto_file = "") {
   std::string ruby_tests = FindRubyTestDir();
 
   google::protobuf::compiler::CommandLineInterface cli;
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 c8ce218..a2552f6 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,443 @@
 #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() {
+    if (std::is_trivially_constructible<U>::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 +522,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 +552,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 +593,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 +647,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 +672,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 +713,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 +729,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 +833,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 +972,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 +992,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 +1019,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 +1077,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() >= 1 + 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 +1193,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 +1230,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 +1293,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 +1397,6 @@
     symbols_after_checkpoint_.clear();
     files_after_checkpoint_.clear();
     extensions_after_checkpoint_.clear();
-    arena_.ClearRollbackData();
   }
 }
 
@@ -1401,13 +1406,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 +1423,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 +1433,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 +1442,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 +1496,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 +1575,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 +1598,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 +1608,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 +1622,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 +1664,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 +1681,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 +1762,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 +2387,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 +3450,6 @@
   comment_printer.AddPostComment(contents);
 }
 
-
 // Location methods ===============================================
 
 bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,
@@ -3718,7 +3635,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 +3672,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 +3772,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 +3779,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 +3792,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 +4256,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 +4275,7 @@
 
   possible_undeclared_dependency_ = file;
   possible_undeclared_dependency_name_ = name;
-  return kNullSymbol;
+  return Symbol();
 }
 
 Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
@@ -4478,7 +4403,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 +4411,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 +4459,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 +4468,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 +4480,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 +4496,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 +4511,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 +4601,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 +4622,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 +4647,7 @@
           (character < '0' || '9' < character) && (character != '_')) {
         AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
                  "\"" + name + "\" is not a valid identifier.");
+        return;
       }
     }
   }
@@ -4708,23 +4661,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 +4687,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 +4738,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 +4800,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 +4982,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 +5000,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 +5035,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 +5062,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 +5075,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 +5105,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 +5128,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 +5192,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 +5213,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 +5269,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 +5303,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 +5326,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 +5453,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 +5586,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 +5720,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 +5759,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 +5776,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 +5788,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 +5805,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 +5879,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 +5920,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 +5933,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 +5989,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 +6000,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 +6011,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 +6061,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 +6075,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 +6084,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 +6101,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 +6348,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 +6606,6 @@
     method->output_type_.Set(output_type.descriptor());
   }
 }
-
 // -------------------------------------------------------------------
 
 #define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \
@@ -6660,7 +6799,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 +7016,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 +7358,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 +8018,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 +8032,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 +8098,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 +8116,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 +8130,6 @@
   return output_type_.Get(service());
 }
 
-
 namespace internal {
 void LazyDescriptor::Set(const Descriptor* descriptor) {
   GOOGLE_CHECK(!once_);
@@ -8002,8 +8144,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 +8156,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 cf425ff..3799752 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 156e410..e5605a9 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 292c170..9e87914 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 000c3df..8b54992 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 2c52fe7..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,8 +1306,9 @@
                               ConstType default_value) {
     return static_cast<const Type&>(set.GetMessage(number, default_value));
   }
-  static inline std::nullptr_t GetPtr(int number, const ExtensionSet& set,
-                                      ConstType default_value) {
+  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,13 +1365,14 @@
   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,
-                                      int index) {
+  static inline std::nullptr_t GetPtr(int /* number */,
+                                      const ExtensionSet& /* set */,
+                                      int /* index */) {
     // Cannot be implemented because of forward declared messages?
     return nullptr;
   }
-  static inline std::nullptr_t GetRepeatedPtr(int number,
-                                              const ExtensionSet& set) {
+  static inline std::nullptr_t GetRepeatedPtr(int /* number */,
+                                              const ExtensionSet& /* set */) {
     // 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 b0fb892..a7a55b4 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 cf7cd85..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),
@@ -2325,7 +2388,7 @@
                                         MapValueRef* val) const {
   USAGE_CHECK(IsMapFieldInApi(field), "InsertOrLookupMapValue",
               "Field is not a map field.");
-  val->SetType(field->message_type()->FindFieldByName("value")->cpp_type());
+  val->SetType(field->message_type()->map_value()->cpp_type());
   return MutableRaw<MapFieldBase>(message, field)
       ->InsertOrLookupMapValue(key, val);
 }
@@ -2335,7 +2398,7 @@
                                 MapValueConstRef* val) const {
   USAGE_CHECK(IsMapFieldInApi(field), "LookupMapValue",
               "Field is not a map field.");
-  val->SetType(field->message_type()->FindFieldByName("value")->cpp_type());
+  val->SetType(field->message_type()->map_value()->cpp_type());
   return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val);
 }
 
@@ -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 15eebcb..0000000
--- a/src/google/protobuf/generated_message_table_driven.h
+++ /dev/null
@@ -1,351 +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.
-  enum {
-    kCordType = 19,
-    kStringPieceType = 20,
-    kInlinedType = 21,
-    kNumTypes = 21,
-    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..cda0cc4 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,15 +46,155 @@
 namespace protobuf {
 namespace internal {
 
+using FieldEntry = TcParseTableBase::FieldEntry;
+
 #ifndef NDEBUG
 template void AlignFail<4>(uintptr_t);
 template void AlignFail<8>(uintptr_t);
 #endif
 
+const uint32_t TcParser::kMtSmallScanSize;
+
 const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
   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 +213,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 +287,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 +316,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 +336,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 +383,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 +533,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 +577,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 +648,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 +721,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 +902,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 +927,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 +975,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 +984,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 1fe639f..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) {
+// 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
-  // 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);
+  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..ae731d6 100644
--- a/src/google/protobuf/inlined_string_field_unittest.cc
+++ b/src/google/protobuf/inlined_string_field_unittest.cc
@@ -55,232 +55,6 @@
 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 4e9d817..1024b40 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -136,6 +136,10 @@
 #include <machine/endian.h>  // __BYTE_ORDER
 #elif defined(__FreeBSD__)
 #include <sys/endian.h>  // __BYTE_ORDER
+#elif (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))
+#include <sys/isa_defs.h>  // __BYTE_ORDER
+#elif defined(_AIX) || defined(__TOS_AIX__)
+#include <sys/machine.h>  // BYTE_ORDER
 #else
 #if !defined(__QNX__)
 #include <endian.h>  // __BYTE_ORDER
@@ -154,6 +158,7 @@
 #include <google/protobuf/stubs/port.h>
 
 
+// Must be included last.
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -844,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();
@@ -1063,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.
@@ -1229,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.
   //
@@ -1272,6 +1286,9 @@
   EpsCopyOutputStream* EpsCopy() { return &impl_; }
 
  private:
+  template <class Stream>
+  void InitEagerly(Stream* stream);
+
   EpsCopyOutputStream impl_;
   uint8_t* cur_;
   int64_t start_count_;
@@ -1616,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.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index fc75e3ef..c66bc86 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -104,7 +104,7 @@
       is_closed_(false),
       errno_(0),
       previous_seek_failed_(false) {
-#ifndef _MSC_VER
+#ifndef _WIN32
   int flags = fcntl(file_, F_GETFL);
   flags &= ~O_NONBLOCK;
   fcntl(file_, F_SETFL, flags);
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 c87d44e..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;
@@ -855,8 +868,8 @@
   MapIterator(Message* message, const FieldDescriptor* field) {
     const Reflection* reflection = message->GetReflection();
     map_ = reflection->MutableMapData(message, field);
-    key_.SetType(field->message_type()->FindFieldByName("key")->cpp_type());
-    value_.SetType(field->message_type()->FindFieldByName("value")->cpp_type());
+    key_.SetType(field->message_type()->map_key()->cpp_type());
+    value_.SetType(field->message_type()->map_value()->cpp_type());
     map_->InitializeIterator(this);
   }
   MapIterator(const MapIterator& other) {
@@ -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 733f13b..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) {
@@ -1259,21 +1260,21 @@
       desc->FindFieldByName("map_int32_foreign_message");
 
   const FieldDescriptor* fd_map_int32_in32_key =
-      fd_map_int32_int32->message_type()->FindFieldByName("key");
+      fd_map_int32_int32->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_in32_value =
-      fd_map_int32_int32->message_type()->FindFieldByName("value");
+      fd_map_int32_int32->message_type()->map_value();
   const FieldDescriptor* fd_map_int32_double_key =
-      fd_map_int32_double->message_type()->FindFieldByName("key");
+      fd_map_int32_double->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_double_value =
-      fd_map_int32_double->message_type()->FindFieldByName("value");
+      fd_map_int32_double->message_type()->map_value();
   const FieldDescriptor* fd_map_string_string_key =
-      fd_map_string_string->message_type()->FindFieldByName("key");
+      fd_map_string_string->message_type()->map_key();
   const FieldDescriptor* fd_map_string_string_value =
-      fd_map_string_string->message_type()->FindFieldByName("value");
+      fd_map_string_string->message_type()->map_value();
   const FieldDescriptor* fd_map_int32_foreign_message_key =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+      fd_map_int32_foreign_message->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_foreign_message_value =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+      fd_map_int32_foreign_message->message_type()->map_value();
 
   // Get RepeatedPtrField objects for all fields of interest.
   const RepeatedPtrField<Message>& mf_int32_int32 =
@@ -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) {
@@ -1446,21 +1450,21 @@
       desc->FindFieldByName("map_int32_foreign_message");
 
   const FieldDescriptor* fd_map_int32_in32_key =
-      fd_map_int32_int32->message_type()->FindFieldByName("key");
+      fd_map_int32_int32->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_in32_value =
-      fd_map_int32_int32->message_type()->FindFieldByName("value");
+      fd_map_int32_int32->message_type()->map_value();
   const FieldDescriptor* fd_map_int32_double_key =
-      fd_map_int32_double->message_type()->FindFieldByName("key");
+      fd_map_int32_double->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_double_value =
-      fd_map_int32_double->message_type()->FindFieldByName("value");
+      fd_map_int32_double->message_type()->map_value();
   const FieldDescriptor* fd_map_string_string_key =
-      fd_map_string_string->message_type()->FindFieldByName("key");
+      fd_map_string_string->message_type()->map_key();
   const FieldDescriptor* fd_map_string_string_value =
-      fd_map_string_string->message_type()->FindFieldByName("value");
+      fd_map_string_string->message_type()->map_value();
   const FieldDescriptor* fd_map_int32_foreign_message_key =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("key");
+      fd_map_int32_foreign_message->message_type()->map_key();
   const FieldDescriptor* fd_map_int32_foreign_message_value =
-      fd_map_int32_foreign_message->message_type()->FindFieldByName("value");
+      fd_map_int32_foreign_message->message_type()->map_value();
 
   // Get RepeatedFieldRef objects for all fields of interest.
   const RepeatedFieldRef<Message> mf_int32_int32 =
@@ -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()->FindFieldByName("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()->FindFieldByName("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()->FindFieldByName("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()->FindFieldByName("key");
-  const FieldDescriptor* value =
-      map_field->message_type()->FindFieldByName("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);
@@ -3005,7 +3008,7 @@
   const FieldDescriptor* field_descriptor =
       descriptor->FindFieldByName("known_map_field");
   const FieldDescriptor* value_descriptor =
-      field_descriptor->message_type()->FindFieldByName("value");
+      field_descriptor->message_type()->map_value();
   Message* sub_message =
       message.GetReflection()->AddMessage(&message, field_descriptor);
   EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message,
@@ -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(
@@ -3133,7 +3136,7 @@
       message.get(), "map_int32_foreign_message", 0);
   const Reflection* map_entry_reflection = map_entry->GetReflection();
   const Descriptor* map_entry_desc = map_entry->GetDescriptor();
-  const FieldDescriptor* value_field = map_entry_desc->FindFieldByName("value");
+  const FieldDescriptor* value_field = map_entry_desc->map_value();
   Message* submsg =
       map_entry_reflection->MutableMessage(map_entry, value_field);
 
@@ -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()->FindFieldByName("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 62e25dc..f79b865 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 a1c2b8b..e756603 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
@@ -362,11 +366,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
@@ -459,7 +471,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))
@@ -467,6 +479,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
@@ -574,14 +593,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
@@ -598,20 +621,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__))
-#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
@@ -679,19 +725,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                                 \
@@ -712,6 +745,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
@@ -757,12 +792,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 579eb41..6b05be6 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 c96b175..9488507 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>
@@ -1624,16 +1522,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) {
-      (void)[](OtherElement* from) -> Element* { return from; };
-    }
-  }
+      : it_(other.it_) {}
 
   // dereferenceable
   reference operator*() const { return *reinterpret_cast<Element*>(*it_); }
@@ -1652,14 +1547,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) {
@@ -1687,7 +1594,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>
@@ -1697,7 +1606,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.
@@ -1717,6 +1626,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*()); }
@@ -1734,14 +1654,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) {
@@ -1769,27 +1701,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>
@@ -1992,9 +1915,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 d6bc1da..bf0bae9 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 83a9d90..12ac91c 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/common.cc b/src/google/protobuf/stubs/common.cc
index 9067818..82d4653 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -44,10 +44,6 @@
 #endif
 #include <windows.h>
 #define snprintf _snprintf    // see comment in strutil.cc
-#elif defined(HAVE_PTHREAD)
-#include <pthread.h>
-#else
-#error "No suitable threading library available."
 #endif
 #if defined(__ANDROID__)
 #include <android/log.h>
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index fa0ec47..045e25d 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -61,6 +61,10 @@
 #include <machine/endian.h>  // __BYTE_ORDER
 #elif defined(__FreeBSD__)
 #include <sys/endian.h>  // __BYTE_ORDER
+#elif (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))
+#include <sys/isa_defs.h>  // __BYTE_ORDER
+#elif defined(_AIX) || defined(__TOS_AIX__)
+#include <sys/machine.h>  // BYTE_ORDER
 #else
 #if !defined(__QNX__)
 #include <endian.h>  // __BYTE_ORDER
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 66535fe..f8a5812 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 0279828..36fa70d 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 fbbcd3c..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()->FindFieldByName("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 e03527a..fc4fa5e 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
diff --git a/tests.sh b/tests.sh
index fcfb75f..290f110 100755
--- a/tests.sh
+++ b/tests.sh
@@ -204,7 +204,7 @@
   esac
 
   MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository
-  MVN="$MVN -e -X -Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
+  MVN="$MVN -e --quiet -Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY"
 
   which java
   java -version
@@ -375,6 +375,10 @@
   build_python_version py39-python
 }
 
+build_python310() {
+  build_python_version py310-python
+}
+
 build_python_cpp() {
   internal_build_cpp
   export LD_LIBRARY_PATH=../src/.libs # for Linux
@@ -427,6 +431,11 @@
   build_python_cpp_version py39-cpp
 }
 
+build_python310_cpp() {
+  build_python_cpp_version py310-cpp
+}
+
+
 build_ruby23() {
   internal_build_cpp  # For conformance tests.
   cd ruby && bash travis-test.sh ruby-2.3.8 && cd ..
diff --git a/third_party/BUILD b/third_party/BUILD
index b66101a..a8b35ef 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -1 +1 @@
-exports_files(["six.BUILD", "zlib.BUILD"])
+exports_files(["zlib.BUILD"])
diff --git a/third_party/six.BUILD b/third_party/six.BUILD
deleted file mode 100644
index 041c72c..0000000
--- a/third_party/six.BUILD
+++ /dev/null
@@ -1,19 +0,0 @@
-load("@rules_python//python:defs.bzl", "py_library")
-
-# Consume `six.py` as `__init__.py` for compatibility
-# with `--incompatible_default_to_explicit_init_py`.
-# https://github.com/protocolbuffers/protobuf/pull/6795#issuecomment-546060749
-# https://github.com/bazelbuild/bazel/issues/10076
-genrule(
-    name = "copy_six",
-    srcs = ["six-1.12.0/six.py"],
-    outs = ["__init__.py"],
-    cmd = "cp $< $(@)",
-)
-
-py_library(
-    name = "six",
-    srcs = ["__init__.py"],
-    srcs_version = "PY2AND3",
-    visibility = ["//visibility:public"],
-)
diff --git a/third_party/utf8_range/BUILD b/third_party/utf8_range/BUILD
new file mode 100644
index 0000000..68b3e9e
--- /dev/null
+++ b/third_party/utf8_range/BUILD
@@ -0,0 +1,13 @@
+
+cc_library(
+    name = "utf8_range",
+    hdrs = ["utf8_range.h"],
+    srcs = ["utf8_range.c"],
+    visibility = ["//:__pkg__"],
+)
+
+filegroup(
+    name = "cmake_files",
+    srcs = glob(["*"]),
+    visibility = ["//cmake:__pkg__"],
+)
diff --git a/third_party/utf8_range/LICENSE b/third_party/utf8_range/LICENSE
new file mode 100644
index 0000000..c1f087e
--- /dev/null
+++ b/third_party/utf8_range/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Yibo Cai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/utf8_range/utf8_range.c b/third_party/utf8_range/utf8_range.c
new file mode 100644
index 0000000..109a54d
--- /dev/null
+++ b/third_party/utf8_range/utf8_range.c
@@ -0,0 +1,395 @@
+
+/*
+ * http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94
+ *
+ * Table 3-7. Well-Formed UTF-8 Byte Sequences
+ *
+ * +--------------------+------------+-------------+------------+-------------+
+ * | Code Points        | First Byte | Second Byte | Third Byte | Fourth Byte |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+0000..U+007F     | 00..7F     |             |            |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+0080..U+07FF     | C2..DF     | 80..BF      |            |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+0800..U+0FFF     | E0         | A0..BF      | 80..BF     |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+1000..U+CFFF     | E1..EC     | 80..BF      | 80..BF     |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+D000..U+D7FF     | ED         | 80..9F      | 80..BF     |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+E000..U+FFFF     | EE..EF     | 80..BF      | 80..BF     |             |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+10000..U+3FFFF   | F0         | 90..BF      | 80..BF     | 80..BF      |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+40000..U+FFFFF   | F1..F3     | 80..BF      | 80..BF     | 80..BF      |
+ * +--------------------+------------+-------------+------------+-------------+
+ * | U+100000..U+10FFFF | F4         | 80..8F      | 80..BF     | 80..BF      |
+ * +--------------------+------------+-------------+------------+-------------+
+ */
+
+/* Return 0 - success,  >0 - index(1 based) of first error char */
+int utf8_naive(const unsigned char* data, int len) {
+  int err_pos = 1;
+
+  while (len) {
+    int bytes;
+    const unsigned char byte1 = data[0];
+
+    /* 00..7F */
+    if (byte1 <= 0x7F) {
+      bytes = 1;
+      /* C2..DF, 80..BF */
+    } else if (len >= 2 && byte1 >= 0xC2 && byte1 <= 0xDF &&
+               (signed char)data[1] <= (signed char)0xBF) {
+      bytes = 2;
+    } else if (len >= 3) {
+      const unsigned char byte2 = data[1];
+
+      /* Is byte2, byte3 between 0x80 ~ 0xBF */
+      const int byte2_ok = (signed char)byte2 <= (signed char)0xBF;
+      const int byte3_ok = (signed char)data[2] <= (signed char)0xBF;
+
+      if (byte2_ok && byte3_ok &&
+          /* E0, A0..BF, 80..BF */
+          ((byte1 == 0xE0 && byte2 >= 0xA0) ||
+           /* E1..EC, 80..BF, 80..BF */
+           (byte1 >= 0xE1 && byte1 <= 0xEC) ||
+           /* ED, 80..9F, 80..BF */
+           (byte1 == 0xED && byte2 <= 0x9F) ||
+           /* EE..EF, 80..BF, 80..BF */
+           (byte1 >= 0xEE && byte1 <= 0xEF))) {
+        bytes = 3;
+      } else if (len >= 4) {
+        /* Is byte4 between 0x80 ~ 0xBF */
+        const int byte4_ok = (signed char)data[3] <= (signed char)0xBF;
+
+        if (byte2_ok && byte3_ok && byte4_ok &&
+            /* F0, 90..BF, 80..BF, 80..BF */
+            ((byte1 == 0xF0 && byte2 >= 0x90) ||
+             /* F1..F3, 80..BF, 80..BF, 80..BF */
+             (byte1 >= 0xF1 && byte1 <= 0xF3) ||
+             /* F4, 80..8F, 80..BF, 80..BF */
+             (byte1 == 0xF4 && byte2 <= 0x8F))) {
+          bytes = 4;
+        } else {
+          return err_pos;
+        }
+      } else {
+        return err_pos;
+      }
+    } else {
+      return err_pos;
+    }
+
+    len -= bytes;
+    err_pos += bytes;
+    data += bytes;
+  }
+
+  return 0;
+}
+
+#ifdef __SSE4_1__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <x86intrin.h>
+
+int utf8_naive(const unsigned char* data, int len);
+
+static const int8_t _first_len_tbl[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
+};
+
+static const int8_t _first_range_tbl[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
+};
+
+static const int8_t _range_min_tbl[] = {
+    0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80,
+    0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+};
+static const int8_t _range_max_tbl[] = {
+    0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F,
+    0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+static const int8_t _df_ee_tbl[] = {
+    0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
+};
+static const int8_t _ef_fe_tbl[] = {
+    0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Return 0 on success, -1 on error */
+int utf8_range2(const unsigned char* data, int len) {
+  if (len >= 32) {
+    __m128i prev_input = _mm_set1_epi8(0);
+    __m128i prev_first_len = _mm_set1_epi8(0);
+
+    const __m128i first_len_tbl =
+        _mm_loadu_si128((const __m128i*)_first_len_tbl);
+    const __m128i first_range_tbl =
+        _mm_loadu_si128((const __m128i*)_first_range_tbl);
+    const __m128i range_min_tbl =
+        _mm_loadu_si128((const __m128i*)_range_min_tbl);
+    const __m128i range_max_tbl =
+        _mm_loadu_si128((const __m128i*)_range_max_tbl);
+    const __m128i df_ee_tbl = _mm_loadu_si128((const __m128i*)_df_ee_tbl);
+    const __m128i ef_fe_tbl = _mm_loadu_si128((const __m128i*)_ef_fe_tbl);
+
+    __m128i error = _mm_set1_epi8(0);
+
+    while (len >= 32) {
+      /***************************** block 1 ****************************/
+      const __m128i input_a = _mm_loadu_si128((const __m128i*)data);
+
+      __m128i high_nibbles =
+          _mm_and_si128(_mm_srli_epi16(input_a, 4), _mm_set1_epi8(0x0F));
+
+      __m128i first_len_a = _mm_shuffle_epi8(first_len_tbl, high_nibbles);
+
+      __m128i range_a = _mm_shuffle_epi8(first_range_tbl, high_nibbles);
+
+      range_a = _mm_or_si128(range_a,
+                             _mm_alignr_epi8(first_len_a, prev_first_len, 15));
+
+      __m128i tmp;
+      tmp = _mm_alignr_epi8(first_len_a, prev_first_len, 14);
+      tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(1));
+      range_a = _mm_or_si128(range_a, tmp);
+
+      tmp = _mm_alignr_epi8(first_len_a, prev_first_len, 13);
+      tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(2));
+      range_a = _mm_or_si128(range_a, tmp);
+
+      __m128i shift1, pos, range2;
+      shift1 = _mm_alignr_epi8(input_a, prev_input, 15);
+      pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF));
+      tmp = _mm_subs_epu8(pos, _mm_set1_epi8(0xF0));
+      range2 = _mm_shuffle_epi8(df_ee_tbl, tmp);
+      tmp = _mm_adds_epu8(pos, _mm_set1_epi8(0x70));
+      range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_tbl, tmp));
+
+      range_a = _mm_add_epi8(range_a, range2);
+
+      __m128i minv = _mm_shuffle_epi8(range_min_tbl, range_a);
+      __m128i maxv = _mm_shuffle_epi8(range_max_tbl, range_a);
+
+      tmp = _mm_or_si128(_mm_cmplt_epi8(input_a, minv),
+                         _mm_cmpgt_epi8(input_a, maxv));
+      error = _mm_or_si128(error, tmp);
+
+      /***************************** block 2 ****************************/
+      const __m128i input_b = _mm_loadu_si128((const __m128i*)(data + 16));
+
+      high_nibbles =
+          _mm_and_si128(_mm_srli_epi16(input_b, 4), _mm_set1_epi8(0x0F));
+
+      __m128i first_len_b = _mm_shuffle_epi8(first_len_tbl, high_nibbles);
+
+      __m128i range_b = _mm_shuffle_epi8(first_range_tbl, high_nibbles);
+
+      range_b =
+          _mm_or_si128(range_b, _mm_alignr_epi8(first_len_b, first_len_a, 15));
+
+      tmp = _mm_alignr_epi8(first_len_b, first_len_a, 14);
+      tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(1));
+      range_b = _mm_or_si128(range_b, tmp);
+
+      tmp = _mm_alignr_epi8(first_len_b, first_len_a, 13);
+      tmp = _mm_subs_epu8(tmp, _mm_set1_epi8(2));
+      range_b = _mm_or_si128(range_b, tmp);
+
+      shift1 = _mm_alignr_epi8(input_b, input_a, 15);
+      pos = _mm_sub_epi8(shift1, _mm_set1_epi8(0xEF));
+      tmp = _mm_subs_epu8(pos, _mm_set1_epi8(0xF0));
+      range2 = _mm_shuffle_epi8(df_ee_tbl, tmp);
+      tmp = _mm_adds_epu8(pos, _mm_set1_epi8(0x70));
+      range2 = _mm_add_epi8(range2, _mm_shuffle_epi8(ef_fe_tbl, tmp));
+
+      range_b = _mm_add_epi8(range_b, range2);
+
+      minv = _mm_shuffle_epi8(range_min_tbl, range_b);
+      maxv = _mm_shuffle_epi8(range_max_tbl, range_b);
+
+      tmp = _mm_or_si128(_mm_cmplt_epi8(input_b, minv),
+                         _mm_cmpgt_epi8(input_b, maxv));
+      error = _mm_or_si128(error, tmp);
+
+      /************************ next iteration **************************/
+      prev_input = input_b;
+      prev_first_len = first_len_b;
+
+      data += 32;
+      len -= 32;
+    }
+
+    if (!_mm_testz_si128(error, error)) return -1;
+
+    int32_t token4 = _mm_extract_epi32(prev_input, 3);
+    const int8_t* token = (const int8_t*)&token4;
+    int lookahead = 0;
+    if (token[3] > (int8_t)0xBF)
+      lookahead = 1;
+    else if (token[2] > (int8_t)0xBF)
+      lookahead = 2;
+    else if (token[1] > (int8_t)0xBF)
+      lookahead = 3;
+
+    data -= lookahead;
+    len += lookahead;
+  }
+
+  return utf8_naive(data, len);
+}
+
+#endif
+
+#ifdef __ARM_NEON
+
+#include <arm_neon.h>
+#include <stdint.h>
+#include <stdio.h>
+
+int utf8_naive(const unsigned char* data, int len);
+
+static const uint8_t _first_len_tbl[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
+};
+
+static const uint8_t _first_range_tbl[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
+};
+
+static const uint8_t _range_min_tbl[] = {
+    0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80,
+    0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+static const uint8_t _range_max_tbl[] = {
+    0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F,
+    0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const uint8_t _range_adjust_tbl[] = {
+    2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+};
+
+/* Return 0 on success, -1 on error */
+int utf8_range2(const unsigned char* data, int len) {
+  if (len >= 32) {
+    uint8x16_t prev_input = vdupq_n_u8(0);
+    uint8x16_t prev_first_len = vdupq_n_u8(0);
+
+    const uint8x16_t first_len_tbl = vld1q_u8(_first_len_tbl);
+    const uint8x16_t first_range_tbl = vld1q_u8(_first_range_tbl);
+    const uint8x16_t range_min_tbl = vld1q_u8(_range_min_tbl);
+    const uint8x16_t range_max_tbl = vld1q_u8(_range_max_tbl);
+    const uint8x16x2_t range_adjust_tbl = vld2q_u8(_range_adjust_tbl);
+
+    const uint8x16_t const_1 = vdupq_n_u8(1);
+    const uint8x16_t const_2 = vdupq_n_u8(2);
+    const uint8x16_t const_e0 = vdupq_n_u8(0xE0);
+
+    uint8x16_t error1 = vdupq_n_u8(0);
+    uint8x16_t error2 = vdupq_n_u8(0);
+    uint8x16_t error3 = vdupq_n_u8(0);
+    uint8x16_t error4 = vdupq_n_u8(0);
+
+    while (len >= 32) {
+      /******************* two blocks interleaved **********************/
+
+#if defined(__GNUC__) && !defined(__clang__) && (__GNUC__ < 8)
+      /* gcc doesn't support vldq1_u8_x2 until version 8 */
+      const uint8x16_t input_a = vld1q_u8(data);
+      const uint8x16_t input_b = vld1q_u8(data + 16);
+#else
+      /* Forces a double load on Clang */
+      const uint8x16x2_t input_pair = vld1q_u8_x2(data);
+      const uint8x16_t input_a = input_pair.val[0];
+      const uint8x16_t input_b = input_pair.val[1];
+#endif
+
+      const uint8x16_t high_nibbles_a = vshrq_n_u8(input_a, 4);
+      const uint8x16_t high_nibbles_b = vshrq_n_u8(input_b, 4);
+
+      const uint8x16_t first_len_a = vqtbl1q_u8(first_len_tbl, high_nibbles_a);
+      const uint8x16_t first_len_b = vqtbl1q_u8(first_len_tbl, high_nibbles_b);
+
+      uint8x16_t range_a = vqtbl1q_u8(first_range_tbl, high_nibbles_a);
+      uint8x16_t range_b = vqtbl1q_u8(first_range_tbl, high_nibbles_b);
+
+      range_a = vorrq_u8(range_a, vextq_u8(prev_first_len, first_len_a, 15));
+      range_b = vorrq_u8(range_b, vextq_u8(first_len_a, first_len_b, 15));
+
+      uint8x16_t tmp1_a, tmp2_a, tmp1_b, tmp2_b;
+      tmp1_a = vextq_u8(prev_first_len, first_len_a, 14);
+      tmp1_a = vqsubq_u8(tmp1_a, const_1);
+      range_a = vorrq_u8(range_a, tmp1_a);
+
+      tmp1_b = vextq_u8(first_len_a, first_len_b, 14);
+      tmp1_b = vqsubq_u8(tmp1_b, const_1);
+      range_b = vorrq_u8(range_b, tmp1_b);
+
+      tmp2_a = vextq_u8(prev_first_len, first_len_a, 13);
+      tmp2_a = vqsubq_u8(tmp2_a, const_2);
+      range_a = vorrq_u8(range_a, tmp2_a);
+
+      tmp2_b = vextq_u8(first_len_a, first_len_b, 13);
+      tmp2_b = vqsubq_u8(tmp2_b, const_2);
+      range_b = vorrq_u8(range_b, tmp2_b);
+
+      uint8x16_t shift1_a = vextq_u8(prev_input, input_a, 15);
+      uint8x16_t pos_a = vsubq_u8(shift1_a, const_e0);
+      range_a = vaddq_u8(range_a, vqtbl2q_u8(range_adjust_tbl, pos_a));
+
+      uint8x16_t shift1_b = vextq_u8(input_a, input_b, 15);
+      uint8x16_t pos_b = vsubq_u8(shift1_b, const_e0);
+      range_b = vaddq_u8(range_b, vqtbl2q_u8(range_adjust_tbl, pos_b));
+
+      uint8x16_t minv_a = vqtbl1q_u8(range_min_tbl, range_a);
+      uint8x16_t maxv_a = vqtbl1q_u8(range_max_tbl, range_a);
+
+      uint8x16_t minv_b = vqtbl1q_u8(range_min_tbl, range_b);
+      uint8x16_t maxv_b = vqtbl1q_u8(range_max_tbl, range_b);
+
+      error1 = vorrq_u8(error1, vcltq_u8(input_a, minv_a));
+      error2 = vorrq_u8(error2, vcgtq_u8(input_a, maxv_a));
+
+      error3 = vorrq_u8(error3, vcltq_u8(input_b, minv_b));
+      error4 = vorrq_u8(error4, vcgtq_u8(input_b, maxv_b));
+
+      /************************ next iteration *************************/
+      prev_input = input_b;
+      prev_first_len = first_len_b;
+
+      data += 32;
+      len -= 32;
+    }
+    error1 = vorrq_u8(error1, error2);
+    error1 = vorrq_u8(error1, error3);
+    error1 = vorrq_u8(error1, error4);
+
+    if (vmaxvq_u8(error1)) return -1;
+
+    uint32_t token4;
+    vst1q_lane_u32(&token4, vreinterpretq_u32_u8(prev_input), 3);
+
+    const int8_t* token = (const int8_t*)&token4;
+    int lookahead = 0;
+    if (token[3] > (int8_t)0xBF)
+      lookahead = 1;
+    else if (token[2] > (int8_t)0xBF)
+      lookahead = 2;
+    else if (token[1] > (int8_t)0xBF)
+      lookahead = 3;
+
+    data -= lookahead;
+    len += lookahead;
+  }
+
+  return utf8_naive(data, len);
+}
+
+#endif
diff --git a/third_party/utf8_range/utf8_range.h b/third_party/utf8_range/utf8_range.h
new file mode 100644
index 0000000..86daa0b
--- /dev/null
+++ b/third_party/utf8_range/utf8_range.h
@@ -0,0 +1,9 @@
+
+#if defined(__ARM_NEON) || defined(__SSE4_1__)
+int utf8_range2(const unsigned char* data, int len);
+#else
+int utf8_naive(const unsigned char* data, int len);
+static inline int utf8_range2(const unsigned char* data, int len) {
+  return utf8_naive(data, len);
+}
+#endif
diff --git a/toolchain/BUILD b/toolchain/BUILD
index f5c3853..467d1a5 100644
--- a/toolchain/BUILD
+++ b/toolchain/BUILD
@@ -4,17 +4,21 @@
 
 filegroup(name = "empty")
 
-LINUX_TOOLCHAINS = {
+TOOLCHAINS = {
+    "osx-x86_64": "cc-compiler-osx-x86_64",
+    "osx-aarch_64": "cc-compiler-osx-aarch_64",
     "linux-aarch_64": "cc-compiler-linux-aarch_64",
     "linux-ppcle_64": "cc-compiler-linux-ppcle_64",
     "linux-s390_64": "cc-compiler-linux-s390_64",
     "linux-x86_32": "cc-compiler-linux-x86_32",
     "linux-x86_64": "cc-compiler-linux-x86_64",
+    "win32": "cc-compiler-windows-x86_32",
+    "win64": "cc-compiler-windows-x86_64",
 }
 
 cc_toolchain_suite(
     name = "clang_suite",
-    toolchains = LINUX_TOOLCHAINS
+    toolchains = TOOLCHAINS
 )
 
 [
@@ -32,13 +36,19 @@
         toolchain_config = ":" + cpu + "-config",
         toolchain_identifier = toolchain,
     )
-    for cpu, toolchain in LINUX_TOOLCHAINS.items()
+    for cpu, toolchain in TOOLCHAINS.items()
 ]
 
 cc_toolchain_config(
     name = "linux-aarch_64-config",
     bit_flag = "-m64",
-    include_flag = "-I/usr/aarch64-linux-gnu/include/c++/8/aarch64-linux-gnu/",
+    cpp_flag = "-lstdc++",
+    extra_compiler_flags = [
+        "-I/usr/aarch64-linux-gnu/include/c++/8/aarch64-linux-gnu/",
+        "-I/usr/aarch64-linux-gnu/include/c++/8"
+    ],
+    extra_include = "/usr/include",
+    linker_path = "/usr/bin/ld",
     target_cpu = "aarch64",
     target_full_name = "aarch64-linux-gnu",
     toolchain_dir = "/usr/aarch64-linux-gnu/include",
@@ -48,7 +58,13 @@
 cc_toolchain_config(
     name = "linux-ppcle_64-config",
     bit_flag = "-m64",
-    include_flag = "-I/usr/powerpc64le-linux-gnu/include/c++/8/powerpc64le-linux-gnu/",
+    cpp_flag = "-lstdc++",
+    extra_compiler_flags = [
+        "-I/usr/powerpc64le-linux-gnu/include/c++/8/powerpc64le-linux-gnu/",
+        "-I/usr/powerpc64le-linux-gnu/include/c++/8/"
+    ],
+    extra_include = "/usr/include",
+    linker_path = "/usr/bin/ld",
     target_cpu = "ppc64",
     target_full_name = "powerpc64le-linux-gnu",
     toolchain_dir = "/usr/powerpc64le-linux-gnu/include",
@@ -58,7 +74,13 @@
 cc_toolchain_config(
     name = "linux-s390_64-config",
     bit_flag = "-m64",
-    include_flag = "-I/usr/s390x-linux-gnu/include/c++/8/s390x-linux-gnu/",
+    cpp_flag = "-lstdc++",
+    extra_compiler_flags = [
+        "-I/usr/s390x-linux-gnu/include/c++/8/s390x-linux-gnu/",
+        "-I/usr/s390x-linux-gnu/include/c++/8/"
+    ],
+    extra_include = "/usr/include",
+    linker_path = "/usr/bin/ld",
     target_cpu = "systemz",
     target_full_name = "s390x-linux-gnu",
     toolchain_dir = "/usr/s390x-linux-gnu/include",
@@ -68,6 +90,9 @@
 cc_toolchain_config(
     name = "linux-x86_32-config",
     bit_flag = "-m32",
+    cpp_flag = "-lstdc++",
+    extra_include = "/usr/include",
+    linker_path = "/usr/bin/ld",
     target_cpu = "x86_32",
     target_full_name = "i386-linux-gnu",
     toolchain_dir = "/usr/include/i386-linux-gnu",
@@ -77,8 +102,85 @@
 cc_toolchain_config(
     name = "linux-x86_64-config",
     bit_flag = "-m64",
+    cpp_flag = "-lstdc++",
+    extra_include = "/usr/include",
+    linker_path = "/usr/bin/ld",
     target_cpu = "x86_64",
     target_full_name = "x86_64-linux-gnu",
     toolchain_dir = "/usr/include/x86_64-linux-gnu",
     toolchain_name = "linux_x86_64",
 )
+
+cc_toolchain_config(
+    name = "osx-aarch_64-config",
+    bit_flag = "-m64",
+    cpp_flag = "-lc++",
+    extra_compiler_flags = [
+        "-I/usr/tools/apple_sdks/xcode_13_0/macosx/usr/include/c++/v1",
+        "-I/usr/tools/apple_sdks/xcode_13_0/macosx/usr/include"
+    ],
+    extra_include = "/usr/include",
+    linker_path = "/usr/tools",
+    sysroot = "/usr/tools/apple_sdks/xcode_13_0/macosx",
+    target_cpu = "aarch64",
+    target_full_name = "aarch64-apple-macosx11.3",
+    toolchain_dir = "/usr/tools/apple_sdks/xcode_13_0/macosx",
+    toolchain_name = "osx_aarch_64",
+)
+
+cc_toolchain_config(
+    name = "osx-x86_64-config",
+    bit_flag = "-m64",
+    cpp_flag = "-lc++",
+    extra_compiler_flags = [
+        "-I/usr/tools/apple_sdks/xcode_13_0/macosx/usr/include/c++/v1",
+        "-I/usr/tools/apple_sdks/xcode_13_0/macosx/usr/include"
+    ],
+    extra_include = "/usr/include",
+    linker_path = "/usr/tools",
+    sysroot = "/usr/tools/apple_sdks/xcode_13_0/macosx",
+    target_cpu = "x86_64",
+    target_full_name = "x86_64-apple-macosx11.3",
+    toolchain_dir = "/usr/tools/apple_sdks/xcode_13_0/macosx",
+    toolchain_name = "osx_x86_64",
+)
+
+cc_toolchain_config(
+    name = "win32-config",
+    bit_flag = "-m32",
+    cpp_flag = "-lstdc++",
+    extra_compiler_flags = [
+        "-isystem/usr/lib/gcc/i686-w64-mingw32/8.3-posix/include/c++",
+        "-isystem/usr/lib/gcc/i686-w64-mingw32/8.3-posix/include/c++/i686-w64-mingw32",
+        "-fsjlj-exceptions",
+    ],
+    extra_include = "/usr/lib/gcc/i686-w64-mingw32/8.3-posix/include",
+    extra_linker_flags = [
+        "-L/usr/lib/gcc/i686-w64-mingw32/8.3-posix",
+        "-pthread",
+    ],
+    linker_path = "/usr/bin/ld",
+    target_cpu = "x86_32",
+    target_full_name = "i686-w64-mingw32",
+    toolchain_dir = "/usr/i686-w64-mingw32/include",
+    toolchain_name = "i686-w64-mingw32",
+)
+
+cc_toolchain_config(
+    name = "win64-config",
+    bit_flag = "-m64",
+    cpp_flag = "-lstdc++",
+    extra_compiler_flags = [
+        "-isystem/usr/lib/gcc/x86_64-w64-mingw32/8.3-posix/include/c++/",
+        "-isystem/usr/lib/gcc/x86_64-w64-mingw32/8.3-posix/include/c++/x86_64-w64-mingw32",
+    ],
+    extra_include = "/usr/lib/gcc/x86_64-w64-mingw32/8.3-posix/include",
+    extra_linker_flags = [
+        "-L/usr/lib/gcc/x86_64-w64-mingw32/8.3-posix",
+    ],
+    linker_path = "/usr/bin/ld",
+    target_cpu = "x86_64",
+    target_full_name = "x86_64-w64-mingw32",
+    toolchain_dir = "/usr/x86_64-w64-mingw32/include",
+    toolchain_name = "x86_64-w64-mingw32",
+)
diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl
index 4478a11..1d54c1d 100644
--- a/toolchain/cc_toolchain_config.bzl
+++ b/toolchain/cc_toolchain_config.bzl
@@ -1,10 +1,10 @@
 load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
 load(
     "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+    "artifact_name_pattern",
     "feature",
     "flag_group",
     "flag_set",
-    "tool",
     "tool_path",
 )
 
@@ -28,6 +28,14 @@
 ]
 
 def _impl(ctx):
+  artifact_name_patterns = [
+      artifact_name_pattern(
+          category_name = "executable",
+          prefix = "",
+          extension = ".exe",
+      ),
+  ]
+
   tool_paths = [
       tool_path(
           name = "gcc",
@@ -35,15 +43,15 @@
       ),
       tool_path(
           name = "ld",
-          path = "/usr/bin/ld",
+          path = ctx.attr.linker_path,
       ),
       tool_path(
           name = "ar",
-          path = "/usr/bin/ar",
+          path = "/usr/local/bin/llvm-ar",
       ),
       tool_path(
           name = "compat-ld",
-          path = "/usr/bin/ld",
+          path = ctx.attr.linker_path,
       ),
       tool_path(
           name = "cpp",
@@ -84,14 +92,35 @@
               flag_groups = [
                   flag_group(
                       flags = [
-                          "-lstdc++",
+                          "-B" + ctx.attr.linker_path,
+                          ctx.attr.cpp_flag,
                           "--target=" + ctx.attr.target_full_name,
+                      ] + ctx.attr.extra_linker_flags,
+                  ),
+              ],
+          ),
+      ],
+  )
+
+  sysroot_flags = feature(
+      name = "sysroot_flags",
+      #Only enable this if a sysroot was specified
+      enabled = (ctx.attr.sysroot != ""),
+      flag_sets = [
+          flag_set(
+              actions = all_link_actions,
+              flag_groups = [
+                  flag_group(
+                      flags = [
+                          "--sysroot",
+                          ctx.attr.sysroot,
                       ],
                   ),
               ],
           ),
       ],
   )
+
   compiler_flags = feature(
       name = "default_compile_flags",
       enabled = True,
@@ -105,9 +134,10 @@
                           "-Wall",
                           "-no-canonical-prefixes",
                           "--target=" + ctx.attr.target_full_name,
+                          "-fvisibility=hidden",
+                      ] + ctx.attr.extra_compiler_flags + [
                           "-isystem",
                           ctx.attr.toolchain_dir,
-                          ctx.attr.include_flag,
                       ],
                   ),
               ],
@@ -116,16 +146,18 @@
   )
 
   return cc_common.create_cc_toolchain_config_info(
-      abi_libc_version = ctx.attr.target_cpu,
-      abi_version = ctx.attr.target_cpu,
+      abi_libc_version = ctx.attr.abi_version,
+      abi_version = ctx.attr.abi_version,
+      artifact_name_patterns = artifact_name_patterns,
       ctx = ctx,
       compiler = "clang",
       cxx_builtin_include_directories = [
           ctx.attr.toolchain_dir,
-          "/usr/include",
+          ctx.attr.extra_include,
+          "/usr/local/include",
           "/usr/local/lib/clang",
       ],
-      features = [linker_flags, compiler_flags],
+      features = [linker_flags, compiler_flags, sysroot_flags],
       host_system_name = "local",
       target_cpu = ctx.attr.target_cpu,
       target_libc = ctx.attr.target_cpu,
@@ -137,8 +169,14 @@
 cc_toolchain_config = rule(
     implementation = _impl,
     attrs = {
+        "abi_version": attr.string(default = "local"),
         "bit_flag": attr.string(mandatory = True, values = ["-m32", "-m64"]),
-        "include_flag": attr.string(mandatory = False),
+        "cpp_flag": attr.string(mandatory = True),
+        "extra_compiler_flags": attr.string_list(),
+        "extra_include": attr.string(mandatory = False),
+        "extra_linker_flags": attr.string_list(),
+        "linker_path": attr.string(mandatory = True),
+        "sysroot": attr.string(mandatory = False),
         "target_cpu": attr.string(mandatory = True, values = ["aarch64", "ppc64", "systemz", "x86_32", "x86_64"]),
         "target_full_name": attr.string(mandatory = True),
         "toolchain_dir": attr.string(mandatory = True),
diff --git a/toolchain/toolchains.bazelrc b/toolchain/toolchains.bazelrc
index f56e4ce..33b8ff9 100644
--- a/toolchain/toolchains.bazelrc
+++ b/toolchain/toolchains.bazelrc
@@ -6,3 +6,7 @@
 build:linux-s390_64 --config=cross_config --cpu=linux-s390_64
 build:linux-x86_32 --config=cross_config --cpu=linux-x86_32
 build:linux-x86_64 --config=cross_config --cpu=linux-x86_64
+build:osx-aarch_64 --config=cross_config --cpu=osx-aarch_64
+build:osx-x86_64 --config=cross_config --cpu=osx-x86_64
+build:win32 --config=cross_config --cpu=win32
+build:win64 --config=cross_config --cpu=win64
diff --git a/update_version.py b/update_version.py
index b96f715..2c2b489 100755
--- a/update_version.py
+++ b/update_version.py
@@ -241,6 +241,24 @@
   RewriteXml('protoc-artifacts/pom.xml',
     lambda document : ReplaceText(
       Find(document.documentElement, 'version'), GetFullVersion()))
+  
+  RewriteTextFile('java/README.md',
+    lambda line : re.sub(
+      r'<version>.*</version>',
+      '<version>%s</version>' % GetFullVersion(),
+      line))
+
+  RewriteTextFile('java/README.md',
+    lambda line : re.sub(
+      r'implementation \'com.google.protobuf:protobuf-java:.*\'',
+      'implementation \'com.google.protobuf:protobuf-java:%s\'' % GetFullVersion(),
+      line))
+
+  RewriteTextFile('java/lite.md',
+    lambda line : re.sub(
+      r'<version>.*</version>',
+      '<version>%s</version>' % GetFullVersion(),
+      line))
 
 
 def UpdateJavaScript():