down integration from internal
diff --git a/Makefile.am b/Makefile.am
index 5af3f31..688486b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -791,6 +791,7 @@
   python/google/protobuf/internal/descriptor_test.py                         \
   python/google/protobuf/internal/encoder.py                                 \
   python/google/protobuf/internal/enum_type_wrapper.py                       \
+  python/google/protobuf/internal/extension_dict.py                          \
   python/google/protobuf/internal/factory_test1.proto                        \
   python/google/protobuf/internal/factory_test2.proto                        \
   python/google/protobuf/internal/file_options_test.proto                    \
diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake
index 344df28..890074f 100644
--- a/cmake/libprotobuf-lite.cmake
+++ b/cmake/libprotobuf-lite.cmake
@@ -1,4 +1,5 @@
 set(libprotobuf_lite_files
+  ${protobuf_source_dir}/src/google/protobuf/any_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/arena.cc
   ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java
index 008f3bc..478b186 100644
--- a/conformance/ConformanceJava.java
+++ b/conformance/ConformanceJava.java
@@ -249,13 +249,30 @@
         break;
       }
       case TEXT_PAYLOAD: {
-        try {
-          TestMessagesProto3.TestAllTypesProto3.Builder builder =
-              TestMessagesProto3.TestAllTypesProto3.newBuilder();
-          TextFormat.merge(request.getTextPayload(), builder);
-          testMessage = builder.build();
-        } catch (TextFormat.ParseException e) {
-          return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build();
+        if (isProto3) {
+          try {
+            TestMessagesProto3.TestAllTypesProto3.Builder builder =
+                TestMessagesProto3.TestAllTypesProto3.newBuilder();
+            TextFormat.merge(request.getTextPayload(), builder);
+            testMessage = builder.build();
+          } catch (TextFormat.ParseException e) {
+              return Conformance.ConformanceResponse.newBuilder()
+                  .setParseError(e.getMessage())
+                  .build();
+          }
+        } else if (isProto2) {
+          try {
+            TestMessagesProto2.TestAllTypesProto2.Builder builder =
+                TestMessagesProto2.TestAllTypesProto2.newBuilder();
+            TextFormat.merge(request.getTextPayload(), builder);
+            testMessage = builder.build();
+          } catch (TextFormat.ParseException e) {
+              return Conformance.ConformanceResponse.newBuilder()
+                  .setParseError(e.getMessage())
+                  .build();
+          }
+        } else {
+          throw new RuntimeException("Protobuf request doesn't have specific payload type.");
         }
         break;
       }
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index f45bfe3..18ac673 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -207,9 +207,11 @@
 
 conformance_test_runner_LDADD = $(top_srcdir)/src/libprotobuf.la
 conformance_test_runner_SOURCES = conformance_test.h conformance_test.cc \
-                                  binary_json_conformance_main.cc        \
+                                  conformance_test_main.cc               \
                                   binary_json_conformance_suite.h        \
                                   binary_json_conformance_suite.cc       \
+                                  text_format_conformance_suite.h        \
+                                  text_format_conformance_suite.cc       \
                                   conformance_test_runner.cc             \
                                   third_party/jsoncpp/json.h             \
                                   third_party/jsoncpp/jsoncpp.cpp
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index 45d9c16..9506ff1 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -681,6 +681,20 @@
 }
 
 void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
+  // Hack to get the list of test failures based on whether
+  // GOOGLE3_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER is enabled or not.
+  conformance::FailureSet failure_set;
+  ConformanceRequest req;
+  ConformanceResponse res;
+  req.set_message_type(failure_set.GetTypeName());
+  req.set_protobuf_payload("");
+  req.set_requested_output_format(conformance::WireFormat::PROTOBUF);
+  RunTest("FindFailures", req, &res);
+  GOOGLE_CHECK(failure_set.MergeFromString(res.protobuf_payload()));
+  for (const string& failure : failure_set.failure()) {
+    AddExpectedFailedTest(failure);
+  }
+
   type_resolver_.reset(NewTypeResolverForDescriptorPool(
       kTypeUrlPrefix, DescriptorPool::generated_pool()));
   type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
diff --git a/conformance/conformance_python.py b/conformance/conformance_python.py
index 623f8f5..5c4f900 100755
--- a/conformance/conformance_python.py
+++ b/conformance/conformance_python.py
@@ -65,7 +65,12 @@
     # TODO(gerbens): Remove, this is a hack to detect if the old vs new
     # parser is used by the cpp code. Relying on a bug in the old parser.
     hack_proto = test_messages_proto2_pb2.TestAllTypesProto2()
-    if hack_proto.ParseFromString(b"\322\002\001"):
+    old_parser = True
+    try:
+      hack_proto.ParseFromString(b"\322\002\001")
+    except message.DecodeError as e:
+      old_parser = False
+    if old_parser:
       # the string above is one of the failing conformance test strings of the
       # old parser. If we succeed the c++ implementation is using the old
       # parser so we add the list of failing conformance tests.
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index b743e8e..221464c 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -361,6 +361,10 @@
   return "";
 }
 
+void ConformanceTestSuite::AddExpectedFailedTest(const std::string& test_name) {
+  expected_to_fail_.insert(test_name);
+}
+
 bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
                                     std::string* output, const string& filename,
                                     conformance::FailureSet* failure_list) {
@@ -374,17 +378,10 @@
 
   output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
 
-  ConformanceRequest req;
-  ConformanceResponse res;
-  req.set_message_type(failure_list->GetTypeName());
-  req.set_protobuf_payload("");
-  req.set_requested_output_format(conformance::WireFormat::PROTOBUF);
-  RunTest("FindFailures", req, &res);
-  GOOGLE_CHECK(failure_list->MergeFromString(res.protobuf_payload()));
   failure_list_filename_ = filename;
   expected_to_fail_.clear();
   for (const string& failure : failure_list->failure()) {
-    expected_to_fail_.insert(failure);
+    AddExpectedFailedTest(failure);
   }
   RunSuiteImpl();
 
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index e0bc1e0..b64943d 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -84,8 +84,9 @@
 // over a pipe.
 class ForkPipeRunner : public ConformanceTestRunner {
  public:
+  // Note: Run() doesn't take ownership of the pointers inside suites.
   static int Run(int argc, char *argv[],
-                 ConformanceTestSuite* suite);
+                 const std::vector<ConformanceTestSuite*>& suites);
 
   ForkPipeRunner(const std::string &executable)
       : child_pid_(-1), executable_(executable) {}
@@ -139,7 +140,10 @@
 //
 class ConformanceTestSuite {
  public:
-  ConformanceTestSuite() : verbose_(false), enforce_recommended_(false) {}
+  ConformanceTestSuite()
+      : verbose_(false),
+        enforce_recommended_(false),
+        failure_list_flag_name_("--failure_list") {}
   virtual ~ConformanceTestSuite() {}
 
   void SetVerbose(bool verbose) { verbose_ = verbose; }
@@ -156,6 +160,16 @@
     enforce_recommended_ = value;
   }
 
+  // Gets the flag name to the failure list file.
+  // By default, this would return --failure_list
+  string GetFailureListFlagName() {
+    return failure_list_flag_name_;
+  }
+
+  void SetFailureListFlagName(const std::string& failure_list_flag_name) {
+    failure_list_flag_name_ = failure_list_flag_name;
+  }
+
   // Run all the conformance tests against the given test runner.
   // Test output will be stored in "output".
   //
@@ -259,6 +273,8 @@
                const conformance::ConformanceRequest& request,
                conformance::ConformanceResponse* response);
 
+  void AddExpectedFailedTest(const std::string& test_name);
+
   virtual void RunSuiteImpl() = 0;
 
   ConformanceTestRunner* runner_;
@@ -267,6 +283,7 @@
   bool verbose_;
   bool enforce_recommended_;
   std::string output_;
+  std::string failure_list_flag_name_;
   std::string failure_list_filename_;
 
   // The set of test names that are expected to fail in this run, but haven't
diff --git a/conformance/conformance_test_main.cc b/conformance/conformance_test_main.cc
new file mode 100644
index 0000000..c7ac9fc
--- /dev/null
+++ b/conformance/conformance_test_main.cc
@@ -0,0 +1,40 @@
+// 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 "binary_json_conformance_suite.h"
+#include "conformance_test.h"
+#include "text_format_conformance_suite.h"
+
+int main(int argc, char *argv[]) {
+  google::protobuf::BinaryAndJsonConformanceSuite binary_and_json_suite;
+  google::protobuf::TextFormatConformanceTestSuite text_format_suite;
+  return google::protobuf::ForkPipeRunner::Run(
+      argc, argv, {&binary_and_json_suite, &text_format_suite});
+}
diff --git a/conformance/conformance_test_runner.cc b/conformance/conformance_test_runner.cc
index 0279bb6..e7aa0a5 100644
--- a/conformance/conformance_test_runner.cc
+++ b/conformance/conformance_test_runner.cc
@@ -120,6 +120,19 @@
   fprintf(stderr,
           "                              line.  Use '#' for comments.\n");
   fprintf(stderr,
+          "  --text_format_failure_list <filename>   Use to specify list \n");
+  fprintf(stderr,
+          "                              of tests that are expected to \n");
+  fprintf(stderr,
+          "                              fail in the \n");
+  fprintf(stderr,
+          "                              text_format_conformance_suite.  \n");
+  fprintf(stderr,
+          "                              File should contain one test name \n");
+  fprintf(stderr,
+          "                              per line.  Use '#' for comments.\n");
+
+  fprintf(stderr,
           "  --enforce_recommended       Enforce that recommended test\n");
   fprintf(stderr,
           "                              cases are also passing. Specify\n");
@@ -175,41 +188,56 @@
 }
 
 int ForkPipeRunner::Run(
-    int argc, char *argv[], ConformanceTestSuite* suite) {
-  char *program;
-  string failure_list_filename;
-  conformance::FailureSet failure_list;
-
-  for (int arg = 1; arg < argc; ++arg) {
-    if (strcmp(argv[arg], "--failure_list") == 0) {
-      if (++arg == argc) UsageError();
-      failure_list_filename = argv[arg];
-      ParseFailureList(argv[arg], &failure_list);
-    } else if (strcmp(argv[arg], "--verbose") == 0) {
-      suite->SetVerbose(true);
-    } else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
-      suite->SetEnforceRecommended(true);
-    } else if (argv[arg][0] == '-') {
-      fprintf(stderr, "Unknown option: %s\n", argv[arg]);
-      UsageError();
-    } else {
-      if (arg != argc - 1) {
-        fprintf(stderr, "Too many arguments.\n");
-        UsageError();
-      }
-      program = argv[arg];
-    }
+    int argc, char *argv[], const std::vector<ConformanceTestSuite*>& suites) {
+  if (suites.empty()) {
+    fprintf(stderr, "No test suites found.\n");
+    return EXIT_FAILURE;
   }
+  bool all_ok = true;
+  for (ConformanceTestSuite* suite : suites) {
+    char *program;
+    string failure_list_filename;
+    conformance::FailureSet failure_list;
 
-  ForkPipeRunner runner(program);
+    for (int arg = 1; arg < argc; ++arg) {
+      if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) {
+        if (++arg == argc) UsageError();
+        failure_list_filename = argv[arg];
+        ParseFailureList(argv[arg], &failure_list);
+      } else if (strcmp(argv[arg], "--verbose") == 0) {
+        suite->SetVerbose(true);
+      } else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
+        suite->SetEnforceRecommended(true);
+      } else if (argv[arg][0] == '-') {
+        bool recognized_flag = false;
+        for (ConformanceTestSuite* suite : suites) {
+          if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) {
+            if (++arg == argc) UsageError();
+            recognized_flag = true;
+          }
+        }
+        if (!recognized_flag) {
+          fprintf(stderr, "Unknown option: %s\n", argv[arg]);
+          UsageError();
+        }
+      } else {
+        if (arg != argc - 1) {
+          fprintf(stderr, "Too many arguments.\n");
+          UsageError();
+        }
+        program = argv[arg];
+      }
+    }
 
-  std::string output;
-  bool ok =
-      suite->RunSuite(&runner, &output, failure_list_filename, &failure_list);
+    ForkPipeRunner runner(program);
 
-  fwrite(output.c_str(), 1, output.size(), stderr);
+    std::string output;
+    all_ok = all_ok &&
+        suite->RunSuite(&runner, &output, failure_list_filename, &failure_list);
 
-  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
+    fwrite(output.c_str(), 1, output.size(), stderr);
+  }
+  return all_ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 // TODO(haberman): make this work on Windows, instead of using these
diff --git a/conformance/failure_list_python.txt b/conformance/failure_list_python.txt
index ce7cdec..e3ce7af 100644
--- a/conformance/failure_list_python.txt
+++ b/conformance/failure_list_python.txt
@@ -19,4 +19,3 @@
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
-Required.Proto3.JsonInput.EmptyFieldMask.ProtobufOutput
diff --git a/conformance/failure_list_python_cpp.txt b/conformance/failure_list_python_cpp.txt
index 4531946..59a969d 100644
--- a/conformance/failure_list_python_cpp.txt
+++ b/conformance/failure_list_python_cpp.txt
@@ -20,4 +20,3 @@
 Required.Proto3.JsonInput.FloatFieldTooSmall
 Required.Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
 Required.Proto3.JsonInput.TimestampJsonInputLowercaseT
-Required.Proto3.JsonInput.EmptyFieldMask.ProtobufOutput
diff --git a/conformance/text_format_conformance_suite.cc b/conformance/text_format_conformance_suite.cc
new file mode 100644
index 0000000..4483ffb
--- /dev/null
+++ b/conformance/text_format_conformance_suite.cc
@@ -0,0 +1,240 @@
+// 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 "text_format_conformance_suite.h"
+
+#include "conformance_test.h"
+
+#include <google/protobuf/any.pb.h>
+#include <google/protobuf/test_messages_proto2.pb.h>
+#include <google/protobuf/test_messages_proto3.pb.h>
+#include <google/protobuf/text_format.h>
+
+using conformance::ConformanceRequest;
+using conformance::ConformanceResponse;
+using conformance::WireFormat;
+using google::protobuf::Message;
+using google::protobuf::TextFormat;
+using protobuf_test_messages::proto2::TestAllTypesProto2;
+using protobuf_test_messages::proto3::TestAllTypesProto3;
+using std::string;
+
+namespace google {
+namespace protobuf {
+
+TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() {
+  SetFailureListFlagName("--text_format_failure_list");
+}
+
+bool TextFormatConformanceTestSuite::ParseTextFormatResponse(
+    const ConformanceResponse& response, Message* test_message) {
+  if (!TextFormat::ParseFromString(response.text_payload(), test_message)) {
+    GOOGLE_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode "
+                      << "yielded unparseable proto. Text payload: "
+                      << response.text_payload();
+    return false;
+  }
+
+  return true;
+}
+
+bool TextFormatConformanceTestSuite::ParseResponse(
+    const ConformanceResponse& response,
+    const ConformanceRequestSetting& setting, Message* test_message) {
+  const ConformanceRequest& request = setting.GetRequest();
+  WireFormat requested_output = request.requested_output_format();
+  const string& test_name = setting.GetTestName();
+  ConformanceLevel level = setting.GetLevel();
+
+  switch (response.result_case()) {
+    case ConformanceResponse::kProtobufPayload: {
+      if (requested_output != conformance::PROTOBUF) {
+        ReportFailure(
+            test_name, level, request, response,
+            StrCat("Test was asked for ", WireFormatToString(requested_output),
+                   " output but provided PROTOBUF instead.")
+                .c_str());
+        return false;
+      }
+
+      if (!test_message->ParseFromString(response.protobuf_payload())) {
+        ReportFailure(test_name, level, request, response,
+                      "Protobuf output we received from test was unparseable.");
+        return false;
+      }
+
+      break;
+    }
+
+    case ConformanceResponse::kTextPayload: {
+      if (requested_output != conformance::TEXT_FORMAT) {
+        ReportFailure(
+            test_name, level, request, response,
+            StrCat("Test was asked for ", WireFormatToString(requested_output),
+                   " output but provided TEXT_FORMAT instead.")
+                .c_str());
+        return false;
+      }
+
+      if (!ParseTextFormatResponse(response, test_message)) {
+        ReportFailure(
+            test_name, level, request, response,
+            "TEXT_FORMAT output we received from test was unparseable.");
+        return false;
+      }
+
+      break;
+    }
+
+    default:
+      GOOGLE_LOG(FATAL) << test_name
+                        << ": unknown payload type: " << response.result_case();
+  }
+
+  return true;
+}
+
+void TextFormatConformanceTestSuite::ExpectParseFailure(const string& test_name,
+                                                        ConformanceLevel level,
+                                                        const string& input) {
+  TestAllTypesProto3 prototype;
+  // We don't expect output, but if the program erroneously accepts the protobuf
+  // we let it send its response as this.  We must not leave it unspecified.
+  ConformanceRequestSetting setting(
+      level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
+      conformance::TEXT_FORMAT_TEST, prototype, test_name, input);
+  const ConformanceRequest& request = setting.GetRequest();
+  ConformanceResponse response;
+  string effective_test_name = StrCat(setting.ConformanceLevelToString(level),
+                                      ".Proto3.TextFormatInput.", test_name);
+
+  RunTest(effective_test_name, request, &response);
+  if (response.result_case() == ConformanceResponse::kParseError) {
+    ReportSuccess(effective_test_name);
+  } else if (response.result_case() == ConformanceResponse::kSkipped) {
+    ReportSkip(effective_test_name, request, response);
+  } else {
+    ReportFailure(effective_test_name, level, request, response,
+                  "Should have failed to parse, but didn't.");
+  }
+}
+
+void TextFormatConformanceTestSuite::RunValidTextFormatTest(
+    const string& test_name, ConformanceLevel level, const string& input_text) {
+  TestAllTypesProto3 prototype;
+  RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
+}
+
+void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2(
+    const string& test_name, ConformanceLevel level, const string& input_text) {
+  TestAllTypesProto2 prototype;
+  RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
+}
+
+void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
+    const string& test_name, ConformanceLevel level, const string& input_text,
+    const Message& prototype) {
+  ConformanceRequestSetting setting1(
+      level, conformance::TEXT_FORMAT, conformance::PROTOBUF,
+      conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
+  RunValidInputTest(setting1, input_text);
+  ConformanceRequestSetting setting2(
+      level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
+      conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
+  RunValidInputTest(setting2, input_text);
+}
+
+void TextFormatConformanceTestSuite::RunSuiteImpl() {
+  RunValidTextFormatTest("HelloWorld", REQUIRED,
+                         "optional_string: 'Hello, World!'");
+  // Integer fields.
+  RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED,
+                         "optional_int32: 2147483647");
+  RunValidTextFormatTest("Int32FieldMinValue", REQUIRED,
+                         "optional_int32: -2147483648");
+  RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED,
+                         "optional_uint32: 4294967295");
+  RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED,
+                         "optional_int64: 9223372036854775807");
+  RunValidTextFormatTest("Int64FieldMinValue", REQUIRED,
+                         "optional_int64: -9223372036854775808");
+  RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
+                         "optional_uint64: 18446744073709551615");
+
+  // Parsers reject out-of-bound integer values.
+  ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
+                     "optional_int32: 2147483648");
+  ExpectParseFailure("Int32FieldTooSmall", REQUIRED,
+                     "optional_int32: -2147483649");
+  ExpectParseFailure("Uint32FieldTooLarge", REQUIRED,
+                     "optional_uint32: 4294967296");
+  ExpectParseFailure("Int64FieldTooLarge", REQUIRED,
+                     "optional_int64: 9223372036854775808");
+  ExpectParseFailure("Int64FieldTooSmall", REQUIRED,
+                     "optional_int64: -9223372036854775809");
+  ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
+                     "optional_uint64: 18446744073709551616");
+
+  // Floating point fields
+  RunValidTextFormatTest("FloatField", REQUIRED,
+                         "optional_float: 3.192837");
+  RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
+                         "optional_float: 3.123456789123456789");
+  RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
+                         "optional_float: 3.40282e+38");
+  RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
+                         "optional_float: 1.17549e-38");
+  RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED,
+                         "optional_float: NaN");
+  RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
+                         "optional_float: inf");
+  RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
+                         "optional_float: -inf");
+  RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
+                         "optional_float: 4294967296");
+  RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
+                         "optional_float: 9223372036854775808");
+
+  ExpectParseFailure("FloatFieldTooLarge", REQUIRED,
+                     "optional_int32: 3.4028235e+39");
+  ExpectParseFailure("FloatFieldTooSmall", REQUIRED,
+                     "optional_int32: 1.17549e-39");
+
+  // Group fields
+  RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
+                               "Data { group_int32: 1 }");
+  RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
+                               "Data: { group_int32: 1 }");
+  RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
+                               "Data {}");
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/conformance/text_format_conformance_suite.h b/conformance/text_format_conformance_suite.h
new file mode 100644
index 0000000..661d45e
--- /dev/null
+++ b/conformance/text_format_conformance_suite.h
@@ -0,0 +1,66 @@
+// 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 TEXT_FORMAT_CONFORMANCE_SUITE_H_
+#define TEXT_FORMAT_CONFORMANCE_SUITE_H_
+
+#include "conformance_test.h"
+
+namespace google {
+namespace protobuf {
+
+class TextFormatConformanceTestSuite : public ConformanceTestSuite {
+ public:
+  TextFormatConformanceTestSuite();
+
+ private:
+  void RunSuiteImpl();
+  void RunValidTextFormatTest(const string& test_name, ConformanceLevel level,
+                              const string& input);
+  void RunValidTextFormatTestProto2(const string& test_name,
+                                    ConformanceLevel level,
+                                    const string& input);
+  void RunValidTextFormatTestWithMessage(const string& test_name,
+                                         ConformanceLevel level,
+                                         const string& input_text,
+                                         const Message& prototype);
+  void ExpectParseFailure(const string& test_name, ConformanceLevel level,
+                          const string& input);
+  bool ParseTextFormatResponse(const conformance::ConformanceResponse& response,
+                               Message* test_message);
+  bool ParseResponse(const conformance::ConformanceResponse& response,
+                     const ConformanceRequestSetting& setting,
+                     Message* test_message) override;
+};
+
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // TEXT_FORMAT_CONFORMANCE_SUITE_H_
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 ec48796..6cece05 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -3006,7 +3006,39 @@
         throw InvalidProtocolBufferException.truncatedMessage();
       }
 
-      if (refillCallback != null) {
+      int totalSkipped = 0;
+      if (refillCallback == null) {
+        // Skipping more bytes than are in the buffer.  First skip what we have.
+        totalBytesRetired += pos;
+        totalSkipped = bufferSize - pos;
+        bufferSize = 0;
+        pos = 0;
+
+        try {
+          while (totalSkipped < size) {
+            int toSkip = size - totalSkipped;
+            long skipped = input.skip(toSkip);
+            if (skipped < 0 || skipped > toSkip) {
+              throw new IllegalStateException(
+                  input.getClass()
+                      + "#skip returned invalid result: "
+                      + skipped
+                      + "\nThe InputStream implementation is buggy.");
+            } else if (skipped == 0) {
+              // The API contract of skip() permits an inputstream to skip zero bytes for any reason
+              // it wants. In particular, ByteArrayInputStream will just return zero over and over
+              // when it's at the end of its input. In order to actually confirm that we've hit the
+              // end of input, we need to issue a read call via the other path.
+              break;
+            }
+            totalSkipped += (int) skipped;
+          }
+        } finally {
+          totalBytesRetired += totalSkipped;
+          recomputeBufferSizeAfterLimit();
+        }
+      }
+      if (totalSkipped < size) {
         // Skipping more bytes than are in the buffer.  First skip what we have.
         int tempPos = bufferSize - pos;
         pos = bufferSize;
@@ -3021,30 +3053,6 @@
         }
 
         pos = size - tempPos;
-      } else {
-        // Skipping more bytes than are in the buffer.  First skip what we have.
-        totalBytesRetired += pos;
-        int totalSkipped = bufferSize - pos;
-        bufferSize = 0;
-        pos = 0;
-
-        try {
-          while (totalSkipped < size) {
-            int toSkip = size - totalSkipped;
-            long skipped = input.skip(toSkip);
-            if (skipped < 0 || skipped > toSkip) {
-              throw new IllegalStateException(
-                  input.getClass()
-                      + "#skip returned invalid result: "
-                      + skipped
-                      + "\nThe InputStream implementation is buggy.");
-            }
-            totalSkipped += (int) skipped;
-          }
-        } finally {
-          totalBytesRetired += totalSkipped;
-          recomputeBufferSizeAfterLimit();
-        }
       }
     }
   }
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 6f8696e..8b7e1cc 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -185,8 +185,9 @@
       if (name.indexOf('.') != -1) {
         return null;
       }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
+      final String packageName = getPackage();
+      if (!packageName.isEmpty()) {
+        name = packageName + '.' + name;
       }
       final GenericDescriptor result = pool.findSymbol(name);
       if (result != null && result instanceof Descriptor && result.getFile() == this) {
@@ -208,8 +209,9 @@
       if (name.indexOf('.') != -1) {
         return null;
       }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
+      final String packageName = getPackage();
+      if (!packageName.isEmpty()) {
+        name = packageName + '.' + name;
       }
       final GenericDescriptor result = pool.findSymbol(name);
       if (result != null && result instanceof EnumDescriptor && result.getFile() == this) {
@@ -231,8 +233,9 @@
       if (name.indexOf('.') != -1) {
         return null;
       }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
+      final String packageName = getPackage();
+      if (!packageName.isEmpty()) {
+        name = packageName + '.' + name;
       }
       final GenericDescriptor result = pool.findSymbol(name);
       if (result != null && result instanceof ServiceDescriptor && result.getFile() == this) {
@@ -252,8 +255,9 @@
       if (name.indexOf('.') != -1) {
         return null;
       }
-      if (getPackage().length() > 0) {
-        name = getPackage() + '.' + name;
+      final String packageName = getPackage();
+      if (!packageName.isEmpty()) {
+        name = packageName + '.' + name;
       }
       final GenericDescriptor result = pool.findSymbol(name);
       if (result != null && result instanceof FieldDescriptor && result.getFile() == this) {
@@ -1223,14 +1227,20 @@
     // This method should match exactly with the ToJsonName() function in C++
     // descriptor.cc.
     private static String fieldNameToJsonName(String name) {
-      StringBuilder result = new StringBuilder(name.length());
+      final int length = name.length();
+      StringBuilder result = new StringBuilder(length);
       boolean isNextUpperCase = false;
-      for (int i = 0; i < name.length(); i++) {
+      for (int i = 0; i < length; i++) {
         char ch = name.charAt(i);
         if (ch == '_') {
           isNextUpperCase = true;
         } else if (isNextUpperCase) {
-          result.append(Character.toUpperCase(ch));
+          // This closely matches the logic for ASCII characters in:
+          // http://google3/google/protobuf/descriptor.cc?l=249-251&rcl=228891689
+          if ('a' <= ch && ch <= 'z') {
+            ch = (char) (ch - 'a' + 'A');
+          }
+          result.append(ch);
           isNextUpperCase = false;
         } else {
           result.append(ch);
@@ -1787,7 +1797,6 @@
       file.pool.addEnumValueByNumber(this);
     }
 
-    private Integer number;
     // Create an unknown enum value.
     private EnumValueDescriptor(
         final FileDescriptor file, final EnumDescriptor parent, final Integer number) {
@@ -1799,7 +1808,6 @@
       this.file = file;
       this.type = parent;
       this.fullName = parent.getFullName() + '.' + proto.getName();
-      this.number = number;
 
       // Don't add this descriptor into pool.
     }
@@ -2029,11 +2037,14 @@
       final FileDescriptor file, final Descriptor parent, final String name) {
     if (parent != null) {
       return parent.getFullName() + '.' + name;
-    } else if (file.getPackage().length() > 0) {
-      return file.getPackage() + '.' + name;
-    } else {
-      return name;
     }
+
+    final String packageName = file.getPackage();
+    if (!packageName.isEmpty()) {
+      return packageName + '.' + name;
+    }
+
+    return name;
   }
 
   // =================================================================
@@ -2322,13 +2333,13 @@
       validateSymbolName(descriptor);
 
       final String fullName = descriptor.getFullName();
-      final int dotpos = fullName.lastIndexOf('.');
 
       final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
       if (old != null) {
         descriptorsByName.put(fullName, old);
 
         if (descriptor.getFile() == old.getFile()) {
+          final int dotpos = fullName.lastIndexOf('.');
           if (dotpos == -1) {
             throw new DescriptorValidationException(
                 descriptor, '\"' + fullName + "\" is already defined.");
@@ -2494,27 +2505,22 @@
       final String name = descriptor.getName();
       if (name.length() == 0) {
         throw new DescriptorValidationException(descriptor, "Missing name.");
-      } else {
-        boolean valid = true;
-        for (int i = 0; i < name.length(); i++) {
-          final char c = name.charAt(i);
-          // Non-ASCII characters are not valid in protobuf identifiers, even
-          // if they are letters or digits.
-          if (c >= 128) {
-            valid = false;
-          }
-          // First character must be letter or _.  Subsequent characters may
-          // be letters, numbers, or digits.
-          if (Character.isLetter(c) || c == '_' || (Character.isDigit(c) && i > 0)) {
-            // Valid
-          } else {
-            valid = false;
-          }
+      }
+
+      // Non-ASCII characters are not valid in protobuf identifiers, even
+      // if they are letters or digits.
+      // The first character must be a letter or '_'.
+      // Subsequent characters may be letters, numbers, or digits.
+      for (int i = 0; i < name.length(); i++) {
+        final char c = name.charAt(i);
+        if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
+          || (c == '_')
+          || ('0' <= c && c <= '9' && i > 0)) {
+          // Valid
+          continue;
         }
-        if (!valid) {
-          throw new DescriptorValidationException(
-              descriptor, '\"' + name + "\" is not a valid identifier.");
-        }
+        throw new DescriptorValidationException(
+            descriptor, '\"' + name + "\" is not a valid identifier.");
       }
     }
   }
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 998f4d5..9c5d6da 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -1186,4 +1186,13 @@
       }
     }
   }
+
+  public void testSkipPastEndOfByteArrayInput() throws Exception {
+    try {
+      CodedInputStream.newInstance(new ByteArrayInputStream(new byte[100])).skipRawBytes(101);
+      fail();
+    } catch (InvalidProtocolBufferException e) {
+      // Expected
+    }
+  }
 }
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 20b9380..4e63ee7 100644
--- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java
@@ -217,6 +217,23 @@
   }
 
   @Test
+  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.writeTag(DescriptorProto.ENUM_TYPE_FIELD_NUMBER, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    cos.writeRawVarint32(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
+    ByteArrayInputStream bais = new ByteArrayInputStream(body);
+    try {
+      DescriptorProto.parseDelimitedFrom(bais);
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+    }
+  }
+
+  @Test
   public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() {
     setupDelimited();
     verifyExceptions(
diff --git a/js/binary/writer.js b/js/binary/writer.js
index 287d29c..ae1c29b 100644
--- a/js/binary/writer.js
+++ b/js/binary/writer.js
@@ -800,6 +800,38 @@
 
 
 /**
+ * Writes a message set extension to the buffer.
+ * @param {number} field The field number for the extension.
+ * @param {?MessageType} value The extension message object to write. Note that
+ *     message set can only have extensions with type of optional message.
+ * @param {function(!MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
+ *     Will be invoked with the value to write and the writer to write it with.
+ * @template MessageType
+ * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
+ * the null in blah|null with none.  This is necessary because the compiler will
+ * infer MessageType to be nullable if the value parameter is nullable.
+ * @template MessageTypeNonNull :=
+ *     cond(isUnknown(MessageType), unknown(),
+ *       mapunion(MessageType, (X) =>
+ *         cond(eq(X, 'null'), none(), X)))
+ * =:
+ */
+jspb.BinaryWriter.prototype.writeMessageSet = function(
+    field, value, writerCallback) {
+  if (value == null) return;
+  // The wire format for a message set is defined by
+  // google3/net/proto/message_set.proto
+  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.START_GROUP);
+  this.writeFieldHeader_(2, jspb.BinaryConstants.WireType.VARINT);
+  this.encoder_.writeSignedVarint32(field);
+  var bookmark = this.beginDelimited_(3);
+  writerCallback(value, this);
+  this.endDelimited_(bookmark);
+  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.END_GROUP);
+};
+
+
+/**
  * Writes a group message to the buffer.
  *
  * @param {number} field The field number.
diff --git a/js/message.js b/js/message.js
index 1ca9fac..eb54678 100644
--- a/js/message.js
+++ b/js/message.js
@@ -183,9 +183,6 @@
  *     calling fromObject. Enabling this might disable the JSCompiler's ability
  *     to dead code eliminate fields used in protocol buffers that are never
  *     used in an application.
- *     NOTE: By default no protos actually have a fromObject method. You need to
- *     add the jspb.generate_from_object options to the proto definition to
- *     activate the feature.
  *     By default this is enabled for test code only.
  */
 goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
@@ -703,20 +700,7 @@
  * @protected
  */
 jspb.Message.getRepeatedField = function(msg, fieldNumber) {
-  if (fieldNumber < msg.pivot_) {
-    var index = jspb.Message.getIndex_(msg, fieldNumber);
-    var val = msg.array[index];
-    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
-      return msg.array[index] = [];
-    }
-    return val;
-  }
-
-  var val = msg.extensionObject_[fieldNumber];
-  if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
-    return msg.extensionObject_[fieldNumber] = [];
-  }
-  return val;
+  return /** @type {!Array} */ (jspb.Message.getField(msg, fieldNumber));
 };
 
 
diff --git a/js/test.proto b/js/test.proto
index bc1a9b6..1c0d255 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -106,6 +106,13 @@
   }
 }
 
+message MineField {
+  // document.cookie is a banned property in a couple of conformance check
+  // configs at Google. Verify that having a field called cookie doesn't confuse
+  // the compiler and break the build.
+  optional string cookie = 1;
+}
+
 message IsExtension {
   extend HasExtensions {
     optional IsExtension ext_field = 100;
@@ -261,7 +268,6 @@
 }
 
 message TestMapFieldsNoBinary {
-
   map<string, string> map_string_string = 1;
   map<string, int32> map_string_int32 = 2;
   map<string, int64> map_string_int64 = 3;
@@ -285,7 +291,6 @@
 }
 
 message MapValueMessageNoBinary {
-
   optional int32 foo = 1;
 }
 
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index b82936b..9b968e7 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -230,6 +230,8 @@
       kwargs['cmp'] = kwargs.pop('sort_function')
     self._values.sort(*args, **kwargs)
 
+collections_abc.MutableSequence.register(BaseContainer)
+
 
 class RepeatedScalarFieldContainer(BaseContainer):
 
@@ -341,8 +343,6 @@
     # We are presumably comparing against some other sequence type.
     return other == self._values
 
-collections_abc.MutableSequence.register(BaseContainer)
-
 
 class RepeatedCompositeFieldContainer(BaseContainer):
 
@@ -380,6 +380,24 @@
       self._message_listener.Modified()
     return new_element
 
+  def append(self, value):
+    """Appends one element by copying the message."""
+    new_element = self._message_descriptor._concrete_class()
+    new_element._SetListener(self._message_listener)
+    new_element.CopyFrom(value)
+    self._values.append(new_element)
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
+  def insert(self, key, value):
+    """Inserts the item at the specified position by copying."""
+    new_element = self._message_descriptor._concrete_class()
+    new_element._SetListener(self._message_listener)
+    new_element.CopyFrom(value)
+    self._values.insert(key, new_element)
+    if not self._message_listener.dirty:
+      self._message_listener.Modified()
+
   def extend(self, elem_seq):
     """Extends by appending the given sequence of elements of the same type
     as this one, copying each individual message.
diff --git a/python/google/protobuf/internal/extension_dict.py b/python/google/protobuf/internal/extension_dict.py
new file mode 100644
index 0000000..4a1399d
--- /dev/null
+++ b/python/google/protobuf/internal/extension_dict.py
@@ -0,0 +1,185 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc.  All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Contains _ExtensionDict class to represent extensions.
+"""
+
+from google.protobuf.internal import type_checkers
+from google.protobuf.descriptor import FieldDescriptor
+
+
+def _VerifyExtensionHandle(message, extension_handle):
+  """Verify that the given extension handle is valid."""
+
+  if not isinstance(extension_handle, FieldDescriptor):
+    raise KeyError('HasExtension() expects an extension handle, got: %s' %
+                   extension_handle)
+
+  if not extension_handle.is_extension:
+    raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
+
+  if not extension_handle.containing_type:
+    raise KeyError('"%s" is missing a containing_type.'
+                   % extension_handle.full_name)
+
+  if extension_handle.containing_type is not message.DESCRIPTOR:
+    raise KeyError('Extension "%s" extends message type "%s", but this '
+                   'message is of type "%s".' %
+                   (extension_handle.full_name,
+                    extension_handle.containing_type.full_name,
+                    message.DESCRIPTOR.full_name))
+
+
+# TODO(robinson): Unify error handling of "unknown extension" crap.
+# TODO(robinson): Support iteritems()-style iteration over all
+# extensions with the "has" bits turned on?
+class _ExtensionDict(object):
+
+  """Dict-like container for Extension fields on proto instances.
+
+  Note that in all cases we expect extension handles to be
+  FieldDescriptors.
+  """
+
+  def __init__(self, extended_message):
+    """
+    Args:
+      extended_message: Message instance for which we are the Extensions dict.
+    """
+    self._extended_message = extended_message
+
+  def __getitem__(self, extension_handle):
+    """Returns the current value of the given extension handle."""
+
+    _VerifyExtensionHandle(self._extended_message, extension_handle)
+
+    result = self._extended_message._fields.get(extension_handle)
+    if result is not None:
+      return result
+
+    if extension_handle.label == FieldDescriptor.LABEL_REPEATED:
+      result = extension_handle._default_constructor(self._extended_message)
+    elif extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
+      assert getattr(extension_handle.message_type, '_concrete_class', None), (
+          'Uninitialized concrete class found for field %r (message type %r)'
+          % (extension_handle.full_name,
+             extension_handle.message_type.full_name))
+      result = extension_handle.message_type._concrete_class()
+      try:
+        result._SetListener(self._extended_message._listener_for_children)
+      except ReferenceError:
+        pass
+    else:
+      # Singular scalar -- just return the default without inserting into the
+      # dict.
+      return extension_handle.default_value
+
+    # Atomically check if another thread has preempted us and, if not, swap
+    # in the new object we just created.  If someone has preempted us, we
+    # take that object and discard ours.
+    # WARNING:  We are relying on setdefault() being atomic.  This is true
+    #   in CPython but we haven't investigated others.  This warning appears
+    #   in several other locations in this file.
+    result = self._extended_message._fields.setdefault(
+        extension_handle, result)
+
+    return result
+
+  def __eq__(self, other):
+    if not isinstance(other, self.__class__):
+      return False
+
+    my_fields = self._extended_message.ListFields()
+    other_fields = other._extended_message.ListFields()
+
+    # Get rid of non-extension fields.
+    my_fields = [field for field in my_fields if field.is_extension]
+    other_fields = [field for field in other_fields if field.is_extension]
+
+    return my_fields == other_fields
+
+  def __ne__(self, other):
+    return not self == other
+
+  def __len__(self):
+    fields = self._extended_message.ListFields()
+    # Get rid of non-extension fields.
+    extension_fields = [field for field in fields if field[0].is_extension]
+    return len(extension_fields)
+
+  def __hash__(self):
+    raise TypeError('unhashable object')
+
+  # Note that this is only meaningful for non-repeated, scalar extension
+  # fields.  Note also that we may have to call _Modified() when we do
+  # successfully set a field this way, to set any necssary "has" bits in the
+  # ancestors of the extended message.
+  def __setitem__(self, extension_handle, value):
+    """If extension_handle specifies a non-repeated, scalar extension
+    field, sets the value of that field.
+    """
+
+    _VerifyExtensionHandle(self._extended_message, extension_handle)
+
+    if (extension_handle.label == FieldDescriptor.LABEL_REPEATED or
+        extension_handle.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE):
+      raise TypeError(
+          'Cannot assign to extension "%s" because it is a repeated or '
+          'composite type.' % extension_handle.full_name)
+
+    # It's slightly wasteful to lookup the type checker each time,
+    # but we expect this to be a vanishingly uncommon case anyway.
+    type_checker = type_checkers.GetTypeChecker(extension_handle)
+    # pylint: disable=protected-access
+    self._extended_message._fields[extension_handle] = (
+        type_checker.CheckValue(value))
+    self._extended_message._Modified()
+
+  def _FindExtensionByName(self, name):
+    """Tries to find a known extension with the specified name.
+
+    Args:
+      name: Extension full name.
+
+    Returns:
+      Extension field descriptor.
+    """
+    return self._extended_message._extensions_by_name.get(name, None)
+
+  def _FindExtensionByNumber(self, number):
+    """Tries to find a known extension with the field number.
+
+    Args:
+      number: Extension field number.
+
+    Returns:
+      Extension field descriptor.
+    """
+    return self._extended_message._extensions_by_number.get(number, None)
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 0f5b630..2695635 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -52,7 +52,6 @@
 from google.protobuf import any_test_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
-from google.protobuf.internal import well_known_types
 from google.protobuf import descriptor_pool
 from google.protobuf import json_format
 from google.protobuf.util import json_format_proto3_pb2
@@ -481,6 +480,14 @@
     parsed_message = json_format_proto3_pb2.TestFieldMask()
     self.CheckParseBack(message, parsed_message)
 
+    message.value.Clear()
+    self.assertEqual(
+        json_format.MessageToJson(message, True),
+        '{\n'
+        '  "value": ""\n'
+        '}')
+    self.CheckParseBack(message, parsed_message)
+
   def testWrapperMessage(self):
     message = json_format_proto3_pb2.TestWrapper()
     message.bool_value.value = False
@@ -922,17 +929,18 @@
     text = '{"value": "10000-01-01T00:00:00.00Z"}'
     self.assertRaisesRegexp(
         json_format.ParseError,
+        'Failed to parse value field: '
         'time data \'10000-01-01T00:00:00\' does not match'
         ' format \'%Y-%m-%dT%H:%M:%S\'.',
         json_format.Parse, text, message)
     text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        json_format.ParseError,
         'nanos 0123456789012 more than 9 fractional digits.',
         json_format.Parse, text, message)
     text = '{"value": "1972-01-01T01:00:00.01+08"}'
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        json_format.ParseError,
         (r'Invalid timezone offset value: \+08.'),
         json_format.Parse, text, message)
     # Time smaller than minimum time.
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index b97e3f6..5be65c7 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -136,13 +136,14 @@
           'google.protobuf.python.internal.Factory2Message.one_more_field')
       ext2 = msg1.Extensions._FindExtensionByName(
           'google.protobuf.python.internal.another_field')
+      self.assertEqual(0, len(msg1.Extensions))
       msg1.Extensions[ext1] = 'test1'
       msg1.Extensions[ext2] = 'test2'
       self.assertEqual('test1', msg1.Extensions[ext1])
       self.assertEqual('test2', msg1.Extensions[ext2])
       self.assertEqual(None,
                        msg1.Extensions._FindExtensionByNumber(12321))
-      self.assertRaises(TypeError, len, msg1.Extensions)
+      self.assertEqual(2, len(msg1.Extensions))
       if api_implementation.Type() == 'cpp':
         self.assertRaises(TypeError,
                           msg1.Extensions._FindExtensionByName, 0)
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 137420d..80a65e3 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -411,6 +411,58 @@
     empty.ParseFromString(populated.SerializeToString())
     self.assertEqual(str(empty), '')
 
+  def testAppendRepeatedCompositeField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.append(
+        message_module.TestAllTypes.NestedMessage(bb=1))
+    nested = message_module.TestAllTypes.NestedMessage(bb=2)
+    msg.repeated_nested_message.append(nested)
+    try:
+      msg.repeated_nested_message.append(1)
+    except TypeError:
+      pass
+    self.assertEqual(2, len(msg.repeated_nested_message))
+    self.assertEqual([1, 2],
+                     [m.bb for m in msg.repeated_nested_message])
+
+  def testInsertRepeatedCompositeField(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_nested_message.insert(
+        -1, message_module.TestAllTypes.NestedMessage(bb=1))
+    sub_msg = msg.repeated_nested_message[0]
+    msg.repeated_nested_message.insert(
+        0, message_module.TestAllTypes.NestedMessage(bb=2))
+    msg.repeated_nested_message.insert(
+        99, message_module.TestAllTypes.NestedMessage(bb=3))
+    msg.repeated_nested_message.insert(
+        -2, message_module.TestAllTypes.NestedMessage(bb=-1))
+    msg.repeated_nested_message.insert(
+        -1000, message_module.TestAllTypes.NestedMessage(bb=-1000))
+    try:
+      msg.repeated_nested_message.insert(1, 999)
+    except TypeError:
+      pass
+    self.assertEqual(5, len(msg.repeated_nested_message))
+    self.assertEqual([-1000, 2, -1, 1, 3],
+                     [m.bb for m in msg.repeated_nested_message])
+    self.assertEqual(str(msg),
+                     'repeated_nested_message {\n'
+                     '  bb: -1000\n'
+                     '}\n'
+                     'repeated_nested_message {\n'
+                     '  bb: 2\n'
+                     '}\n'
+                     'repeated_nested_message {\n'
+                     '  bb: -1\n'
+                     '}\n'
+                     'repeated_nested_message {\n'
+                     '  bb: 1\n'
+                     '}\n'
+                     'repeated_nested_message {\n'
+                     '  bb: 3\n'
+                     '}\n')
+    self.assertEqual(sub_msg.bb, 1)
+
   def testMergeFromRepeatedField(self, message_module):
     msg = message_module.TestAllTypes()
     msg.repeated_int32.append(1)
@@ -442,6 +494,30 @@
       pass
     self.assertEqual(len(msg.repeated_nested_message), 0)
 
+  def testRepeatedContains(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    self.assertIn(2, msg.repeated_int32)
+    self.assertNotIn(0, msg.repeated_int32)
+
+    msg.repeated_nested_message.add(bb=1)
+    sub_msg1 = msg.repeated_nested_message[0]
+    sub_msg2 = message_module.TestAllTypes.NestedMessage(bb=2)
+    sub_msg3 = message_module.TestAllTypes.NestedMessage(bb=3)
+    msg.repeated_nested_message.append(sub_msg2)
+    msg.repeated_nested_message.insert(0, sub_msg3)
+    self.assertIn(sub_msg1, msg.repeated_nested_message)
+    self.assertIn(sub_msg2, msg.repeated_nested_message)
+    self.assertIn(sub_msg3, msg.repeated_nested_message)
+
+  def testRepeatedScalarIterable(self, message_module):
+    msg = message_module.TestAllTypes()
+    msg.repeated_int32.extend([1, 2, 3])
+    add = 0
+    for item in msg.repeated_int32:
+      add += item
+    self.assertEqual(add, 6)
+
   def testRepeatedNestedFieldIteration(self, message_module):
     msg = message_module.TestAllTypes()
     msg.repeated_nested_message.add(bb=1)
@@ -1173,6 +1249,27 @@
     with self.assertRaises(AttributeError):
       m.repeated_int32 = []
 
+  def testReturningType(self, message_module):
+    m = message_module.TestAllTypes()
+    self.assertEqual(float, type(m.optional_float))
+    self.assertEqual(float, type(m.optional_double))
+    self.assertEqual(bool, type(m.optional_bool))
+    m.optional_float = 1
+    m.optional_double = 1
+    m.optional_bool = 1
+    m.repeated_float.append(1)
+    m.repeated_double.append(1)
+    m.repeated_bool.append(1)
+    m.ParseFromString(m.SerializeToString())
+    self.assertEqual(float, type(m.optional_float))
+    self.assertEqual(float, type(m.optional_double))
+    self.assertEqual('1.0', str(m.optional_double))
+    self.assertEqual(bool, type(m.optional_bool))
+    self.assertEqual(float, type(m.repeated_float[0]))
+    self.assertEqual(float, type(m.repeated_double[0]))
+    self.assertEqual(bool, type(m.repeated_bool[0]))
+    self.assertEqual(True, m.repeated_bool[0])
+
 
 # Class to test proto2-only features (required, extensions, etc.)
 class Proto2Test(BaseTestCase):
diff --git a/python/google/protobuf/internal/more_messages.proto b/python/google/protobuf/internal/more_messages.proto
index 2c6ab9e..612f029 100644
--- a/python/google/protobuf/internal/more_messages.proto
+++ b/python/google/protobuf/internal/more_messages.proto
@@ -50,3 +50,262 @@
   optional   uint64 optional_uint64   =  4;
   optional    int64 optional_int64    =  2;
 }
+
+message LotsNestedMessage {
+  message B0 {}
+  message B1 {}
+  message B2 {}
+  message B3 {}
+  message B4 {}
+  message B5 {}
+  message B6 {}
+  message B7 {}
+  message B8 {}
+  message B9 {}
+  message B10 {}
+  message B11 {}
+  message B12 {}
+  message B13 {}
+  message B14 {}
+  message B15 {}
+  message B16 {}
+  message B17 {}
+  message B18 {}
+  message B19 {}
+  message B20 {}
+  message B21 {}
+  message B22 {}
+  message B23 {}
+  message B24 {}
+  message B25 {}
+  message B26 {}
+  message B27 {}
+  message B28 {}
+  message B29 {}
+  message B30 {}
+  message B31 {}
+  message B32 {}
+  message B33 {}
+  message B34 {}
+  message B35 {}
+  message B36 {}
+  message B37 {}
+  message B38 {}
+  message B39 {}
+  message B40 {}
+  message B41 {}
+  message B42 {}
+  message B43 {}
+  message B44 {}
+  message B45 {}
+  message B46 {}
+  message B47 {}
+  message B48 {}
+  message B49 {}
+  message B50 {}
+  message B51 {}
+  message B52 {}
+  message B53 {}
+  message B54 {}
+  message B55 {}
+  message B56 {}
+  message B57 {}
+  message B58 {}
+  message B59 {}
+  message B60 {}
+  message B61 {}
+  message B62 {}
+  message B63 {}
+  message B64 {}
+  message B65 {}
+  message B66 {}
+  message B67 {}
+  message B68 {}
+  message B69 {}
+  message B70 {}
+  message B71 {}
+  message B72 {}
+  message B73 {}
+  message B74 {}
+  message B75 {}
+  message B76 {}
+  message B77 {}
+  message B78 {}
+  message B79 {}
+  message B80 {}
+  message B81 {}
+  message B82 {}
+  message B83 {}
+  message B84 {}
+  message B85 {}
+  message B86 {}
+  message B87 {}
+  message B88 {}
+  message B89 {}
+  message B90 {}
+  message B91 {}
+  message B92 {}
+  message B93 {}
+  message B94 {}
+  message B95 {}
+  message B96 {}
+  message B97 {}
+  message B98 {}
+  message B99 {}
+  message B100 {}
+  message B101 {}
+  message B102 {}
+  message B103 {}
+  message B104 {}
+  message B105 {}
+  message B106 {}
+  message B107 {}
+  message B108 {}
+  message B109 {}
+  message B110 {}
+  message B111 {}
+  message B112 {}
+  message B113 {}
+  message B114 {}
+  message B115 {}
+  message B116 {}
+  message B117 {}
+  message B118 {}
+  message B119 {}
+  message B120 {}
+  message B121 {}
+  message B122 {}
+  message B123 {}
+  message B124 {}
+  message B125 {}
+  message B126 {}
+  message B127 {}
+  message B128 {}
+  message B129 {}
+  message B130 {}
+  message B131 {}
+  message B132 {}
+  message B133 {}
+  message B134 {}
+  message B135 {}
+  message B136 {}
+  message B137 {}
+  message B138 {}
+  message B139 {}
+  message B140 {}
+  message B141 {}
+  message B142 {}
+  message B143 {}
+  message B144 {}
+  message B145 {}
+  message B146 {}
+  message B147 {}
+  message B148 {}
+  message B149 {}
+  message B150 {}
+  message B151 {}
+  message B152 {}
+  message B153 {}
+  message B154 {}
+  message B155 {}
+  message B156 {}
+  message B157 {}
+  message B158 {}
+  message B159 {}
+  message B160 {}
+  message B161 {}
+  message B162 {}
+  message B163 {}
+  message B164 {}
+  message B165 {}
+  message B166 {}
+  message B167 {}
+  message B168 {}
+  message B169 {}
+  message B170 {}
+  message B171 {}
+  message B172 {}
+  message B173 {}
+  message B174 {}
+  message B175 {}
+  message B176 {}
+  message B177 {}
+  message B178 {}
+  message B179 {}
+  message B180 {}
+  message B181 {}
+  message B182 {}
+  message B183 {}
+  message B184 {}
+  message B185 {}
+  message B186 {}
+  message B187 {}
+  message B188 {}
+  message B189 {}
+  message B190 {}
+  message B191 {}
+  message B192 {}
+  message B193 {}
+  message B194 {}
+  message B195 {}
+  message B196 {}
+  message B197 {}
+  message B198 {}
+  message B199 {}
+  message B200 {}
+  message B201 {}
+  message B202 {}
+  message B203 {}
+  message B204 {}
+  message B205 {}
+  message B206 {}
+  message B207 {}
+  message B208 {}
+  message B209 {}
+  message B210 {}
+  message B211 {}
+  message B212 {}
+  message B213 {}
+  message B214 {}
+  message B215 {}
+  message B216 {}
+  message B217 {}
+  message B218 {}
+  message B219 {}
+  message B220 {}
+  message B221 {}
+  message B222 {}
+  message B223 {}
+  message B224 {}
+  message B225 {}
+  message B226 {}
+  message B227 {}
+  message B228 {}
+  message B229 {}
+  message B230 {}
+  message B231 {}
+  message B232 {}
+  message B233 {}
+  message B234 {}
+  message B235 {}
+  message B236 {}
+  message B237 {}
+  message B238 {}
+  message B239 {}
+  message B240 {}
+  message B241 {}
+  message B242 {}
+  message B243 {}
+  message B244 {}
+  message B245 {}
+  message B246 {}
+  message B247 {}
+  message B248 {}
+  message B249 {}
+  message B250 {}
+  message B251 {}
+  message B252 {}
+  message B253 {}
+  message B254 {}
+  message B255 {}
+}
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 4b5df99..14cb749 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -64,6 +64,7 @@
 from google.protobuf.internal import decoder
 from google.protobuf.internal import encoder
 from google.protobuf.internal import enum_type_wrapper
+from google.protobuf.internal import extension_dict
 from google.protobuf.internal import message_listener as message_listener_mod
 from google.protobuf.internal import type_checkers
 from google.protobuf.internal import well_known_types
@@ -74,7 +75,7 @@
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
 _AnyFullTypeName = 'google.protobuf.Any'
-
+_ExtensionDict = extension_dict._ExtensionDict
 
 class GeneratedProtocolMessageType(type):
 
@@ -237,28 +238,6 @@
   return proto_field_name
 
 
-def _VerifyExtensionHandle(message, extension_handle):
-  """Verify that the given extension handle is valid."""
-
-  if not isinstance(extension_handle, _FieldDescriptor):
-    raise KeyError('HasExtension() expects an extension handle, got: %s' %
-                   extension_handle)
-
-  if not extension_handle.is_extension:
-    raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
-
-  if not extension_handle.containing_type:
-    raise KeyError('"%s" is missing a containing_type.'
-                   % extension_handle.full_name)
-
-  if extension_handle.containing_type is not message.DESCRIPTOR:
-    raise KeyError('Extension "%s" extends message type "%s", but this '
-                   'message is of type "%s".' %
-                   (extension_handle.full_name,
-                    extension_handle.containing_type.full_name,
-                    message.DESCRIPTOR.full_name))
-
-
 def _AddSlots(message_descriptor, dictionary):
   """Adds a __slots__ entry to dictionary, containing the names of all valid
   attributes for this message type.
@@ -379,8 +358,8 @@
 
 
 def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
-  extension_dict = descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.items():
+  extensions = descriptor.extensions_by_name
+  for extension_name, extension_field in extensions.items():
     assert extension_name not in dictionary
     dictionary[extension_name] = extension_field
 
@@ -784,8 +763,8 @@
 
 def _AddPropertiesForExtensions(descriptor, cls):
   """Adds properties for all fields in this protocol message type."""
-  extension_dict = descriptor.extensions_by_name
-  for extension_name, extension_field in extension_dict.items():
+  extensions = descriptor.extensions_by_name
+  for extension_name, extension_field in extensions.items():
     constant_name = extension_name.upper() + '_FIELD_NUMBER'
     setattr(cls, constant_name, extension_field.number)
 
@@ -922,7 +901,7 @@
 def _AddClearExtensionMethod(cls):
   """Helper for _AddMessageMethods()."""
   def ClearExtension(self, extension_handle):
-    _VerifyExtensionHandle(self, extension_handle)
+    extension_dict._VerifyExtensionHandle(self, extension_handle)
 
     # Similar to ClearField(), above.
     if extension_handle in self._fields:
@@ -934,7 +913,7 @@
 def _AddHasExtensionMethod(cls):
   """Helper for _AddMessageMethods()."""
   def HasExtension(self, extension_handle):
-    _VerifyExtensionHandle(self, extension_handle)
+    extension_dict._VerifyExtensionHandle(self, extension_handle)
     if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
       raise KeyError('"%s" is repeated.' % extension_handle.full_name)
 
@@ -1550,126 +1529,3 @@
       super(_OneofListener, self).Modified()
     except ReferenceError:
       pass
-
-
-# TODO(robinson): Move elsewhere?  This file is getting pretty ridiculous...
-# TODO(robinson): Unify error handling of "unknown extension" crap.
-# TODO(robinson): Support iteritems()-style iteration over all
-# extensions with the "has" bits turned on?
-class _ExtensionDict(object):
-
-  """Dict-like container for supporting an indexable "Extensions"
-  field on proto instances.
-
-  Note that in all cases we expect extension handles to be
-  FieldDescriptors.
-  """
-
-  def __init__(self, extended_message):
-    """extended_message: Message instance for which we are the Extensions dict.
-    """
-
-    self._extended_message = extended_message
-
-  def __getitem__(self, extension_handle):
-    """Returns the current value of the given extension handle."""
-
-    _VerifyExtensionHandle(self._extended_message, extension_handle)
-
-    result = self._extended_message._fields.get(extension_handle)
-    if result is not None:
-      return result
-
-    if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
-      result = extension_handle._default_constructor(self._extended_message)
-    elif extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
-      assert getattr(extension_handle.message_type, '_concrete_class', None), (
-          'Uninitialized concrete class found for field %r (message type %r)'
-          % (extension_handle.full_name,
-             extension_handle.message_type.full_name))
-      result = extension_handle.message_type._concrete_class()
-      try:
-        result._SetListener(self._extended_message._listener_for_children)
-      except ReferenceError:
-        pass
-    else:
-      # Singular scalar -- just return the default without inserting into the
-      # dict.
-      return extension_handle.default_value
-
-    # Atomically check if another thread has preempted us and, if not, swap
-    # in the new object we just created.  If someone has preempted us, we
-    # take that object and discard ours.
-    # WARNING:  We are relying on setdefault() being atomic.  This is true
-    #   in CPython but we haven't investigated others.  This warning appears
-    #   in several other locations in this file.
-    result = self._extended_message._fields.setdefault(
-        extension_handle, result)
-
-    return result
-
-  def __eq__(self, other):
-    if not isinstance(other, self.__class__):
-      return False
-
-    my_fields = self._extended_message.ListFields()
-    other_fields = other._extended_message.ListFields()
-
-    # Get rid of non-extension fields.
-    my_fields = [field for field in my_fields if field.is_extension]
-    other_fields = [field for field in other_fields if field.is_extension]
-
-    return my_fields == other_fields
-
-  def __ne__(self, other):
-    return not self == other
-
-  def __hash__(self):
-    raise TypeError('unhashable object')
-
-  # Note that this is only meaningful for non-repeated, scalar extension
-  # fields.  Note also that we may have to call _Modified() when we do
-  # successfully set a field this way, to set any necssary "has" bits in the
-  # ancestors of the extended message.
-  def __setitem__(self, extension_handle, value):
-    """If extension_handle specifies a non-repeated, scalar extension
-    field, sets the value of that field.
-    """
-
-    _VerifyExtensionHandle(self._extended_message, extension_handle)
-
-    if (extension_handle.label == _FieldDescriptor.LABEL_REPEATED or
-        extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE):
-      raise TypeError(
-          'Cannot assign to extension "%s" because it is a repeated or '
-          'composite type.' % extension_handle.full_name)
-
-    # It's slightly wasteful to lookup the type checker each time,
-    # but we expect this to be a vanishingly uncommon case anyway.
-    type_checker = type_checkers.GetTypeChecker(extension_handle)
-    # pylint: disable=protected-access
-    self._extended_message._fields[extension_handle] = (
-        type_checker.CheckValue(value))
-    self._extended_message._Modified()
-
-  def _FindExtensionByName(self, name):
-    """Tries to find a known extension with the specified name.
-
-    Args:
-      name: Extension full name.
-
-    Returns:
-      Extension field descriptor.
-    """
-    return self._extended_message._extensions_by_name.get(name, None)
-
-  def _FindExtensionByNumber(self, number):
-    """Tries to find a known extension with the field number.
-
-    Args:
-      number: Extension field number.
-
-    Returns:
-      Extension field descriptor.
-    """
-    return self._extended_message._extensions_by_number.get(number, None)
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 0807e7f..df8306a 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -107,13 +107,18 @@
       message = ('%.1024r has type %s, but expected one of: %s' %
                  (proposed_value, type(proposed_value), self._acceptable_types))
       raise TypeError(message)
+    # Some field types(float, double and bool) accept other types, must
+    # convert to the correct type in such cases.
+    if self._acceptable_types:
+      if self._acceptable_types[0] in (bool, float):
+        return self._acceptable_types[0](proposed_value)
     return proposed_value
 
 
 class TypeCheckerWithDefault(TypeChecker):
 
   def __init__(self, default_value, *acceptable_types):
-    TypeChecker.__init__(self, acceptable_types)
+    TypeChecker.__init__(self, *acceptable_types)
     self._default_value = default_value
 
   def DefaultValue(self):
@@ -232,9 +237,9 @@
     _FieldDescriptor.CPPTYPE_UINT32: Uint32ValueChecker(),
     _FieldDescriptor.CPPTYPE_UINT64: Uint64ValueChecker(),
     _FieldDescriptor.CPPTYPE_DOUBLE: TypeCheckerWithDefault(
-        0.0, numbers.Real),
+        0.0, float, numbers.Real),
     _FieldDescriptor.CPPTYPE_FLOAT: TypeCheckerWithDefault(
-        0.0, numbers.Real),
+        0.0, float, numbers.Real),
     _FieldDescriptor.CPPTYPE_BOOL: TypeCheckerWithDefault(
         False, bool, numbers.Integral),
     _FieldDescriptor.CPPTYPE_STRING: TypeCheckerWithDefault(b'', bytes),
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
index 92df148..6b4df51 100644
--- a/python/google/protobuf/internal/well_known_types.py
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -58,14 +58,6 @@
 _DURATION_SECONDS_MAX = 315576000000
 
 
-class Error(Exception):
-  """Top-level module error."""
-
-
-class ParseError(Error):
-  """Thrown in case of parsing error."""
-
-
 class Any(object):
   """Class for Any Message type."""
 
@@ -136,7 +128,7 @@
           Example of accepted format: '1972-01-01T10:00:20.021-05:00'
 
     Raises:
-      ParseError: On parsing problems.
+      ValueError: On parsing problems.
     """
     timezone_offset = value.find('Z')
     if timezone_offset == -1:
@@ -144,7 +136,7 @@
     if timezone_offset == -1:
       timezone_offset = value.rfind('-')
     if timezone_offset == -1:
-      raise ParseError(
+      raise ValueError(
           'Failed to parse timestamp: missing valid timezone offset.')
     time_value = value[0:timezone_offset]
     # Parse datetime and nanos.
@@ -159,7 +151,7 @@
     td = date_object - datetime(1970, 1, 1)
     seconds = td.seconds + td.days * _SECONDS_PER_DAY
     if len(nano_value) > 9:
-      raise ParseError(
+      raise ValueError(
           'Failed to parse Timestamp: nanos {0} more than '
           '9 fractional digits.'.format(nano_value))
     if nano_value:
@@ -169,13 +161,13 @@
     # Parse timezone offsets.
     if value[timezone_offset] == 'Z':
       if len(value) != timezone_offset + 1:
-        raise ParseError('Failed to parse timestamp: invalid trailing'
+        raise ValueError('Failed to parse timestamp: invalid trailing'
                          ' data {0}.'.format(value))
     else:
       timezone = value[timezone_offset:]
       pos = timezone.find(':')
       if pos == -1:
-        raise ParseError(
+        raise ValueError(
             'Invalid timezone offset value: {0}.'.format(timezone))
       if timezone[0] == '+':
         seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
@@ -289,10 +281,10 @@
           precision. For example: "1s", "1.01s", "1.0000001s", "-3.100s
 
     Raises:
-      ParseError: On parsing problems.
+      ValueError: On parsing problems.
     """
     if len(value) < 1 or value[-1] != 's':
-      raise ParseError(
+      raise ValueError(
           'Duration must end with letter "s": {0}.'.format(value))
     try:
       pos = value.find('.')
@@ -308,9 +300,9 @@
       _CheckDurationValid(seconds, nanos)
       self.seconds = seconds
       self.nanos = nanos
-    except ValueError:
-      raise ParseError(
-          'Couldn\'t parse duration: {0}.'.format(value))
+    except ValueError as e:
+      raise ValueError(
+          'Couldn\'t parse duration: {0} : {1}.'.format(value, e))
 
   def ToNanoseconds(self):
     """Converts a Duration to nanoseconds."""
@@ -375,15 +367,15 @@
 
 def _CheckDurationValid(seconds, nanos):
   if seconds < -_DURATION_SECONDS_MAX or seconds > _DURATION_SECONDS_MAX:
-    raise Error(
+    raise ValueError(
         'Duration is not valid: Seconds {0} must be in range '
         '[-315576000000, 315576000000].'.format(seconds))
   if nanos <= -_NANOS_PER_SECOND or nanos >= _NANOS_PER_SECOND:
-    raise Error(
+    raise ValueError(
         'Duration is not valid: Nanos {0} must be in range '
         '[-999999999, 999999999].'.format(nanos))
   if (nanos < 0 and seconds > 0) or (nanos > 0 and seconds < 0):
-    raise Error(
+    raise ValueError(
         'Duration is not valid: Sign mismatch.')
 
 
@@ -415,8 +407,9 @@
   def FromJsonString(self, value):
     """Converts string to FieldMask according to proto3 JSON spec."""
     self.Clear()
-    for path in value.split(','):
-      self.paths.append(_CamelCaseToSnakeCase(path))
+    if value:
+      for path in value.split(','):
+        self.paths.append(_CamelCaseToSnakeCase(path))
 
   def IsValidForDescriptor(self, message_descriptor):
     """Checks whether the FieldMask is valid for Message Descriptor."""
@@ -509,24 +502,26 @@
   after_underscore = False
   for c in path_name:
     if c.isupper():
-      raise Error('Fail to print FieldMask to Json string: Path name '
-                  '{0} must not contain uppercase letters.'.format(path_name))
+      raise ValueError(
+          'Fail to print FieldMask to Json string: Path name '
+          '{0} must not contain uppercase letters.'.format(path_name))
     if after_underscore:
       if c.islower():
         result.append(c.upper())
         after_underscore = False
       else:
-        raise Error('Fail to print FieldMask to Json string: The '
-                    'character after a "_" must be a lowercase letter '
-                    'in path name {0}.'.format(path_name))
+        raise ValueError(
+            'Fail to print FieldMask to Json string: The '
+            'character after a "_" must be a lowercase letter '
+            'in path name {0}.'.format(path_name))
     elif c == '_':
       after_underscore = True
     else:
       result += c
 
   if after_underscore:
-    raise Error('Fail to print FieldMask to Json string: Trailing "_" '
-                'in path name {0}.'.format(path_name))
+    raise ValueError('Fail to print FieldMask to Json string: Trailing "_" '
+                     'in path name {0}.'.format(path_name))
   return ''.join(result)
 
 
@@ -535,7 +530,7 @@
   result = []
   for c in path_name:
     if c == '_':
-      raise ParseError('Fail to parse FieldMask: Path name '
+      raise ValueError('Fail to parse FieldMask: Path name '
                        '{0} must not contain "_"s.'.format(path_name))
     if c.isupper():
       result += '_'
@@ -682,7 +677,7 @@
 
 def _AddFieldPaths(node, prefix, field_mask):
   """Adds the field paths descended from node to field_mask."""
-  if not node:
+  if not node and prefix:
     field_mask.paths.append(prefix)
     return
   for name in sorted(node):
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
index bf304b6..95a7023 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -294,12 +294,12 @@
   def testInvalidTimestamp(self):
     message = timestamp_pb2.Timestamp()
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'Failed to parse timestamp: missing valid timezone offset.',
         message.FromJsonString,
         '')
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'Failed to parse timestamp: invalid trailing data '
         '1970-01-01T00:00:01Ztrail.',
         message.FromJsonString,
@@ -310,12 +310,12 @@
         ' format \'%Y-%m-%dT%H:%M:%S\'',
         message.FromJsonString, '10000-01-01T00:00:00.00Z')
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'nanos 0123456789012 more than 9 fractional digits.',
         message.FromJsonString,
         '1970-01-01T00:00:00.0123456789012Z')
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         (r'Invalid timezone offset value: \+08.'),
         message.FromJsonString,
         '1972-01-01T01:00:00.01+08',)
@@ -333,43 +333,43 @@
   def testInvalidDuration(self):
     message = duration_pb2.Duration()
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'Duration must end with letter "s": 1.',
         message.FromJsonString, '1')
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'Couldn\'t parse duration: 1...2s.',
         message.FromJsonString, '1...2s')
     text = '-315576000001.000000000s'
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         r'Duration is not valid\: Seconds -315576000001 must be in range'
         r' \[-315576000000\, 315576000000\].',
         message.FromJsonString, text)
     text = '315576000001.000000000s'
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         r'Duration is not valid\: Seconds 315576000001 must be in range'
         r' \[-315576000000\, 315576000000\].',
         message.FromJsonString, text)
     message.seconds = -315576000001
     message.nanos = 0
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         r'Duration is not valid\: Seconds -315576000001 must be in range'
         r' \[-315576000000\, 315576000000\].',
         message.ToJsonString)
     message.seconds = 0
     message.nanos = 999999999 + 1
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         r'Duration is not valid\: Nanos 1000000000 must be in range'
         r' \[-999999999\, 999999999\].',
         message.ToJsonString)
     message.seconds = -1
     message.nanos = 1
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         r'Duration is not valid\: Sign mismatch.',
         message.ToJsonString)
 
@@ -400,6 +400,7 @@
 
     mask.FromJsonString('')
     self.assertEqual('', mask.ToJsonString())
+    self.assertEqual([], mask.paths)
     mask.FromJsonString('fooBar')
     self.assertEqual(['foo_bar'], mask.paths)
     mask.FromJsonString('fooBar,barQuz')
@@ -512,6 +513,8 @@
     mask2.FromJsonString('bar,quz')
     out_mask.Intersect(mask1, mask2)
     self.assertEqual('', out_mask.ToJsonString())
+    self.assertEqual(len(out_mask.paths), 0)
+    self.assertEqual(out_mask.paths, [])
     # Overlap with duplicated paths.
     mask1.FromJsonString('foo,baz.bb')
     mask2.FromJsonString('baz.bb,quz')
@@ -526,6 +529,15 @@
     mask2.FromJsonString('foo.bar.baz,quz')
     out_mask.Intersect(mask1, mask2)
     self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
+    # Intersect '' with ''
+    mask1.Clear()
+    mask2.Clear()
+    mask1.paths.append('')
+    mask2.paths.append('')
+    self.assertEqual(mask1.paths, [''])
+    self.assertEqual('', mask1.ToJsonString())
+    out_mask.Intersect(mask1, mask2)
+    self.assertEqual(out_mask.paths, [])
 
   def testMergeMessageWithoutMapFields(self):
     # Test merge one field.
@@ -682,7 +694,7 @@
 
     # No uppercase letter is allowed.
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         'Fail to print FieldMask to Json string: Path name Foo must '
         'not contain uppercase letters.',
         well_known_types._SnakeCaseToCamelCase,
@@ -692,19 +704,19 @@
     #   2. "_" cannot be followed by a digit.
     #   3. "_" cannot appear as the last character.
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         'Fail to print FieldMask to Json string: The character after a '
         '"_" must be a lowercase letter in path name foo__bar.',
         well_known_types._SnakeCaseToCamelCase,
         'foo__bar')
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         'Fail to print FieldMask to Json string: The character after a '
         '"_" must be a lowercase letter in path name foo_3bar.',
         well_known_types._SnakeCaseToCamelCase,
         'foo_3bar')
     self.assertRaisesRegexp(
-        well_known_types.Error,
+        ValueError,
         'Fail to print FieldMask to Json string: Trailing "_" in path '
         'name foo_bar_.',
         well_known_types._SnakeCaseToCamelCase,
@@ -718,7 +730,7 @@
     self.assertEqual('foo3_bar',
                      well_known_types._CamelCaseToSnakeCase('foo3Bar'))
     self.assertRaisesRegexp(
-        well_known_types.ParseError,
+        ValueError,
         'Fail to parse FieldMask: Path name foo_bar must not contain "_"s.',
         well_known_types._CamelCaseToSnakeCase,
         'foo_bar')
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index 7e40fdd..80f0103 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -570,7 +570,7 @@
             setattr(message, field.name, _ConvertScalarFieldValue(value, field))
       except ParseError as e:
         if field and field.containing_oneof is None:
-          raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+          raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
         else:
           raise ParseError(str(e))
       except ValueError as e:
@@ -607,7 +607,10 @@
     """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.
-    message.FromJsonString(value)
+    try:
+      message.FromJsonString(value)
+    except ValueError as e:
+      raise ParseError(e)
 
   def _ConvertValueMessage(self, value, message):
     """Convert a JSON representation into Value message."""
diff --git a/python/google/protobuf/proto_api.h b/python/google/protobuf/proto_api.h
index 47edf0e..75ee979 100644
--- a/python/google/protobuf/proto_api.h
+++ b/python/google/protobuf/proto_api.h
@@ -47,6 +47,7 @@
 
 #include <Python.h>
 
+#include <google/protobuf/descriptor_database.h>
 #include <google/protobuf/message.h>
 
 namespace google {
@@ -76,6 +77,11 @@
   // pointing to the message, like submessages or repeated containers.
   // With the current implementation, only empty messages are in this case.
   virtual Message* GetMutableMessagePointer(PyObject* msg) const = 0;
+
+  // Expose the underlying DescriptorPool and MessageFactory to enable C++ code
+  // to create Python-compatible message.
+  virtual const DescriptorPool* GetDefaultDescriptorPool() const = 0;
+  virtual MessageFactory* GetDefaultMessageFactory() const = 0;
 };
 
 inline const char* PyProtoAPICapsuleName() {
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index b73368e..7debe6f 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -65,6 +65,31 @@
 
 namespace extension_dict {
 
+static Py_ssize_t len(ExtensionDict* self) {
+  Py_ssize_t size = 0;
+  std::vector<const FieldDescriptor*> fields;
+  self->parent->message->GetReflection()->ListFields(*self->parent->message,
+                                                     &fields);
+
+  for (size_t i = 0; i < fields.size(); ++i) {
+    if (fields[i]->is_extension()) {
+      // 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.
+      // ListFields() has the same behavior.
+      if (fields[i]->message_type() != nullptr &&
+          message_factory::GetMessageClass(
+              cmessage::GetFactoryForMessage(self->parent),
+              fields[i]->message_type()) == nullptr) {
+        PyErr_Clear();
+        continue;
+      }
+      ++size;
+    }
+  }
+  return size;
+}
+
 PyObject* subscript(ExtensionDict* self, PyObject* key) {
   const FieldDescriptor* descriptor = cmessage::GetExtensionDescriptor(key);
   if (descriptor == NULL) {
@@ -246,7 +271,7 @@
 }
 
 static PyMappingMethods MpMethods = {
-  (lenfunc)NULL,               /* mp_length */
+  (lenfunc)len,                /* mp_length */
   (binaryfunc)subscript,       /* mp_subscript */
   (objobjargproc)ass_subscript,/* mp_ass_subscript */
 };
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
index 8d465eb..4bb35b3 100644
--- a/python/google/protobuf/pyext/message_module.cc
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -30,7 +30,9 @@
 
 #include <Python.h>
 
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/message_factory.h>
 #include <google/protobuf/proto_api.h>
 
 #include <google/protobuf/message_lite.h>
@@ -45,37 +47,42 @@
   google::protobuf::Message* GetMutableMessagePointer(PyObject* msg) const override {
     return google::protobuf::python::PyMessage_GetMutableMessagePointer(msg);
   }
+  const google::protobuf::DescriptorPool* GetDefaultDescriptorPool() const override {
+    return google::protobuf::python::GetDefaultDescriptorPool()->pool;
+  }
+
+  google::protobuf::MessageFactory* GetDefaultMessageFactory() const override {
+    return google::protobuf::python::GetDefaultDescriptorPool()
+        ->py_message_factory->message_factory;
+  }
 };
 
 }  // namespace
 
 static const char module_docstring[] =
-"python-proto2 is a module that can be used to enhance proto2 Python API\n"
-"performance.\n"
-"\n"
-"It provides access to the protocol buffers C++ reflection API that\n"
-"implements the basic protocol buffer functions.";
+    "python-proto2 is a module that can be used to enhance proto2 Python API\n"
+    "performance.\n"
+    "\n"
+    "It provides access to the protocol buffers C++ reflection API that\n"
+    "implements the basic protocol buffer functions.";
 
 static PyMethodDef ModuleMethods[] = {
-  {"SetAllowOversizeProtos",
-    (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
-    METH_O, "Enable/disable oversize proto parsing."},
-  // DO NOT USE: For migration and testing only.
-  { NULL, NULL}
-};
+    {"SetAllowOversizeProtos",
+     (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, METH_O,
+     "Enable/disable oversize proto parsing."},
+    // DO NOT USE: For migration and testing only.
+    {NULL, NULL}};
 
 #if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef _module = {
-  PyModuleDef_HEAD_INIT,
-  "_message",
-  module_docstring,
-  -1,
-  ModuleMethods,  /* m_methods */
-  NULL,
-  NULL,
-  NULL,
-  NULL
-};
+static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
+                                     "_message",
+                                     module_docstring,
+                                     -1,
+                                     ModuleMethods, /* m_methods */
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     NULL};
 #define INITFUNC PyInit__message
 #define INITFUNC_ERRORVAL NULL
 #else  // Python 2
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index ca70058..f0b6e5d 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -159,10 +159,6 @@
   }
 
   PyObject* py_cmsg = reinterpret_cast<PyObject*>(cmsg);
-  if (PyList_Append(self->child_messages, py_cmsg) < 0) {
-    Py_DECREF(py_cmsg);
-    return NULL;
-  }
   return py_cmsg;
 }
 
@@ -174,6 +170,18 @@
   // Create a new Message detached from the rest.
   PyObject* py_cmsg = PyEval_CallObjectWithKeywords(
       self->child_message_class->AsPyObject(), args, kwargs);
+  return py_cmsg;
+}
+
+PyObject* Add(RepeatedCompositeContainer* self,
+              PyObject* args,
+              PyObject* kwargs) {
+  PyObject* py_cmsg;
+  if (self->message == nullptr)
+    py_cmsg = AddToReleased(self, args, kwargs);
+  else
+    py_cmsg = AddToAttached(self, args, kwargs);
+
   if (py_cmsg == NULL)
     return NULL;
 
@@ -184,20 +192,98 @@
   return py_cmsg;
 }
 
-PyObject* Add(RepeatedCompositeContainer* self,
-              PyObject* args,
-              PyObject* kwargs) {
-  if (self->message == NULL)
-    return AddToReleased(self, args, kwargs);
-  else
-    return AddToAttached(self, args, kwargs);
-}
-
 static PyObject* AddMethod(PyObject* self, PyObject* args, PyObject* kwargs) {
   return Add(reinterpret_cast<RepeatedCompositeContainer*>(self), args, kwargs);
 }
 
 // ---------------------------------------------------------------------
+// append()
+
+static PyObject* AddMessage(RepeatedCompositeContainer* self, PyObject* value) {
+  cmessage::AssureWritable(self->parent);
+  if (UpdateChildMessages(self) < 0) {
+    return nullptr;
+  }
+
+  PyObject* py_cmsg;
+  if (self->message == nullptr) {
+    py_cmsg = AddToReleased(self, nullptr, nullptr);
+    if (py_cmsg == nullptr) return nullptr;
+    CMessage* cmsg = reinterpret_cast<CMessage*>(py_cmsg);
+    if (ScopedPyObjectPtr(cmessage::MergeFrom(cmsg, value)) == nullptr) {
+      Py_DECREF(cmsg);
+      return nullptr;
+    }
+  } else {
+    Message* message = self->message;
+    const Reflection* reflection = message->GetReflection();
+    py_cmsg = AddToAttached(self, nullptr, nullptr);
+    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);
+      Py_DECREF(cmsg);
+      return nullptr;
+    }
+  }
+  return py_cmsg;
+}
+
+static PyObject* AppendMethod(PyObject* pself, PyObject* value) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+  PyObject* py_cmsg = AddMessage(self, value);
+  if (py_cmsg == nullptr) {
+    return nullptr;
+  }
+
+  if (PyList_Append(self->child_messages, py_cmsg) < 0) {
+    Py_DECREF(py_cmsg);
+    return nullptr;
+  }
+
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
+// insert()
+static PyObject* Insert(PyObject* pself, PyObject* args) {
+  RepeatedCompositeContainer* self =
+      reinterpret_cast<RepeatedCompositeContainer*>(pself);
+
+  Py_ssize_t index;
+  PyObject* value;
+  if (!PyArg_ParseTuple(args, "nO", &index, &value)) {
+    return nullptr;
+  }
+
+  PyObject* py_cmsg = AddMessage(self, value);
+  if (py_cmsg == nullptr) {
+    return nullptr;
+  }
+
+  if (self->message != nullptr) {
+    // Swap the element to right position.
+    Message* message = self->message;
+    const Reflection* reflection = message->GetReflection();
+    const FieldDescriptor* field_descriptor = self->parent_field_descriptor;
+    Py_ssize_t length = reflection->FieldSize(*message, field_descriptor) - 1;
+    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 --) {
+      reflection->SwapElements(message, field_descriptor, i, i - 1);
+    }
+  }
+
+  if (PyList_Insert(self->child_messages, index, py_cmsg) < 0) {
+    return nullptr;
+  }
+  Py_RETURN_NONE;
+}
+
+// ---------------------------------------------------------------------
 // extend()
 
 PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) {
@@ -638,6 +724,10 @@
     "Makes a deep copy of the class." },
   { "add", (PyCFunction)AddMethod, METH_VARARGS | METH_KEYWORDS,
     "Adds an object to the repeated container." },
+  { "append", AppendMethod, METH_O,
+    "Appends a message to the end of the repeated container."},
+  { "insert", Insert, METH_VARARGS,
+    "Inserts a message before the specified index." },
   { "extend", ExtendMethod, METH_O,
     "Adds objects to the repeated container." },
   { "pop", Pop, METH_VARARGS,
diff --git a/src/Makefile.am b/src/Makefile.am
index ff87338..a850508 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -200,6 +200,7 @@
   google/protobuf/stubs/strutil.cc                             \
   google/protobuf/stubs/time.cc                                \
   google/protobuf/stubs/time.h                                 \
+  google/protobuf/any_lite.cc                                  \
   google/protobuf/arena.cc                                     \
   google/protobuf/extension_set.cc                             \
   google/protobuf/generated_message_util.cc                    \
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index b94529e..9d6d5cd 100644
--- a/src/google/protobuf/any.cc
+++ b/src/google/protobuf/any.cc
@@ -30,79 +30,35 @@
 
 #include <google/protobuf/any.h>
 
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/descriptor.h>
 #include <google/protobuf/generated_message_util.h>
-
+#include <google/protobuf/message.h>
 
 namespace google {
 namespace protobuf {
 namespace internal {
 
-namespace {
-string GetTypeUrl(const Descriptor* message,
-                  const string& type_url_prefix) {
-  if (!type_url_prefix.empty() &&
-      type_url_prefix[type_url_prefix.size() - 1] == '/') {
-    return type_url_prefix + message->full_name();
-  } else {
-    return type_url_prefix + "/" + message->full_name();
-  }
-}
-}  // namespace
-
-const char kAnyFullTypeName[] = "google.protobuf.Any";
-const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
-const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
-
-AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
-    : type_url_(type_url), value_(value) {
-}
-
 void AnyMetadata::PackFrom(const Message& message) {
   PackFrom(message, kTypeGoogleApisComPrefix);
 }
 
 void AnyMetadata::PackFrom(const Message& message,
                            const string& type_url_prefix) {
-  type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
-                        GetTypeUrl(message.GetDescriptor(), type_url_prefix));
+  type_url_->SetNoArena(
+      &::google::protobuf::internal::GetEmptyString(),
+      GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix));
   message.SerializeToString(value_->MutableNoArena(
       &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
 }
 
 bool AnyMetadata::UnpackTo(Message* message) const {
-  if (!InternalIs(message->GetDescriptor())) {
+  if (!InternalIs(message->GetDescriptor()->full_name())) {
     return false;
   }
   return message->ParseFromString(value_->GetNoArena());
 }
 
-bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
-  const string type_url = type_url_->GetNoArena();
-  string full_name;
-  if (!ParseAnyTypeUrl(type_url, &full_name)) {
-    return false;
-  }
-  return full_name == descriptor->full_name();
-}
-
-bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
-                     string* full_type_name) {
-  size_t pos = type_url.find_last_of("/");
-  if (pos == string::npos || pos + 1 == type_url.size()) {
-    return false;
-  }
-  if (url_prefix) {
-    *url_prefix = type_url.substr(0, pos + 1);
-  }
-  *full_type_name = type_url.substr(pos + 1);
-  return true;
-}
-
-bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
-  return ParseAnyTypeUrl(type_url, NULL, full_type_name);
-}
-
-
 bool GetAnyFieldDescriptors(const Message& message,
                             const FieldDescriptor** type_url_field,
                             const FieldDescriptor** value_field) {
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
index db7d76a..f5428c8 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -34,16 +34,26 @@
 #include <string>
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/message.h>
 #include <google/protobuf/arenastring.h>
+#include <google/protobuf/message_lite.h>
 
 #include <google/protobuf/port_def.inc>
 
 namespace google {
 namespace protobuf {
+
+class FieldDescriptor;
+class Message;
+
 namespace internal {
 
+extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
+extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
+
+std::string GetTypeUrl(StringPiece message_name,
+                  StringPiece type_url_prefix);
+
 // Helper class used to implement google::protobuf::Any.
 class PROTOBUF_EXPORT AnyMetadata {
   typedef ArenaStringPtr UrlType;
@@ -54,31 +64,52 @@
 
   // Packs a message using the default type URL prefix: "type.googleapis.com".
   // The resulted type URL will be "type.googleapis.com/<message_full_name>".
+  template <typename T>
+  void PackFrom(const T& message) {
+    InternalPackFrom(message, kTypeGoogleApisComPrefix, T::FullMessageName());
+  }
+
   void PackFrom(const Message& message);
+
   // Packs a message using the given type URL prefix. The type URL will be
   // constructed by concatenating the message type's full name to the prefix
   // with an optional "/" separator if the prefix doesn't already end up "/".
   // For example, both PackFrom(message, "type.googleapis.com") and
   // PackFrom(message, "type.googleapis.com/") yield the same result type
   // URL: "type.googleapis.com/<message_full_name>".
+  template <typename T>
+  void PackFrom(const T& message, StringPiece type_url_prefix) {
+    InternalPackFrom(message, type_url_prefix, T::FullMessageName());
+  }
+
   void PackFrom(const Message& message, const std::string& type_url_prefix);
 
   // Unpacks the payload into the given message. Returns false if the message's
   // type doesn't match the type specified in the type URL (i.e., the full
   // name after the last "/" of the type URL doesn't match the message's actual
   // full name) or parsing the payload has failed.
+  template <typename T>
+  bool UnpackTo(T* message) const {
+    return InternalUnpackTo(T::FullMessageName(), message);
+  }
+
   bool UnpackTo(Message* message) const;
 
   // Checks whether the type specified in the type URL matches the given type.
   // A type is consdiered matching if its full name matches the full name after
   // the last "/" in the type URL.
-  template<typename T>
+  template <typename T>
   bool Is() const {
-    return InternalIs(T::default_instance().GetDescriptor());
+    return InternalIs(T::FullMessageName());
   }
 
  private:
-  bool InternalIs(const Descriptor* message) const;
+  void InternalPackFrom(const MessageLite& message,
+                        StringPiece type_url_prefix,
+                        StringPiece type_name);
+  bool InternalUnpackTo(StringPiece type_name,
+                        MessageLite* message) const;
+  bool InternalIs(StringPiece type_name) const;
 
   UrlType* type_url_;
   ValueType* value_;
@@ -86,10 +117,6 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
 };
 
-extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
-extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
-extern const char kTypeGoogleProdComPrefix[];  // "type.googleprod.com/".
-
 // Get the proto type name from Any::type_url value. For example, passing
 // "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
 // *full_type_name. Returns false if the type_url does not have a "/"
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index 0b68e1d..8bd80e1 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Any_google_2fprotobuf_2fany_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fany_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fany_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fany_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -63,7 +63,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Any_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fany_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fany_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fany_2eproto, "google/protobuf/any.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fany_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fany_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
@@ -77,7 +77,7 @@
   "\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
   "roto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fany_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
   "google/protobuf/any.proto", &assign_descriptors_table_google_2fprotobuf_2fany_2eproto, 205,
@@ -111,11 +111,6 @@
 bool Any::UnpackTo(::google::protobuf::Message* message) const {
   return _any_metadata_.UnpackTo(message);
 }
-bool Any::ParseAnyTypeUrl(const string& type_url,
-                                  string* full_type_name) {
-  return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,
-                                             full_type_name);
-}
 bool Any::GetAnyFieldDescriptors(
     const ::google::protobuf::Message& message,
     const ::google::protobuf::FieldDescriptor** type_url_field,
@@ -123,6 +118,11 @@
   return ::google::protobuf::internal::GetAnyFieldDescriptors(
       message, type_url_field, value_field);
 }
+bool Any::ParseAnyTypeUrl(const string& type_url,
+                                  string* full_type_name) {
+  return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,
+                                             full_type_name);
+}
 
 class Any::HasBitSetters {
  public:
@@ -192,71 +192,40 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Any::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Any*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Any::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string type_url = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_type_url(), ptr, ctx, "google.protobuf.Any.type_url");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Any.type_url");
-        object = msg->mutable_type_url();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // bytes value = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParser(mutable_value(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        object = msg->mutable_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Any::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 5858b12..bcc2edb 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -108,15 +108,15 @@
   void PackFrom(const ::google::protobuf::Message& message,
                 const ::std::string& type_url_prefix);
   bool UnpackTo(::google::protobuf::Message* message) const;
+  static bool GetAnyFieldDescriptors(
+      const ::google::protobuf::Message& message,
+      const ::google::protobuf::FieldDescriptor** type_url_field,
+      const ::google::protobuf::FieldDescriptor** value_field);
   template<typename T> bool Is() const {
     return _any_metadata_.Is<T>();
   }
   static bool ParseAnyTypeUrl(const string& type_url,
                               string* full_type_name);
-  static bool GetAnyFieldDescriptors(
-      const ::google::protobuf::Message& message,
-      const ::google::protobuf::FieldDescriptor** type_url_field,
-      const ::google::protobuf::FieldDescriptor** value_field);
   void Swap(Any* other);
   friend void swap(Any& a, Any& b) {
     a.Swap(&b);
@@ -140,8 +140,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -153,10 +152,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Any* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Any";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
diff --git a/src/google/protobuf/any_lite.cc b/src/google/protobuf/any_lite.cc
new file mode 100644
index 0000000..9356514
--- /dev/null
+++ b/src/google/protobuf/any_lite.cc
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/any.h>
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/stubs/strutil.h>
+
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+string GetTypeUrl(StringPiece message_name,
+                  StringPiece type_url_prefix) {
+  if (!type_url_prefix.empty() &&
+      type_url_prefix[type_url_prefix.size() - 1] == '/') {
+    return StrCat(type_url_prefix, message_name);
+  } else {
+    return StrCat(type_url_prefix, "/", message_name);
+  }
+}
+
+const char kAnyFullTypeName[] = "google.protobuf.Any";
+const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
+
+AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
+    : type_url_(type_url), value_(value) {}
+
+void AnyMetadata::InternalPackFrom(const MessageLite& message,
+                                   StringPiece type_url_prefix,
+                                   StringPiece type_name) {
+  type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
+                        GetTypeUrl(type_name, type_url_prefix));
+  message.SerializeToString(value_->MutableNoArena(
+      &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
+}
+
+bool AnyMetadata::InternalUnpackTo(StringPiece type_name,
+                                   MessageLite* message) const {
+  if (!InternalIs(type_name)) {
+    return false;
+  }
+  return message->ParseFromString(value_->GetNoArena());
+}
+
+namespace {
+
+// The type URL could be stored in either an ArenaStringPtr or a
+// StringPieceField, so we provide these helpers to get a string_view from
+// either type. We use a template function as a way to avoid depending on
+// StringPieceField.
+
+template <typename T>
+StringPiece Get(const T* ptr) {
+  return ptr->Get();
+}
+
+template <>
+// NOLINTNEXTLINE: clang-diagnostic-unused-function
+StringPiece Get(const ArenaStringPtr* ptr) {
+  return ptr->GetNoArena();
+}
+
+}  // namespace
+
+bool AnyMetadata::InternalIs(StringPiece type_name) const {
+  StringPiece type_url = Get(type_url_);
+  return type_url.size() >= type_name.size() + 1 &&
+         type_url[type_url.size() - type_name.size() - 1] == '/' &&
+         HasSuffixString(type_url, type_name);
+}
+
+bool ParseAnyTypeUrl(const string& type_url, string* url_prefix,
+                     string* full_type_name) {
+  size_t pos = type_url.find_last_of("/");
+  if (pos == string::npos || pos + 1 == type_url.size()) {
+    return false;
+  }
+  if (url_prefix) {
+    *url_prefix = type_url.substr(0, pos + 1);
+  }
+  *full_type_name = type_url.substr(pos + 1);
+  return true;
+}
+
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
+  return ParseAnyTypeUrl(type_url, nullptr, full_type_name);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/any_test.cc b/src/google/protobuf/any_test.cc
index 514ac51..378981c 100644
--- a/src/google/protobuf/any_test.cc
+++ b/src/google/protobuf/any_test.cc
@@ -29,9 +29,11 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <google/protobuf/any_test.pb.h>
+#include <google/protobuf/unittest.pb.h>
 #include <gtest/gtest.h>
 
 
+
 namespace google {
 namespace protobuf {
 namespace {
@@ -46,10 +48,22 @@
 
   ASSERT_TRUE(message.ParseFromString(data));
   EXPECT_TRUE(message.has_any_value());
+  submessage.Clear();
   ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
   EXPECT_EQ(12345, submessage.int32_value());
 }
 
+TEST(AnyTest, TestUnpackWithTypeMismatch) {
+  protobuf_unittest::TestAny payload;
+  payload.set_int32_value(13);
+  google::protobuf::Any any;
+  any.PackFrom(payload);
+
+  // Attempt to unpack into the wrong type.
+  protobuf_unittest::TestAllTypes dest;
+  EXPECT_FALSE(any.UnpackTo(&dest));
+}
+
 TEST(AnyTest, TestPackAndUnpackAny) {
   // We can pack a Any message inside another Any message.
   protobuf_unittest::TestAny submessage;
@@ -63,26 +77,26 @@
 
   ASSERT_TRUE(message.ParseFromString(data));
   EXPECT_TRUE(message.has_any_value());
+  any.Clear();
+  submessage.Clear();
   ASSERT_TRUE(message.any_value().UnpackTo(&any));
   ASSERT_TRUE(any.UnpackTo(&submessage));
   EXPECT_EQ(12345, submessage.int32_value());
 }
 
-TEST(AnyType, TestPackWithCustomTypeUrl) {
+TEST(AnyTest, TestPackWithCustomTypeUrl) {
   protobuf_unittest::TestAny submessage;
   submessage.set_int32_value(12345);
   google::protobuf::Any any;
   // Pack with a custom type URL prefix.
   any.PackFrom(submessage, "type.myservice.com");
-  EXPECT_EQ("type.myservice.com/" + submessage.GetDescriptor()->full_name(),
-            any.type_url());
+  EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
   // Pack with a custom type URL prefix ending with '/'.
   any.PackFrom(submessage, "type.myservice.com/");
-  EXPECT_EQ("type.myservice.com/" + submessage.GetDescriptor()->full_name(),
-            any.type_url());
+  EXPECT_EQ("type.myservice.com/protobuf_unittest.TestAny", any.type_url());
   // Pack with an empty type URL prefix.
   any.PackFrom(submessage, "");
-  EXPECT_EQ("/" + submessage.GetDescriptor()->full_name(), any.type_url());
+  EXPECT_EQ("/protobuf_unittest.TestAny", any.type_url());
 
   // Test unpacking the type.
   submessage.Clear();
@@ -104,6 +118,15 @@
   ASSERT_TRUE(message.ParseFromString(message.SerializeAsString()));
   EXPECT_FALSE(message.any_value().Is<protobuf_unittest::TestAny>());
   EXPECT_TRUE(message.any_value().Is<google::protobuf::Any>());
+
+  any.set_type_url("/protobuf_unittest.TestAny");
+  EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
+  // The type URL must contain at least one "/".
+  any.set_type_url("protobuf_unittest.TestAny");
+  EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
+  // The type name after the slash must be fully qualified.
+  any.set_type_url("/TestAny");
+  EXPECT_FALSE(any.Is<protobuf_unittest::TestAny>());
 }
 
 TEST(AnyTest, MoveConstructor) {
@@ -117,6 +140,7 @@
 
   google::protobuf::Any dst(std::move(src));
   EXPECT_EQ(type_url, dst.type_url().data());
+  payload.Clear();
   ASSERT_TRUE(dst.UnpackTo(&payload));
   EXPECT_EQ(12345, payload.int32_value());
 }
@@ -133,6 +157,7 @@
   google::protobuf::Any dst;
   dst = std::move(src);
   EXPECT_EQ(type_url, dst.type_url().data());
+  payload.Clear();
   ASSERT_TRUE(dst.UnpackTo(&payload));
   EXPECT_EQ(12345, payload.int32_value());
 }
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 2a6ca2b..8fe7301 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -89,9 +89,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Mixin_google_2fprotobuf_2fapi_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fapi_2eproto[3];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fapi_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -138,7 +138,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Mixin_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fapi_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fapi_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fapi_2eproto, "google/protobuf/api.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fapi_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fapi_2eproto, 3, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
@@ -165,7 +165,7 @@
   "nproto/protobuf/api;api\242\002\003GPB\252\002\036Google.P"
   "rotobuf.WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fapi_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
   "google/protobuf/api.proto", &assign_descriptors_table_google_2fprotobuf_2fapi_2eproto, 750,
@@ -298,141 +298,85 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Api::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Api*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Api::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Api.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Api.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.Method methods = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_methods(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Method::_InternalParse;
-          object = msg->add_methods();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.Option options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       // string version = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_version(), ptr, ctx, "google.protobuf.Api.version");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Api.version");
-        object = msg->mutable_version();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // .google.protobuf.SourceContext source_context = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_source_context(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::SourceContext::_InternalParse;
-        object = msg->mutable_source_context();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // repeated .google.protobuf.Mixin mixins = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_mixins(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Mixin::_InternalParse;
-          object = msg->add_mixins();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
       }
       // .google.protobuf.Syntax syntax = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 56) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_syntax(static_cast<::google::protobuf::Syntax>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_syntax(static_cast<::google::protobuf::Syntax>(val));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Api::MergePartialFromCodedStream(
@@ -957,77 +901,44 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Method::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Method*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Method::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Method.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Method.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // string request_type_url = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_request_type_url(), ptr, ctx, "google.protobuf.Method.request_type_url");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Method.request_type_url");
-        object = msg->mutable_request_type_url();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // bool request_streaming = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_request_streaming(::google::protobuf::internal::ReadVarint(&ptr));
+        set_request_streaming(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // string response_type_url = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_response_type_url(), ptr, ctx, "google.protobuf.Method.response_type_url");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Method.response_type_url");
-        object = msg->mutable_response_type_url();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // bool response_streaming = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
-        msg->set_response_streaming(::google::protobuf::internal::ReadVarint(&ptr));
+        set_response_streaming(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -1035,48 +946,34 @@
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
       }
       // .google.protobuf.Syntax syntax = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 56) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_syntax(static_cast<::google::protobuf::Syntax>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_syntax(static_cast<::google::protobuf::Syntax>(val));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Method::MergePartialFromCodedStream(
@@ -1571,72 +1468,40 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Mixin::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Mixin*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Mixin::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Mixin.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // string root = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_root(), ptr, ctx, "google.protobuf.Mixin.root");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.root");
-        object = msg->mutable_root();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Mixin::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 11e8196..6e63871 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 #include <google/protobuf/source_context.pb.h>
 #include <google/protobuf/type.pb.h>
 // @@protoc_insertion_point(includes)
@@ -134,8 +141,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -147,10 +153,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Api* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Api";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
@@ -325,8 +335,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -338,10 +347,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Method* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Method";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
@@ -509,8 +522,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -522,10 +534,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Mixin* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Mixin";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index a38a802..bd56239 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -34,6 +34,7 @@
 #define GOOGLE_PROTOBUF_ARENA_H__
 
 #include <limits>
+#include <type_traits>
 #ifdef max
 #undef max  // Visual Studio defines this macro
 #endif
@@ -156,13 +157,14 @@
  private:
   // Hooks for adding external functionality such as user-specific metrics
   // collection, specific debugging abilities, etc.
-  // Init hook may return a pointer to a cookie to be stored in the arena.
-  // reset and destruction hooks will then be called with the same cookie
-  // pointer. This allows us to save an external object per arena instance and
-  // use it on the other hooks (Note: It is just as legal for init to return
-  // NULL and not use the cookie feature).
-  // on_arena_reset and on_arena_destruction also receive the space used in
-  // the arena just before the reset.
+  // Init hook (if set) will always be called at Arena init time. Init hook may
+  // return a pointer to a cookie to be stored in the arena. Reset and
+  // destruction hooks will then be called with the same cookie pointer. This
+  // allows us to save an external object per arena instance and use it on the
+  // other hooks (Note: If init hook returns NULL, the other hooks will NOT be
+  // called on this arena instance).
+  // on_arena_reset and on_arena_destruction also receive the space used in the
+  // arena just before the reset.
   void* (*on_arena_init)(Arena* arena);
   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
@@ -408,12 +410,12 @@
   }
 
   // Retrieves the arena associated with |value| if |value| is an arena-capable
-  // message, or NULL otherwise. This differs from value->GetArena() in that the
-  // latter is a virtual call, while this method is a templated call that
-  // resolves at compile-time.
+  // message, or NULL otherwise. If possible, the call resolves at compile time.
+  // Note that we can often devirtualize calls to `value->GetArena()` so usually
+  // calling this method is unnecessary.
   template <typename T>
   PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
-    return GetArenaInternal(value, is_arena_constructable<T>());
+    return GetArenaInternal(value);
   }
 
   template <typename T>
@@ -440,6 +442,15 @@
                                              sizeof(char)>
         is_arena_constructable;
 
+    template <typename U>
+    static char HasGetArena(decltype(&U::GetArena));
+    template <typename U>
+    static double HasGetArena(...);
+
+    typedef std::integral_constant<bool, sizeof(HasGetArena<T>(nullptr)) ==
+                                             sizeof(char)>
+        has_get_arena;
+
     template <typename... Args>
     static T* Construct(void* ptr, Args&&... args) {
       return new (ptr) T(std::forward<Args>(args)...);
@@ -655,16 +666,24 @@
   // Implementation for GetArena(). Only message objects with
   // InternalArenaConstructable_ tags can be associated with an arena, and such
   // objects must implement a GetArenaNoVirtual() method.
-  template <typename T>
-  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value,
-                                                        std::true_type) {
+  template <typename T, typename std::enable_if<
+                            is_arena_constructable<T>::value, int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
     return InternalHelper<T>::GetArena(value);
   }
-
-  template <typename T>
-  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* /* value */,
-                                                        std::false_type) {
-    return NULL;
+  template <typename T,
+            typename std::enable_if<!is_arena_constructable<T>::value &&
+                                        InternalHelper<T>::has_get_arena::value,
+                                    int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return value->GetArena();
+  }
+  template <typename T, typename std::enable_if<
+                            !is_arena_constructable<T>::value &&
+                                !InternalHelper<T>::has_get_arena::value,
+                            int>::type = 0>
+  PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
+    return nullptr;
   }
 
   // For friends of arena.
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index a942cff..9fdcda5 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -1324,6 +1324,12 @@
   const ArenaMessage* const_pointer_to_message = message;
   EXPECT_EQ(&arena, Arena::GetArena(message));
   EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+
+  // Test that the Message* / MessageLite* specialization SFINAE works.
+  const Message* const_pointer_to_message_type = message;
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_type));
+  const MessageLite* const_pointer_to_message_lite_type = message;
+  EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_lite_type));
 }
 
 TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 4dc4725..54bec72 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -2463,9 +2463,8 @@
       "net/proto2/internal/no_such_file.proto: No such file or directory\n");
 }
 
-INSTANTIATE_TEST_CASE_P(FileDescriptorSetSource,
-                        EncodeDecodeTest,
-                        testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
+INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest,
+                         testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
 }  // anonymous namespace
 
 #endif  // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 39fe9e6..66e56d0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -72,7 +72,6 @@
   variables_["short_name"] = descriptor_->name();
   variables_["enumbase"] = options_.proto_h ? " : int" : "";
   variables_["nested_name"] = descriptor_->name();
-  variables_["constexpr"] = options_.proto_h ? "constexpr" : "";
   variables_["prefix"] =
       (descriptor_->containing_type() == NULL) ? "" : classname_ + "_";
 }
@@ -127,15 +126,15 @@
 
   format(
       "$dllexport_decl $bool $classname$_IsValid(int value);\n"
-      "const $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
+      "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
       "$prefix$$2$;\n"
-      "const $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
+      "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
       "$prefix$$3$;\n",
       descriptor_, EnumValueName(min_value), EnumValueName(max_value));
 
   if (generate_array_size_) {
     format(
-        "const int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
+        "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
         "$prefix$$short_name$_MAX + 1;\n\n",
         descriptor_);
   }
@@ -199,7 +198,7 @@
     string deprecated_attr = DeprecatedAttribute(
         options_, descriptor_->value(j)->options().deprecated());
     format(
-        "$1$static $constexpr $const $nested_name$ ${2$$3$$}$ =\n"
+        "$1$static constexpr $nested_name$ ${2$$3$$}$ =\n"
         "  $classname$_$3$;\n",
         deprecated_attr, descriptor_->value(j),
         EnumValueName(descriptor_->value(j)));
@@ -209,14 +208,14 @@
       "static inline bool $nested_name$_IsValid(int value) {\n"
       "  return $classname$_IsValid(value);\n"
       "}\n"
-      "static const $nested_name$ ${1$$nested_name$_MIN$}$ =\n"
+      "static constexpr $nested_name$ ${1$$nested_name$_MIN$}$ =\n"
       "  $classname$_$nested_name$_MIN;\n"
-      "static const $nested_name$ ${1$$nested_name$_MAX$}$ =\n"
+      "static constexpr $nested_name$ ${1$$nested_name$_MAX$}$ =\n"
       "  $classname$_$nested_name$_MAX;\n",
       descriptor_);
   if (generate_array_size_) {
     format(
-        "static const int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
+        "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
         "  $classname$_$nested_name$_ARRAYSIZE;\n",
         descriptor_);
   }
@@ -297,25 +296,26 @@
 
   if (descriptor_->containing_type() != NULL) {
     string parent = ClassName(descriptor_->containing_type(), false);
-    // We need to "define" the static constants which were declared in the
-    // header, to give the linker a place to put them.  Or at least the C++
-    // standard says we have to.  MSVC actually insists that we do _not_ define
-    // them again in the .cc file, prior to VC++ 2015.
-    format("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n");
+    // Before C++17, we must define the static constants which were
+    // declared in the header, to give the linker a place to put them.
+    // But pre-2015 MSVC++ insists that we not.
+    format("#if (__cplusplus < 201703) && "
+           "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
 
     for (int i = 0; i < descriptor_->value_count(); i++) {
-      format("$constexpr $const $classname$ $1$::$2$;\n", parent,
+      format("constexpr $classname$ $1$::$2$;\n", parent,
              EnumValueName(descriptor_->value(i)));
     }
     format(
-        "const $classname$ $1$::$nested_name$_MIN;\n"
-        "const $classname$ $1$::$nested_name$_MAX;\n",
+        "constexpr $classname$ $1$::$nested_name$_MIN;\n"
+        "constexpr $classname$ $1$::$nested_name$_MAX;\n",
         parent);
     if (generate_array_size_) {
-      format("const int $1$::$nested_name$_ARRAYSIZE;\n", parent);
+      format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent);
     }
 
-    format("#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900\n");
+    format("#endif  // (__cplusplus < 201703) && "
+           "(!defined(_MSC_VER) || _MSC_VER >= 1900)\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index e9abeff..24c88d3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -706,29 +706,34 @@
   // in the file.
 
   if (!message_generators_.empty()) {
-    format("::$proto_ns$::Metadata $file_level_metadata$[$1$];\n",
+    format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n",
            message_generators_.size());
   } else {
     format(
+        "static "
         "constexpr ::$proto_ns$::Metadata* $file_level_metadata$ = nullptr;\n");
   }
   if (!enum_generators_.empty()) {
     format(
+        "static "
         "const ::$proto_ns$::EnumDescriptor* "
         "$file_level_enum_descriptors$[$1$];\n",
         enum_generators_.size());
   } else {
     format(
+        "static "
         "constexpr ::$proto_ns$::EnumDescriptor const** "
         "$file_level_enum_descriptors$ = nullptr;\n");
   }
   if (HasGenericServices(file_, options_) && file_->service_count() > 0) {
     format(
+        "static "
         "const ::$proto_ns$::ServiceDescriptor* "
         "$file_level_service_descriptors$[$1$];\n",
         file_->service_count());
   } else {
     format(
+        "static "
         "constexpr ::$proto_ns$::ServiceDescriptor const** "
         "$file_level_service_descriptors$ = nullptr;\n");
   }
@@ -795,6 +800,7 @@
   // AssignDescriptors().  All later times, waits for the first call to
   // complete and then returns.
   format(
+      "static "
       "::$proto_ns$::internal::AssignDescriptorsTable $assign_desc_table$ = "
       "{\n"
       "  {}, $add_descriptors$, \"$filename$\", schemas,\n"
@@ -846,6 +852,7 @@
 
   // Now generate the AddDescriptors() function.
   format(
+      "static "
       "::$proto_ns$::internal::DescriptorTable $1$ = {\n"
       "  false, $init_defaults$, \n"
       "  $2$,\n",
@@ -1295,6 +1302,26 @@
 
   if (IsAnyMessage(file_, options_)) {
     IncludeFile("net/proto2/internal/any.h", printer);
+  } else {
+    // For Any support with lite protos, we need to friend AnyMetadata, so we
+    // forward-declare it here.
+    if (options_.opensource_runtime) {
+      format(
+          "namespace google {\n"
+          "namespace protobuf {\n"
+          "namespace internal {\n"
+          "class AnyMetadata;\n"
+          "}  // namespace internal\n"
+          "}  // namespace protobuf\n"
+          "}  // namespace google\n");
+    } else {
+      format(
+          "namespace google {\nnamespace protobuf {\n"
+          "namespace internal {\n"
+          "class AnyMetadata;\n"
+          "}  // namespace internal\n"
+          "}  // namespace protobuf\n}  // namespace google\n");
+    }
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index e6cbdf4..a3bd81f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -32,6 +32,7 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <functional>
 #include <limits>
 #include <map>
 #include <queue>
@@ -75,7 +76,7 @@
   return StringReplace(name, ".", "::", true);
 }
 
-const char* const kKeywordList[] = {  //
+static const char* const kKeywordList[] = {  //
     "NULL",
     "alignas",
     "alignof",
@@ -160,15 +161,15 @@
     "xor",
     "xor_eq"};
 
-std::unordered_set<string> MakeKeywordsMap() {
-  std::unordered_set<string> result;
-  for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
-    result.insert(kKeywordList[i]);
+static std::unordered_set<string>* MakeKeywordsMap() {
+  auto* result = new std::unordered_set<string>();
+  for (const auto keyword : kKeywordList) {
+    result->emplace(keyword);
   }
   return result;
 }
 
-std::unordered_set<string> kKeywords = MakeKeywordsMap();
+static std::unordered_set<string>& kKeywords = *MakeKeywordsMap();
 
 // Returns whether the provided descriptor has an extension. This includes its
 // nested types.
@@ -255,6 +256,7 @@
         "ECK";
   }
 
+  SetIntVar(options, "int8", variables);
   SetIntVar(options, "uint8", variables);
   SetIntVar(options, "uint32", variables);
   SetIntVar(options, "uint64", variables);
@@ -910,11 +912,7 @@
 }
 
 bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
-  // For now we do not support Any in lite mode, so if we're building for lite
-  // then we just treat Any as if it's an ordinary message with no special
-  // behavior.
-  return descriptor->name() == kAnyProtoFile &&
-         GetOptimizeFor(descriptor, options) != FileOptions::LITE_RUNTIME;
+  return descriptor->name() == kAnyProtoFile;
 }
 
 bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
@@ -1302,14 +1300,20 @@
 
   void GenerateParserLoop(const Descriptor* descriptor) {
     format_.Set("classname", ClassName(descriptor));
-    format_.Set("proto_ns", ProtobufNamespace(options_));
+    format_.Set("p_ns", "::" + ProtobufNamespace(options_));
+    format_.Set("pi_ns", StrCat("::", ProtobufNamespace(options_), "::internal"));
     format_.Set("GOOGLE_PROTOBUF", MacroPrefix(options_));
+    format_.Set("kSlopBytes",
+                static_cast<int>(internal::ParseContext::kSlopBytes));
     std::map<string, string> vars;
     SetCommonVars(options_, &vars);
     format_.AddMap(vars);
 
     std::vector<const FieldDescriptor*> ordered_fields;
     for (auto field : FieldRange(descriptor)) {
+      if (IsProto1(descriptor->file(), options_)) {
+        if (field->number() >= (1 << 14)) continue;
+      }
       ordered_fields.push_back(field);
     }
     std::sort(ordered_fields.begin(), ordered_fields.end(),
@@ -1318,19 +1322,11 @@
               });
 
     format_(
-        "const char* $classname$::_InternalParse(const char* begin, const "
-        "char* "
-        "end, void* object,\n"
-        "                  ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "  auto msg = static_cast<$classname$*>(object);\n"
-        "  $int32$ size; (void)size;\n"
-        "  int depth; (void)depth;\n"
-        "  $uint32$ tag;\n"
-        "  ::$proto_ns$::internal::ParseFunc parser_till_end; "
-        "(void)parser_till_end;\n"
-        "  auto ptr = begin;\n"
-        "  while (ptr < end) {\n"
-        "    ptr = ::$proto_ns$::io::Parse32(ptr, &tag);\n"
+        "const char* $classname$::_InternalParse(const char* ptr, "
+        "$pi_ns$::ParseContext* ctx) {\n"
+        "  while (!ctx->Done(&ptr)) {\n"
+        "    $uint32$ tag;\n"
+        "    ptr = $pi_ns$::ReadTag(ptr, &tag);\n"
         "    $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
         "    switch (tag >> 3) {\n");
 
@@ -1338,11 +1334,7 @@
     format_.Indent();
     format_.Indent();
 
-    bool use_handle_unusual = false;
     for (const auto* field : ordered_fields) {
-      if (IsProto1(descriptor->file(), options_)) {
-        if (field->number() >= (1 << 14)) continue;
-      }
       // Print the field's (or oneof's) proto-syntax definition as a comment.
       // We don't want to print group bodies so we cut off after the first
       // line.
@@ -1359,22 +1351,21 @@
           "case $2$: {\n",
           def, field->number());
       format_.Indent();
-      use_handle_unusual = true;
       GenerateCaseBody(field);
       format_.Outdent();
       format_("}\n");  // case
     }                  // for fields
+
+    // Default case
     format_("default: {\n");
-    if (use_handle_unusual) format_("handle_unusual:\n");
+    if (!ordered_fields.empty()) format_("handle_unusual:\n");
     format_(
         "  if ((tag & 7) == 4 || tag == 0) {\n"
-        "    ctx->EndGroup(tag);\n"
+        "    ctx->SetLastTag(tag);\n"
         "    return ptr;\n"
         "  }\n");
     if (IsMapEntryMessage(descriptor)) {
-      format_(
-          "  break;\n"
-          "}\n");
+      format_("  break;\n");
     } else {
       if (descriptor->extension_range_count() > 0) {
         format_("if (");
@@ -1396,113 +1387,59 @@
         }
         format_(") {\n");
         format_(
-            "  auto res = msg->_extensions_.ParseField(tag, {_InternalParse, "
-            "msg}, ptr, end,\n"
-            "      internal_default_instance(), &msg->_internal_metadata_, "
+            "  ptr = _extensions_.ParseField(tag, ptr, \n"
+            "      internal_default_instance(), &_internal_metadata_, "
             "ctx);\n"
-            "  ptr = res.first;\n"
             "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
-            "  if (res.second) return ptr;\n"
-            "  continue;\n"
+            "  break;\n"
             "}\n");
       }
       format_(
-          "  auto res = UnknownFieldParse(tag, {_InternalParse, msg},\n"
-          "    ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), "
-          "ctx);\n"
-          "  ptr = res.first;\n"
+          "  ptr = UnknownFieldParse(tag,\n"
+          "    _internal_metadata_.mutable_unknown_fields(), ptr, ctx);\n"
           "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
-          "  if (res.second) return ptr;\n"
-          "}\n");  // default case
+          "  break;\n");
     }
+    format_("}\n");  // default case
     format_.Outdent();
     format_.Outdent();
     format_.Outdent();
     format_(
         "    }  // switch\n"
         "  }  // while\n"
-        "  return ptr;\n");
-    if (use_string_) {
-      format_(
-          "string_till_end:\n"
-          "  static_cast<$string$*>(object)->clear();\n"
-          // TODO(gerbens) evaluate security
-          "  static_cast<$string$*>(object)->reserve(size);\n"
-          "  goto len_delim_till_end;\n");
-    }
-    if (use_arena_string_) {
-      format_(
-          "arena_string_till_end:\n"
-          "  object = "
-          "static_cast<::$proto_ns$::internal::ArenaStringPtr*>(object)->"
-          "Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), "
-          "msg->GetArenaNoVirtual());\n"
-          "  static_cast<$string$*>(object)->clear();\n"
-          // TODO(gerbens) evaluate security
-          "  static_cast<$string$*>(object)->reserve(size);\n"
-          "  goto len_delim_till_end;\n");
-    }
-    if (use_length_delimited_) {
-      format_(
-          "len_delim_till_end:\n"
-          "  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},\n"
-          "                               {parser_till_end, object}, size);\n");
-    }
-    if (use_group_) {
-      // Group crossed end and must be continued. Either this a parse failure
-      // or we need to resume on the next chunk and thus save the state.
-      format_(
-          "group_continues:\n"
-          "  $DCHK$(ptr >= end);\n"
-          "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->StoreGroup(\n   "
-          "   {_InternalParse, msg}, {parser_till_end, object}, depth, tag));\n"
-          "  return ptr;\n");
-    }
-    format_("}\n");
+        "  return ptr;\n"
+        "}\n");
   }
 
  private:
   MessageSCCAnalyzer* scc_analyzer_;
   const Options& options_;
   Formatter format_;
-  bool use_length_delimited_ = false;
-  bool use_group_ = false;
-  bool use_string_ = false;
-  bool use_arena_string_ = false;
 
   using WireFormat = internal::WireFormat;
   using WireFormatLite = internal::WireFormatLite;
 
-  void GenerateArenaString(const FieldDescriptor* field, const string& utf8) {
-    use_arena_string_ = true;
+  void GenerateArenaString(const FieldDescriptor* field, const string& utf8,
+                           const string& field_name) {
     if (HasFieldPresence(field->file())) {
-      format_("HasBitSetters::set_has_$1$(msg);\n", FieldName(field));
+      format_("HasBitSetters::set_has_$1$(this);\n", FieldName(field));
     }
     format_(
-        "if (size > end - ptr + "
-        "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n"
-        "  object = &msg->$1$_;\n"
-        "  parser_till_end = ::$proto_ns$::internal::GreedyStringParser$2$;\n"
-        "  goto arena_string_till_end;\n"
-        "}\n"
-        "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$"
-        "(ptr, size, ctx));\n"
-        "::$proto_ns$::internal::CopyIntoArenaString(ptr, size, &msg->$1$_, "
-        "msg->GetArenaNoVirtual());\n"
-        "ptr += size;\n",
-        FieldName(field), utf8);
+        "ptr = $pi_ns$::InlineCopyIntoArenaString$1$(&$2$_, ptr, ctx, "
+        "GetArenaNoVirtual()$3$);\n",
+        utf8, FieldName(field), field_name);
   }
 
   void GenerateStrings(const FieldDescriptor* field, bool check_utf8) {
     string utf8;
+    string field_name;
     if (check_utf8) {
       utf8 = GetUtf8Suffix(field, options_);
       if (!utf8.empty()) {
-        string name = "nullptr";
+        field_name = ", nullptr";
         if (HasDescriptorMethods(field->file(), options_)) {
-          name = "\"" + field->full_name() + "\"";
+          field_name = StrCat(", \"", field->full_name(), "\"");
         }
-        format_("ctx->extra_parse_data().SetFieldName($1$);\n", name);
       }
     }
     FieldOptions::CType ctype = FieldOptions::STRING;
@@ -1523,73 +1460,40 @@
         !IsProto1(field->file(), options_) &&
         !IsStringInlined(field, options_) &&
         field->containing_oneof() == nullptr && ctype == FieldOptions::STRING) {
-      GenerateArenaString(field, utf8);
+      GenerateArenaString(field, utf8, field_name);
       return;
     }
-    format_(
-        "object = msg->$1$_$2$();\n"
-        "if (size > end - ptr + "
-        "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n",
-        field->is_repeated() && !field->is_packable() ? "add" : "mutable",
-        FieldName(field));
     string name;
-    string label = "len_delim_till_end";
     switch (ctype) {
       case FieldOptions::STRING:
-        name = "GreedyStringParser";
-        use_string_ = true;
-        label = "string_till_end";
+        name = "GreedyStringParser" + utf8;
         break;
       case FieldOptions::CORD:
-        name = "CordParser";
-        format_("  static_cast<::Cord*>(object)->Clear();\n");
+        name = "CordParser" + utf8;
         break;
       case FieldOptions::STRING_PIECE:
-        name = "StringPieceParser";
-        format_(
-            "  "
-            "static_cast<::$proto_ns$::internal::StringPieceField*>(object)->"
-            "Clear();\n");
+        name = "StringPieceParser" + utf8;
         break;
     }
     format_(
-        "  parser_till_end = ::$proto_ns$::internal::$1$$2$;\n"
-        "  goto $3$;\n"
-        "}\n"
-        "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$"
-        "(ptr, size, ctx));\n"
-        "::$proto_ns$::internal::Inline$1$(object, ptr, size, ctx);\n"
-        "ptr += size;\n",
-        name, utf8, label);
+        "ptr = $pi_ns$::Inline$1$($2$_$3$(), ptr, ctx$4$);\n",
+        name, field->is_repeated() && !field->is_packable() ? "add" : "mutable",
+        FieldName(field), field_name);
   }
 
   void GenerateLengthDelim(const FieldDescriptor* field) {
-    format_(
-        "ptr = ::$proto_ns$::io::ReadSize(ptr, &size);\n"
-        "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
     if (!IsProto1(field->file(), options_) && field->is_packable()) {
+      string enum_validator;
       if (!HasPreservingUnknownEnumSemantics(field->file()) &&
           field->type() == FieldDescriptor::TYPE_ENUM) {
-        format_(
-            "ctx->extra_parse_data().SetEnumValidator($1$_IsValid, "
-            "msg->mutable_unknown_fields(), $2$);\n"
-            "parser_till_end = "
-            "::$proto_ns$::internal::PackedValidEnumParser$3$;\n"
-            "object = msg->mutable_$4$();\n",
-            QualifiedClassName(field->enum_type()), field->number(),
-            UseUnknownFieldSet(field->file(), options_) ? "" : "Lite",
-            FieldName(field));
-      } else {
-        format_(
-            "parser_till_end = ::$proto_ns$::internal::Packed$1$Parser;\n"
-            "object = msg->mutable_$2$();\n",
-            DeclaredTypeMethodName(field->type()), FieldName(field));
+        enum_validator = StrCat(
+            ", ", QualifiedClassName(field->enum_type()),
+            "_IsValid, mutable_unknown_fields(), ", field->number());
       }
       format_(
-          "if (size > end - ptr) goto len_delim_till_end;\n"
-          "auto newend = ptr + size;\n"
-          "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n"
-          "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
+          "ptr = $pi_ns$::Packed$1$Parser(mutable_$2$(), ptr, ctx$3$);\n",
+          DeclaredTypeMethodName(field->type()), FieldName(field),
+          enum_validator);
     } else {
       auto field_type = field->type();
       if (IsProto1(field->file(), options_)) {
@@ -1610,106 +1514,62 @@
           GenerateStrings(field, false /* utf8 */);
           break;
         case FieldDescriptor::TYPE_MESSAGE: {
-          GOOGLE_CHECK(field->message_type());
           if (!IsProto1(field->file(), options_) && field->is_map()) {
-            const FieldDescriptor* val =
-                field->message_type()->FindFieldByName("value");
-            GOOGLE_CHECK(val);
-            if (HasFieldPresence(field->file()) &&
-                val->type() == FieldDescriptor::TYPE_ENUM) {
-              format_(
-                  "ctx->extra_parse_data().field_number = $1$;\n"
-                  "ctx->extra_parse_data().unknown_fields = "
-                  "&msg->_internal_metadata_;\n",
-                  field->number());
-            }
-            format_(
-                "parser_till_end = "
-                "::$proto_ns$::internal::SlowMapEntryParser;\n"
-                "auto parse_map = $1$::_ParseMap;\n"
-                "ctx->extra_parse_data().payload.clear();\n"
-                "ctx->extra_parse_data().parse_map = parse_map;\n"
-                "object = &msg->$2$_;\n"
-                "if (size > end - ptr) goto len_delim_till_end;\n"
-                "auto newend = ptr + size;\n"
-                "$GOOGLE_PROTOBUF$_PARSER_ASSERT(parse_map(ptr, newend, "
-                "object, ctx));\n"
-                "ptr = newend;\n",
-                QualifiedClassName(field->message_type()), FieldName(field));
-            break;
-          }
-          if (!IsProto1(field->file(), options_) && IsLazy(field, options_)) {
+            format_("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
+          } else if (!IsProto1(field->file(), options_) &&
+                     IsLazy(field, options_)) {
             if (field->containing_oneof() != nullptr) {
               format_(
-                  "if (!msg->has_$1$()) {\n"
-                  "  msg->clear_$1$();\n"
-                  "  msg->$2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
-                  "      ::$proto_ns$::internal::LazyField>("
-                  "msg->GetArenaNoVirtual());\n"
-                  "  msg->set_has_$1$();\n"
+                  "if (!has_$1$()) {\n"
+                  "  clear_$1$();\n"
+                  "  $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
+                  "      $pi_ns$::LazyField>("
+                  "GetArenaNoVirtual());\n"
+                  "  set_has_$1$();\n"
                   "}\n"
-                  "auto parse_closure = msg->$2$_.$1$_->_ParseClosure();\n",
+                  "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n",
                   FieldName(field), field->containing_oneof()->name());
             } else if (HasFieldPresence(field->file())) {
               format_(
-                  "HasBitSetters::set_has_$1$(msg);\n"
-                  "auto parse_closure = msg->$1$_._ParseClosure();\n",
+                  "HasBitSetters::set_has_$1$(this);\n"
+                  "ptr = ctx->ParseMessage(&$1$_, ptr);\n",
                   FieldName(field));
             } else {
-              format_("auto parse_closure = msg->$1$_._ParseClosure();\n",
-                      FieldName(field));
+              format_(
+                  "ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
             }
-            format_(
-                "parser_till_end = parse_closure.func;\n"
-                "object = parse_closure.object;\n"
-                "if (size > end - ptr) goto len_delim_till_end;\n"
-                "auto newend = ptr + size;\n"
-                "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->ParseExactRange(\n"
-                "    parse_closure, ptr, newend));\n"
-                "ptr = newend;\n");
-            break;
-          }
-          if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
+          } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
             if (!field->is_repeated()) {
-              format_("object = HasBitSetters::mutable_$1$(msg);\n",
-                      FieldName(field));
+              format_(
+                  "ptr = ctx->ParseMessage(HasBitSetters::mutable_$1$(this), "
+                  "ptr);\n",
+                  FieldName(field));
             } else {
               format_(
-                  "object = "
-                  "CastToBase(&msg->$1$_)->AddWeak(reinterpret_cast<const "
-                  "::$proto_ns$::MessageLite*>(&$2$::_$3$_default_instance_));"
-                  "\n",
+                  "ptr = ctx->ParseMessage("
+                  "CastToBase(&$1$_)->AddWeak(reinterpret_cast<const "
+                  "::$proto_ns$::MessageLite*>(&$2$::_$3$_default_instance_)), "
+                  "ptr);\n",
                   FieldName(field), Namespace(field->message_type()),
                   ClassName(field->message_type()));
             }
-            format_(
-                "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
-                "object)->_ParseFunc();\n");
           } else if (IsWeak(field, options_)) {
             if (IsProto1(field->file(), options_)) {
-              format_("object = msg->internal_mutable_$1$();\n",
-                      FieldName(field));
+              format_(
+                  "ptr = ctx->ParseMessage("
+                  "reinterpret_cast<$p_ns$::MessageLite*>(internal_mutable_$1$("
+                  ")), ptr);\n",
+                  FieldName(field));
             } else {
               format_(
-                  "object = msg->_weak_field_map_.MutableMessage($1$, "
-                  "_$classname$_default_instance_.$2$_);\n",
+                  "ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($1$,"
+                  " _$classname$_default_instance_.$2$_), ptr);\n",
                   field->number(), FieldName(field));
             }
-            format_(
-                "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
-                "object)->_ParseFunc();\n");
           } else {
-            format_(
-                "parser_till_end = $1$::_InternalParse;\n"
-                "object = msg->$2$_$3$();\n",
-                QualifiedClassName(field->message_type()),
-                field->is_repeated() ? "add" : "mutable", FieldName(field));
+            format_("ptr = ctx->ParseMessage($1$_$2$(), ptr);\n",
+                    field->is_repeated() ? "add" : "mutable", FieldName(field));
           }
-          format_(
-              "if (size > end - ptr) goto len_delim_till_end;\n"
-              "ptr += size;\n"
-              "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->ParseExactRange(\n"
-              "    {parser_till_end, object}, ptr - size, ptr));\n");
           break;
         }
         default:
@@ -1731,31 +1591,33 @@
         string prefix = field->is_repeated() ? "add" : "set";
         if (field->type() == FieldDescriptor::TYPE_ENUM &&
             !IsProto1(field->file(), options_)) {
-          format_("$uint64$ val = ::$proto_ns$::internal::ReadVarint(&ptr);\n");
+          format_(
+              "$uint64$ val = $pi_ns$::ReadVarint(&ptr);\n"
+              "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
           if (!HasPreservingUnknownEnumSemantics(field->file())) {
             format_(
                 "if (!$1$_IsValid(val)) {\n"
-                "  ::$proto_ns$::internal::WriteVarint($2$, val, "
-                "msg->mutable_unknown_fields());\n"
+                "  $pi_ns$::WriteVarint($2$, val, "
+                "mutable_unknown_fields());\n"
                 "  break;\n"
                 "}\n",
                 QualifiedClassName(field->enum_type()), field->number());
           }
-          format_("msg->$1$_$2$(static_cast<$3$>(val));\n", prefix,
-                  FieldName(field), QualifiedClassName(field->enum_type()));
+          format_("$1$_$2$(static_cast<$3$>(val));\n", prefix, FieldName(field),
+                  QualifiedClassName(field->enum_type()));
         } else {
+          int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
           string zigzag;
           if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
                field->type() == FieldDescriptor::TYPE_SINT64) &&
               !IsProto1(field->file(), options_)) {
-            int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
             zigzag = StrCat("ZigZag", size);
           }
           format_(
-              "msg->$1$_$2$(::$proto_ns$::internal::ReadVarint$3$(&ptr));\n",
+              "$1$_$2$($pi_ns$::ReadVarint$3$(&ptr));\n"
+              "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n",
               prefix, FieldName(field), zigzag);
         }
-        format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
         break;
       }
       case WireFormatLite::WIRETYPE_FIXED32:
@@ -1763,28 +1625,20 @@
         string prefix = field->is_repeated() ? "add" : "set";
         string type = PrimitiveTypeName(options_, field->cpp_type());
         format_(
-            "msg->$1$_$2$(::$proto_ns$::io::UnalignedLoad<$3$>(ptr));\n"
+            "$1$_$2$($pi_ns$::UnalignedLoad<$3$>(ptr));\n"
             "ptr += sizeof($3$);\n",
             prefix, FieldName(field), type);
         break;
       }
       case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
-        use_length_delimited_ = true;
         GenerateLengthDelim(field);
+        format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
         break;
       }
       case WireFormatLite::WIRETYPE_START_GROUP: {
-        use_group_ = true;
         format_(
-            "parser_till_end = $1$::_InternalParse;\n"
-            "object = msg->$2$_$3$();\n"
-            "auto res = ctx->ParseGroup(tag, {parser_till_end, object}, ptr, "
-            "end, "
-            "&depth);\n"
-            "ptr = res.first;\n"
-            "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
-            "if (res.second) goto group_continues;\n",
-            QualifiedClassName(field->message_type()),
+            "ptr = ctx->ParseGroup($1$_$2$(), ptr, tag);\n"
+            "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n",
             field->is_repeated() ? "add" : "mutable", FieldName(field));
         break;
       }
@@ -1795,7 +1649,6 @@
     }  // switch (wire_type)
 
     if (ShouldRepeat(field, wiretype)) {
-      format_("if (ptr >= end) break;\n");
       uint32 x = field->number() * 8 + wiretype;
       uint64 y = 0;
       int cnt = 0;
@@ -1805,10 +1658,11 @@
         x >>= 7;
       } while (x);
       uint64 mask = (1ull << (cnt * 8)) - 1;
+      format_("if (ctx->Done(&ptr)) return ptr;\n");
       format_.Outdent();
       format_(
-          "} while ((::$proto_ns$::io::UnalignedLoad<$uint64$>(ptr) & $1$) == "
-          "$2$ && (ptr += $3$));\n",
+          "} while (($pi_ns$::UnalignedLoad<$uint64$>(ptr)"
+          " & $1$) == $2$ && (ptr += $3$));\n",
           mask, y, cnt);
     }
     format_("break;\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 86e4df3..bc9ca92 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -65,15 +65,15 @@
   switch (val->cpp_type()) {
     case FieldDescriptor::CPPTYPE_MESSAGE:
       (*variables)["val_cpp"] = FieldMessageTypeName(val);
-      (*variables)["wrapper"] = "EntryWrapper";
+      (*variables)["wrapper"] = "MapEntryWrapper";
       break;
     case FieldDescriptor::CPPTYPE_ENUM:
       (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
-      (*variables)["wrapper"] = "EnumEntryWrapper";
+      (*variables)["wrapper"] = "MapEnumEntryWrapper";
       break;
     default:
       (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type());
-      (*variables)["wrapper"] = "EntryWrapper";
+      (*variables)["wrapper"] = "MapEntryWrapper";
   }
   (*variables)["key_wire_type"] =
       "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type()));
@@ -238,11 +238,9 @@
   }
 }
 
-static void GenerateSerializationLoop(const Formatter& format,
-                                      bool supports_arenas, bool string_key,
+static void GenerateSerializationLoop(const Formatter& format, bool string_key,
                                       bool string_value, bool to_array,
                                       bool is_deterministic) {
-  format("::std::unique_ptr<$map_classname$> entry;\n");
   string ptr;
   if (is_deterministic) {
     format("for (size_type i = 0; i < n; i++) {\n");
@@ -257,24 +255,17 @@
   }
   format.Indent();
 
-  format("entry.reset($name$_.New$wrapper$($1$->first, $1$->second));\n", ptr);
+  format(
+      "$map_classname$::$wrapper$ entry(nullptr, $1$->first, $1$->second);\n",
+      ptr);
   if (to_array) {
     format(
         "target = ::$proto_ns$::internal::WireFormatLite::InternalWrite"
-        "$declared_type$NoVirtualToArray($number$, *entry, target);\n");
+        "$declared_type$NoVirtualToArray($number$, entry, target);\n");
   } else {
     format(
         "::$proto_ns$::internal::WireFormatLite::Write$stream_writer$($number$,"
-        " "
-        "*entry, output);\n");
-  }
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (supports_arenas) {
-    format(
-        "if (entry->GetArena() != nullptr) {\n"
-        "  entry.release();\n"
-        "}\n");
+        " entry, output);\n");
   }
 
   if (string_key || string_value) {
@@ -365,13 +356,11 @@
       "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n",
       to_array ? "false" : "output->IsSerializationDeterministic()");
   format.Indent();
-  GenerateSerializationLoop(format, SupportsArenas(descriptor_), string_key,
-                            string_value, to_array, true);
+  GenerateSerializationLoop(format, string_key, string_value, to_array, true);
   format.Outdent();
   format("} else {\n");
   format.Indent();
-  GenerateSerializationLoop(format, SupportsArenas(descriptor_), string_key,
-                            string_value, to_array, false);
+  GenerateSerializationLoop(format, string_key, string_value, to_array, false);
   format.Outdent();
   format("}\n");
   format.Outdent();
@@ -384,35 +373,13 @@
   format(
       "total_size += $tag_size$ *\n"
       "    ::$proto_ns$::internal::FromIntSize(this->$name$_size());\n"
-      "{\n"
-      "  ::std::unique_ptr<$map_classname$> entry;\n"
-      "  for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = this->$name$().begin();\n"
-      "      it != this->$name$().end(); ++it) {\n");
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    format(
-        "    if (entry.get() != nullptr && entry->GetArena() != nullptr) {\n"
-        "      entry.release();\n"
-        "    }\n");
-  }
-
-  format(
-      "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
-      "    total_size += ::$proto_ns$::internal::WireFormatLite::\n"
-      "        $declared_type$SizeNoVirtual(*entry);\n"
-      "  }\n");
-
-  // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
-    format(
-        "  if (entry.get() != nullptr && entry->GetArena() != nullptr) {\n"
-        "    entry.release();\n"
-        "  }\n");
-  }
-
-  format("}\n");
+      "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+      "    it = this->$name$().begin();\n"
+      "    it != this->$name$().end(); ++it) {\n"
+      "  $map_classname$::$wrapper$ entry(nullptr, it->first, it->second);\n"
+      "  total_size += ::$proto_ns$::internal::WireFormatLite::\n"
+      "      $declared_type$SizeNoVirtual(entry);\n"
+      "}\n");
 }
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index ed20edd..01ab53e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -948,10 +948,6 @@
         "    ::$proto_ns$::internal::WireFormatLite::$val_wire_type$,\n"
         "    $default_enum_value$ > {\n"
         "public:\n"
-        "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
-        "static bool _ParseMap(const char* begin, const "
-        "char* end, void* object, ::$proto_ns$::internal::ParseContext* ctx);\n"
-        "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
         "  typedef ::$proto_ns$::internal::MapEntry$lite$<$classname$, \n"
         "    $key_cpp$, $val_cpp$,\n"
         "    ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
@@ -1097,20 +1093,39 @@
   if (IsAnyMessage(descriptor_, options_)) {
     format(
         "// implements Any -----------------------------------------------\n"
-        "\n"
-        "void PackFrom(const ::$proto_ns$::Message& message);\n"
-        "void PackFrom(const ::$proto_ns$::Message& message,\n"
-        "              const $string$& type_url_prefix);\n"
-        "bool UnpackTo(::$proto_ns$::Message* message) const;\n"
+        "\n");
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "void PackFrom(const ::$proto_ns$::Message& message);\n"
+          "void PackFrom(const ::$proto_ns$::Message& message,\n"
+          "              const $string$& type_url_prefix);\n"
+          "bool UnpackTo(::$proto_ns$::Message* message) const;\n"
+          "static bool GetAnyFieldDescriptors(\n"
+          "    const ::$proto_ns$::Message& message,\n"
+          "    const ::$proto_ns$::FieldDescriptor** type_url_field,\n"
+          "    const ::$proto_ns$::FieldDescriptor** value_field);\n");
+    } else {
+      format(
+          "template <typename T>\n"
+          "void PackFrom(const T& message) {\n"
+          "  _any_metadata_.PackFrom(message);\n"
+          "}\n"
+          "template <typename T>\n"
+          "void PackFrom(const T& message,\n"
+          "              const $string$& type_url_prefix) {\n"
+          "  _any_metadata_.PackFrom(message, type_url_prefix);"
+          "}\n"
+          "template <typename T>\n"
+          "bool UnpackTo(T* message) const {\n"
+          "  return _any_metadata_.UnpackTo(message);\n"
+          "}\n");
+    }
+    format(
         "template<typename T> bool Is() const {\n"
         "  return _any_metadata_.Is<T>();\n"
         "}\n"
         "static bool ParseAnyTypeUrl(const string& type_url,\n"
-        "                            string* full_type_name);\n"
-        "static bool GetAnyFieldDescriptors(\n"
-        "    const ::$proto_ns$::Message& message,\n"
-        "    const ::$proto_ns$::FieldDescriptor** type_url_field,\n"
-        "    const ::$proto_ns$::FieldDescriptor** value_field);\n");
+        "                            string* full_type_name);\n");
   }
 
   format.Set("new_final",
@@ -1166,24 +1181,13 @@
         "\n"
         "size_t ByteSizeLong() const final;\n"
         "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
-        "static const char* _InternalParse(const char* begin, const char* end, "
-        "void* object, ::$proto_ns$::internal::ParseContext* ctx);\n"
-        "::$proto_ns$::internal::ParseFunc _ParseFunc() const final { return "
-        "_InternalParse; }\n"
+        "const char* _InternalParse(const char* ptr, "
+        "::$proto_ns$::internal::ParseContext* ctx) final;\n"
         "#else\n"
         "bool MergePartialFromCodedStream(\n"
         "    ::$proto_ns$::io::CodedInputStream* input)$ "
         "merge_partial_final$;\n"
         "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n");
-    if (descriptor_->options().message_set_wire_format()) {
-      format(
-          "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
-          "static const char* InternalParseMessageSetItem(const char* begin, "
-          "const char* end, void* object, "
-          "::$proto_ns$::internal::ParseContext* "
-          "ctx);\n"
-          "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n");
-    }
 
     if (!options_.table_driven_serialization ||
         descriptor_->options().message_set_wire_format()) {
@@ -1206,10 +1210,20 @@
   format(
       "int GetCachedSize() const final { return _cached_size_.Get(); }"
       "\n\nprivate:\n"
-      "void SharedCtor();\n"
-      "void SharedDtor();\n"
+      "inline void SharedCtor();\n"
+      "inline void SharedDtor();\n"
       "void SetCachedSize(int size) const$ full_final$;\n"
       "void InternalSwap($classname$* other);\n");
+
+  format(
+      // Friend AnyMetadata so that it can call this FullMessageName() method.
+      "friend class ::$proto_ns$::internal::AnyMetadata;\n"
+      "static $1$ FullMessageName() {\n"
+      "  return \"$full_name$\";\n"
+      "}\n",
+      options_.opensource_runtime ? "::google::protobuf::StringPiece"
+                                  : "::StringPiece");
+
   if (SupportsArenas(descriptor_)) {
     format(
         // TODO(gerbens) Make this private! Currently people are deriving from
@@ -1871,65 +1885,6 @@
           "}\n"
           "\n");
     }
-    format(
-        "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
-        "bool $classname$::_ParseMap(const char* begin, const char* end, "
-        "void* object, ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "  using MF = ::$proto_ns$::internal::MapField$1$<\n"
-        "      $classname$, EntryKeyType, EntryValueType,\n"
-        "      kEntryKeyFieldType, kEntryValueFieldType,\n"
-        "      kEntryDefaultEnumValue>;\n"
-        "  auto mf = static_cast<MF*>(object);\n"
-        "  Parser<MF, ::$proto_ns$::Map<EntryKeyType, EntryValueType>> "
-        "parser(mf);\n"
-        "#define DO_(x) if (!(x)) return false\n",
-        HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite");
-    const FieldDescriptor* key = descriptor_->FindFieldByName("key");
-    const FieldDescriptor* val = descriptor_->FindFieldByName("value");
-    GOOGLE_CHECK(val);
-    string key_string;
-    string value_string;
-    if (HasFieldPresence(descriptor_->file()) &&
-        val->type() == FieldDescriptor::TYPE_ENUM) {
-      format(
-          "  DO_(parser.ParseMapEnumValidation(\n"
-          "    begin, end, ctx->extra_parse_data().field_number,\n"
-          "    static_cast<::$proto_ns$::internal::"
-          "InternalMetadataWithArena$1$*>("
-          "ctx->extra_parse_data().unknown_fields), $2$_IsValid));\n",
-          HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite",
-          QualifiedClassName(val->enum_type()));
-      key_string = "parser.entry_key()";
-      value_string = "parser.entry_value()";
-    } else {
-      format("  DO_(parser.ParseMap(begin, end));\n");
-      key_string = "parser.key()";
-      value_string = "parser.value()";
-    }
-    format.Indent();
-    if (key->type() == FieldDescriptor::TYPE_STRING) {
-      GenerateUtf8CheckCodeForString(
-          key, options_, true,
-          StrCat(key_string, ".data(), static_cast<int>(", key_string,
-                       ".length()),\n")
-              .data(),
-          format);
-    }
-    if (val->type() == FieldDescriptor::TYPE_STRING) {
-      GenerateUtf8CheckCodeForString(
-          val, options_, true,
-          StrCat(value_string, ".data(), static_cast<int>(", value_string,
-                       ".length()),\n")
-              .data(),
-          format);
-    }
-    format.Outdent();
-    format(
-        "#undef DO_\n"
-        "  return true;\n"
-        "}\n"
-        "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n");
-    format("\n");
     return;
   }
 
@@ -1942,31 +1897,34 @@
   format("}\n");
 
   if (IsAnyMessage(descriptor_, options_)) {
+    if (HasDescriptorMethods(descriptor_->file(), options_)) {
+      format(
+          "void $classname$::PackFrom(const ::$proto_ns$::Message& message) {\n"
+          "  _any_metadata_.PackFrom(message);\n"
+          "}\n"
+          "\n"
+          "void $classname$::PackFrom(const ::$proto_ns$::Message& message,\n"
+          "                           const $string$& type_url_prefix) {\n"
+          "  _any_metadata_.PackFrom(message, type_url_prefix);\n"
+          "}\n"
+          "\n"
+          "bool $classname$::UnpackTo(::$proto_ns$::Message* message) const {\n"
+          "  return _any_metadata_.UnpackTo(message);\n"
+          "}\n"
+          "bool $classname$::GetAnyFieldDescriptors(\n"
+          "    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"
+          "      message, type_url_field, value_field);\n"
+          "}\n");
+    }
     format(
-        "void $classname$::PackFrom(const ::$proto_ns$::Message& message) {\n"
-        "  _any_metadata_.PackFrom(message);\n"
-        "}\n"
-        "\n"
-        "void $classname$::PackFrom(const ::$proto_ns$::Message& message,\n"
-        "                           const $string$& type_url_prefix) {\n"
-        "  _any_metadata_.PackFrom(message, type_url_prefix);\n"
-        "}\n"
-        "\n"
-        "bool $classname$::UnpackTo(::$proto_ns$::Message* message) const {\n"
-        "  return _any_metadata_.UnpackTo(message);\n"
-        "}\n"
         "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n"
         "                                  string* full_type_name) {\n"
         "  return ::$proto_ns$::internal::ParseAnyTypeUrl(type_url,\n"
         "                                             full_type_name);\n"
         "}\n"
-        "bool $classname$::GetAnyFieldDescriptors(\n"
-        "    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"
-        "      message, type_url_field, value_field);\n"
-        "}\n"
         "\n");
   }
 
@@ -3360,21 +3318,10 @@
     // Special-case MessageSet.
     format(
         "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
-        "const char* $classname$::_InternalParse(const char* begin, const "
-        "char* end, void* object,\n"
+        "const char* $classname$::_InternalParse(const char* ptr,\n"
         "                  ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "  auto msg = static_cast<$classname$*>(object);\n"
-        "  return ::$proto_ns$::internal::ParseMessageSet(begin, end, "
-        "msg, &msg->_extensions_, &msg->_internal_metadata_, ctx);\n"
-        "}\n"
-        "const char* $classname$::InternalParseMessageSetItem(const char* "
-        "begin, const char* end, void* object,\n"
-        "                  ::$proto_ns$::internal::ParseContext* ctx) {\n"
-        "  auto msg = static_cast<$classname$*>(object);\n"
-        "  return "
-        "msg->_extensions_.ParseMessageSetItem({InternalParseMessageSetItem, "
-        "msg}, begin, end, internal_default_instance(), "
-        "&msg->_internal_metadata_, ctx);\n"
+        "  return _extensions_.ParseMessageSet(ptr, \n"
+        "      internal_default_instance(), &_internal_metadata_, ctx);\n"
         "}\n"
         "#else\n"
         "bool $classname$::MergePartialFromCodedStream(\n"
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 35c9a31..6517e5b 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -152,11 +152,11 @@
 ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {}
 
 int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {
-  return 1;
+  return GetNumBitsForMessage();
 }
 
 void ImmutableEnumFieldGenerator::
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 2b0ec29..458bf3d 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -132,7 +132,7 @@
 ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
 
 int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 void ImmutableEnumFieldLiteGenerator::
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 9aabd62..c60e8c5 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -66,11 +66,6 @@
 using internal::WireFormatLite;
 
 namespace {
-bool GenerateHasBits(const Descriptor* descriptor) {
-  return SupportFieldPresence(descriptor->file()) ||
-      HasRepeatedFields(descriptor);
-}
-
 string MapValueImmutableClassdName(const Descriptor* descriptor,
                                    ClassNameResolver* name_resolver) {
   const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
@@ -397,18 +392,16 @@
     messageGenerator.Generate(printer);
   }
 
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForMessage();
-    }
-    int totalInts = (totalBits + 31) / 32;
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print("private int $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  // Integers for bit fields.
+  int totalBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    totalBits +=
+        field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
+  }
+  int totalInts = (totalBits + 31) / 32;
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("private int $bit_field_name$;\n", "bit_field_name",
+                   GetBitFieldName(i));
   }
 
   // oneof
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index 761be79..b78f1e7 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -61,11 +61,6 @@
 namespace java {
 
 namespace {
-bool GenerateHasBits(const Descriptor* descriptor) {
-  return SupportFieldPresence(descriptor->file()) ||
-      HasRepeatedFields(descriptor);
-}
-
 string MapValueImmutableClassdName(const Descriptor* descriptor,
                                    ClassNameResolver* name_resolver) {
   const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
@@ -149,18 +144,16 @@
       "\n");
   }
 
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForBuilder();
-    }
-    int totalInts = (totalBits + 31) / 32;
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print("private int $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  // Integers for bit fields.
+  int totalBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    totalBits +=
+        field_generators_.get(descriptor_->field(i)).GetNumBitsForBuilder();
+  }
+  int totalInts = (totalBits + 31) / 32;
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("private int $bit_field_name$;\n", "bit_field_name",
+                   GetBitFieldName(i));
   }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -408,19 +401,17 @@
   int totalBuilderInts = (totalBuilderBits + 31) / 32;
   int totalMessageInts = (totalMessageBits + 31) / 32;
 
-  if (GenerateHasBits(descriptor_)) {
-    // Local vars for from and to bit fields to avoid accessing the builder and
-    // message over and over for these fields. Seems to provide a slight
-    // perforamance improvement in micro benchmark and this is also what proto1
-    // code does.
-    for (int i = 0; i < totalBuilderInts; i++) {
-      printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("int to_$bit_field_name$ = 0;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  // Local vars for from and to bit fields to avoid accessing the builder and
+  // message over and over for these fields. Seems to provide a slight
+  // perforamance improvement in micro benchmark and this is also what proto1
+  // code does.
+  for (int i = 0; i < totalBuilderInts; i++) {
+    printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
+                   "bit_field_name", GetBitFieldName(i));
+  }
+  for (int i = 0; i < totalMessageInts; i++) {
+    printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name",
+                   GetBitFieldName(i));
   }
 
   // Output generation code for each field.
@@ -428,12 +419,10 @@
     field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
   }
 
-  if (GenerateHasBits(descriptor_)) {
-    // Copy the bit field results to the generated message
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  // Copy the bit field results to the generated message
+  for (int i = 0; i < totalMessageInts; i++) {
+    printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
+                   "bit_field_name", GetBitFieldName(i));
   }
 
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
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 8987fa4..641f66a 100644
--- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -59,13 +59,6 @@
 namespace compiler {
 namespace java {
 
-namespace {
-bool GenerateHasBits(const Descriptor* descriptor) {
-  return SupportFieldPresence(descriptor->file()) ||
-      HasRepeatedFields(descriptor);
-}
-}  // namespace
-
 MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
     const Descriptor* descriptor, Context* context)
   : descriptor_(descriptor), context_(context),
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 5b6de09..d79b8c4 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -137,11 +137,11 @@
 ImmutableMessageFieldGenerator::~ImmutableMessageFieldGenerator() {}
 
 int ImmutableMessageFieldGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 int ImmutableMessageFieldGenerator::GetNumBitsForBuilder() const {
-  return 1;
+  return GetNumBitsForMessage();
 }
 
 void ImmutableMessageFieldGenerator::
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 58fbf15..8501203 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -119,7 +119,7 @@
 ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {}
 
 int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 void ImmutableMessageFieldLiteGenerator::
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 3f907e2..abc5101 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -74,11 +74,6 @@
 #endif  // !PROTOBUF_EXPERIMENT
 }
 
-bool GenerateHasBits(const Descriptor* descriptor) {
-  return SupportFieldPresence(descriptor->file()) ||
-      HasRepeatedFields(descriptor);
-}
-
 string MapValueImmutableClassdName(const Descriptor* descriptor,
                                    ClassNameResolver* name_resolver) {
   const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
@@ -233,18 +228,16 @@
     messageGenerator.Generate(printer);
   }
 
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForMessage();
-    }
-    int totalInts = (totalBits + 31) / 32;
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print("private int $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  // Integers for bit fields.
+  int totalBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    totalBits +=
+        field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
+  }
+  int totalInts = (totalBits + 31) / 32;
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("private int $bit_field_name$;\n", "bit_field_name",
+                   GetBitFieldName(i));
   }
 
   // oneof
@@ -952,20 +945,17 @@
       "oneof_name", context_->GetOneofGeneratorInfo(field)->name);
   }
 
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForMessage();
-    }
-    int totalInts = (totalBits + 31) / 32;
+  // Integers for bit fields.
+  int totalBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    totalBits +=
+        field_generators_.get(descriptor_->field(i)).GetNumBitsForMessage();
+  }
+  int totalInts = (totalBits + 31) / 32;
 
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print(
-        "$bit_field_name$ |= other.$bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
+  for (int i = 0; i < totalInts; i++) {
+    printer->Print("$bit_field_name$ |= other.$bit_field_name$;\n",
+                   "bit_field_name", GetBitFieldName(i));
   }
   printer->Outdent();
   printer->Print(
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index b3ab529..454e2eb 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -201,11 +201,11 @@
 ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {}
 
 int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {
-  return 1;
+  return GetNumBitsForMessage();
 }
 
 void ImmutablePrimitiveFieldGenerator::
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 ce34882..2dfa242 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -187,7 +187,7 @@
 ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
 
 int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 void ImmutablePrimitiveFieldLiteGenerator::
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 36676f9..55c6eec 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -304,8 +304,10 @@
     const MethodDescriptor* method = descriptor_->method(i);
     std::map<string, string> vars;
     vars["index"] = StrCat(i);
-    vars["type"] = name_resolver_->GetImmutableClassName(
-      (which == REQUEST) ? method->input_type() : method->output_type());
+    vars["type"] =
+        (which == REQUEST)
+            ? name_resolver_->GetImmutableClassName(method->input_type())
+            : GetOutput(method);
     printer->Print(vars,
       "case $index$:\n"
       "  return $type$.getDefaultInstance();\n");
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 0184297..ac4cf1f 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -154,11 +154,11 @@
 ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {}
 
 int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const {
-  return 1;
+  return GetNumBitsForMessage();
 }
 
 // A note about how strings are handled. This code used to just store a String
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 29f5d05..42c56f2 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -134,7 +134,7 @@
 ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
 
 int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
-  return 1;
+  return SupportFieldPresence(descriptor_->file()) ? 1 : 0;
 }
 
 // A note about how strings are handled. In the SPEED and CODE_SIZE runtimes,
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 71e9ba8..c513a6e 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -1135,6 +1135,10 @@
 
 string JSBinaryWriterMethodName(const GeneratorOptions& options,
                                 const FieldDescriptor* field) {
+  if (field->containing_type() &&
+      field->containing_type()->options().message_set_wire_format()) {
+    return "jspb.BinaryWriter.prototype.writeMessageSet";
+  }
   return "jspb.BinaryWriter.prototype.write" +
          JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
 }
@@ -2243,17 +2247,17 @@
       "\n"
       "if (jspb.Message.GENERATE_TO_OBJECT) {\n"
       "/**\n"
-      " * Creates an object representation of this proto suitable for use in "
-      "Soy templates.\n"
+      " * Creates an object representation of this proto.\n"
       " * Field names that are reserved in JavaScript and will be renamed to "
       "pb_name.\n"
+      " * Optional fields that are not set will be set to undefined.\n"
       " * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.\n"
       " * For the list of reserved names please see:\n"
-      " *     com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.\n"
-      " * @param {boolean=} opt_includeInstance Whether to include the JSPB "
-      "instance\n"
-      " *     for transitional soy proto support: http://goto/soy-param-"
-      "migration\n"
+      " *     net/proto2/compiler/js/internal/generator.cc#kKeyword.\n"
+      " * @param {boolean=} opt_includeInstance Deprecated. whether to include "
+      "the\n"
+      " *     JSPB instance for transitional soy proto support:\n"
+      " *     http://goto/soy-param-migration\n"
       " * @return {!Object}\n"
       " */\n"
       "$classname$.prototype.toObject = function(opt_includeInstance) {\n"
@@ -2263,16 +2267,16 @@
       "\n"
       "/**\n"
       " * Static version of the {@see toObject} method.\n"
-      " * @param {boolean|undefined} includeInstance Whether to include the "
-      "JSPB\n"
-      " *     instance for transitional soy proto support:\n"
+      " * @param {boolean|undefined} includeInstance Deprecated. Whether to "
+      "include\n"
+      " *     the JSPB instance for transitional soy proto support:\n"
       " *     http://goto/soy-param-migration\n"
       " * @param {!$classname$} msg The msg instance to transform.\n"
       " * @return {!Object}\n"
       " * @suppress {unusedLocalVariables} f is only used for nested messages\n"
       " */\n"
       "$classname$.toObject = function(includeInstance, msg) {\n"
-      "  var obj = {",
+      "  var f, obj = {",
       "classname", GetMessagePath(options, desc));
 
   bool first = true;
@@ -2424,7 +2428,39 @@
     // We are migrating the accessors to return defaults instead of null, but
     // it may take longer to migrate toObject (or we might not want to do it at
     // all).  So we want to generate independent code.
+    // The accessor for unset optional values without default should return
+    // null. Those are converted to undefined in the generated object.
+    printer->Print("(f = ");
     GenerateFieldValueExpression(printer, "msg", field, use_default);
+    printer->Print(") == null ? undefined : f");
+  }
+}
+
+void Generator::GenerateObjectTypedef(const GeneratorOptions& options,
+                                      io::Printer* printer,
+                                      const Descriptor* desc) const {
+  // TODO(b/122687752): Consider renaming nested messages called ObjectFormat
+  //     to prevent collisions.
+  const string type_name = GetMessagePath(options, desc) + ".ObjectFormat";
+
+  printer->Print(
+      "/**\n"
+      " * The raw object form of $messageName$ as accepted by the `fromObject` "
+      "method.\n"
+      " * @record\n"
+      " */\n"
+      "$typeName$ = function() {};\n\n",
+      "messageName", desc->name(),
+      "typeName", type_name);
+
+  for (int i = 0; i < desc->field_count(); i++) {
+    printer->Print(
+        "/** @type {$fieldType$|undefined} */\n"
+        "$typeName$.prototype.$fieldName$;\n\n",
+        "typeName", type_name,
+        "fieldName", JSObjectFieldName(options, desc->field(i)),
+        // TODO(b/121097361): Add type checking for field values.
+        "fieldType", "?");
   }
 }
 
@@ -2432,15 +2468,16 @@
                                         io::Printer* printer,
                                         const Descriptor* desc) const {
   printer->Print(
-      "if (jspb.Message.GENERATE_FROM_OBJECT) {\n"
+      "if (jspb.Message.GENERATE_FROM_OBJECT) {\n\n");
+
+  GenerateObjectTypedef(options, printer, desc);
+
+  printer->Print(
       "/**\n"
       " * Loads data from an object into a new instance of this proto.\n"
-      " * @param {!Object} obj The object representation of this proto to\n"
-      " *     load the data from.\n"
+      " * @param {!$classname$.ObjectFormat} obj\n"
+      " *     The object representation of this proto to load the data from.\n"
       " * @return {!$classname$}\n"
-      " * @suppress {missingProperties} To prevent JSCompiler errors at "
-      "the\n"
-      " *     `goog.isDef(obj.<fieldName>)` lookups.\n"
       " */\n"
       "$classname$.fromObject = function(obj) {\n"
       "  var msg = new $classname$();\n",
@@ -2456,7 +2493,7 @@
   printer->Print(
       "  return msg;\n"
       "};\n"
-      "}\n");
+      "}\n\n");
 }
 
 void Generator::GenerateClassFieldFromObject(
@@ -2469,7 +2506,7 @@
       // Since the map values are of message type, we have to do some extra work
       // to recursively call fromObject() on them before setting the map field.
       printer->Print(
-          "  goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
+          "  obj.$name$ && jspb.Message.setWrapperField(\n"
           "      msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, "
           "$fieldclass$.fromObject));\n",
           "name", JSObjectFieldName(options, field),
@@ -2480,7 +2517,7 @@
       // map containers wrapping underlying arrays, so we can simply directly
       // set the array here without fear of a stale wrapper.
       printer->Print(
-          "  goog.isDef(obj.$name$) && "
+          "  obj.$name$ && "
           "jspb.Message.setField(msg, $index$, obj.$name$);\n",
           "name", JSObjectFieldName(options, field),
           "index", JSFieldIndex(field));
@@ -2490,7 +2527,7 @@
     if (field->is_repeated()) {
       {
         printer->Print(
-            "  goog.isDef(obj.$name$) && "
+            "  obj.$name$ && "
             "jspb.Message.setRepeatedWrapperField(\n"
             "      msg, $index$, obj.$name$.map(\n"
             "          $fieldclass$.fromObject));\n",
@@ -2500,7 +2537,7 @@
       }
     } else {
       printer->Print(
-          "  goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
+          "  obj.$name$ && jspb.Message.setWrapperField(\n"
           "      msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
           "name", JSObjectFieldName(options, field),
           "index", JSFieldIndex(field),
@@ -2509,7 +2546,7 @@
   } else {
     // Simple (primitive) field.
     printer->Print(
-        "  goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
+        "  obj.$name$ != null && jspb.Message.setField(msg, $index$, "
         "obj.$name$);\n",
         "name", JSObjectFieldName(options, field),
         "index", JSFieldIndex(field));
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index a48750b..5af9b9f 100644
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -272,6 +272,9 @@
   void GenerateOneofCaseDefinition(const GeneratorOptions& options,
                                    io::Printer* printer,
                                    const OneofDescriptor* oneof) const;
+  void GenerateObjectTypedef(const GeneratorOptions& options,
+                             io::Printer* printer,
+                             const Descriptor* desc) const;
   void GenerateClassToObject(const GeneratorOptions& options,
                              io::Printer* printer,
                              const Descriptor* desc) const;
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 745271b..5877b9f 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -107,9 +107,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_CodeGeneratorResponse_google_2fprotobuf_2fcompiler_2fplugin_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[4];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   PROTOBUF_FIELD_OFFSET(::google::protobuf::compiler::Version, _has_bits_),
@@ -173,7 +173,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::compiler::_CodeGeneratorResponse_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, "google/protobuf/compiler/plugin.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fcompiler_2fplugin_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
@@ -197,7 +197,7 @@
   "pilerB\014PluginProtosZ9github.com/golang/p"
   "rotobuf/protoc-gen-go/plugin;plugin_go"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
   "google/protobuf/compiler/plugin.proto", &assign_descriptors_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 638,
@@ -311,77 +311,54 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Version::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Version*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Version::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional int32 major = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_major(::google::protobuf::internal::ReadVarint(&ptr));
+        set_major(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 minor = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_minor(::google::protobuf::internal::ReadVarint(&ptr));
+        set_minor(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 patch = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_patch(::google::protobuf::internal::ReadVarint(&ptr));
+        set_patch(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional string suffix = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_suffix(), ptr, ctx, "google.protobuf.compiler.Version.suffix");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.Version.suffix");
-        object = msg->mutable_suffix();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Version::MergePartialFromCodedStream(
@@ -782,104 +759,60 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* CodeGeneratorRequest::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<CodeGeneratorRequest*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated string file_to_generate = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(add_file_to_generate(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
-          object = msg->add_file_to_generate();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       // optional string parameter = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_parameter(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorRequest.parameter");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.parameter");
-        object = msg->mutable_parameter();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional .google.protobuf.compiler.Version compiler_version = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_compiler_version(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::compiler::Version::_InternalParse;
-        object = msg->mutable_compiler_version();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
       case 15: {
         if (static_cast<::google::protobuf::uint8>(tag) != 122) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_proto_file(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::FileDescriptorProto::_InternalParse;
-          object = msg->add_proto_file();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 122 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 122 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool CodeGeneratorRequest::MergePartialFromCodedStream(
@@ -1295,88 +1228,47 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* CodeGeneratorResponse_File::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<CodeGeneratorResponse_File*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string insertion_point = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_insertion_point(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
-        object = msg->mutable_insertion_point();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string content = 15;
       case 15: {
         if (static_cast<::google::protobuf::uint8>(tag) != 122) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_content(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.File.content");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.content");
-        object = msg->mutable_content();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool CodeGeneratorResponse_File::MergePartialFromCodedStream(
@@ -1742,72 +1634,43 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* CodeGeneratorResponse::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<CodeGeneratorResponse*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string error = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_error(), ptr, ctx, "google.protobuf.compiler.CodeGeneratorResponse.error");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.error");
-        object = msg->mutable_error();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
       case 15: {
         if (static_cast<::google::protobuf::uint8>(tag) != 122) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_file(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::compiler::CodeGeneratorResponse_File::_InternalParse;
-          object = msg->add_file();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 122 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 122 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool CodeGeneratorResponse::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index c84da10..0f7e8bb 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 #include <google/protobuf/descriptor.pb.h>
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
@@ -153,8 +160,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -166,10 +172,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Version* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.Version";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
@@ -306,8 +316,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -319,10 +328,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(CodeGeneratorRequest* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorRequest";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
@@ -481,8 +494,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -494,10 +506,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(CodeGeneratorResponse_File* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorResponse.File";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
@@ -642,8 +658,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -655,10 +670,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(CodeGeneratorResponse* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.compiler.CodeGeneratorResponse";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 6b1e4d2..5009b24 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -814,7 +814,7 @@
 void Generator::PrintMessages() const {
   for (int i = 0; i < file_->message_type_count(); ++i) {
     std::vector<string> to_register;
-    PrintMessage(*file_->message_type(i), "", &to_register);
+    PrintMessage(*file_->message_type(i), "", &to_register, false);
     for (int j = 0; j < to_register.size(); ++j) {
       printer_->Print("_sym_db.RegisterMessage($name$)\n", "name",
                       to_register[j]);
@@ -833,25 +833,33 @@
 // Collect nested message names to_register for the symbol_database.
 void Generator::PrintMessage(const Descriptor& message_descriptor,
                              const string& prefix,
-                             std::vector<string>* to_register) const {
+                             std::vector<string>* to_register,
+                             bool is_nested) const {
   string qualified_name(prefix + message_descriptor.name());
   to_register->push_back(qualified_name);
-  printer_->Print(
-      "$name$ = _reflection.GeneratedProtocolMessageType('$name$', "
-      "(_message.Message,), dict(\n",
-      "name", message_descriptor.name());
+  if (is_nested) {
+    printer_->Print(
+        "'$name$' : _reflection.GeneratedProtocolMessageType('$name$', "
+        "(_message.Message,), {\n",
+        "name", message_descriptor.name());
+  } else {
+    printer_->Print(
+        "$name$ = _reflection.GeneratedProtocolMessageType('$name$', "
+        "(_message.Message,), {\n",
+        "name", message_descriptor.name());
+  }
   printer_->Indent();
 
   PrintNestedMessages(message_descriptor, qualified_name + ".", to_register);
   std::map<string, string> m;
   m["descriptor_key"] = kDescriptorKey;
   m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor);
-  printer_->Print(m, "$descriptor_key$ = $descriptor_name$,\n");
-  printer_->Print("__module__ = '$module_name$'\n",
+  printer_->Print(m, "'$descriptor_key$' : $descriptor_name$,\n");
+  printer_->Print("'__module__' : '$module_name$'\n",
                   "module_name", ModuleName(file_->name()));
   printer_->Print("# @@protoc_insertion_point(class_scope:$full_name$)\n",
                   "full_name", message_descriptor.full_name());
-  printer_->Print("))\n");
+  printer_->Print("})\n");
   printer_->Outdent();
 }
 
@@ -862,7 +870,8 @@
                                     std::vector<string>* to_register) const {
   for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) {
     printer_->Print("\n");
-    PrintMessage(*containing_descriptor.nested_type(i), prefix, to_register);
+    PrintMessage(*containing_descriptor.nested_type(i), prefix, to_register,
+                 true);
     printer_->Print(",\n");
   }
 }
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index e90ff74..61f0385 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -98,7 +98,7 @@
 
   void PrintMessages() const;
   void PrintMessage(const Descriptor& message_descriptor, const std::string& prefix,
-                    std::vector<std::string>* to_register) const;
+                    std::vector<std::string>* to_register, bool is_nested) const;
   void PrintNestedMessages(const Descriptor& containing_descriptor,
                            const std::string& prefix,
                            std::vector<std::string>* to_register) const;
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index b999c1c..59321e9 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -596,9 +596,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_GeneratedCodeInfo_google_2fprotobuf_2fdescriptor_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
-const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
+static const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorSet, _has_bits_),
@@ -1045,7 +1045,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_GeneratedCodeInfo_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fdescriptor_2eproto, "google/protobuf/descriptor.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, 27, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto, file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
@@ -1204,7 +1204,7 @@
   "go/descriptor;descriptor\370\001\001\242\002\003GPB\252\002\032Goog"
   "le.Protobuf.Reflection"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fdescriptor_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
   "google/protobuf/descriptor.proto", &assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto, 6022,
@@ -1251,29 +1251,29 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32;
-const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
-const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
-const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
-const int FieldDescriptorProto::Type_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FLOAT;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_INT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_FIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BOOL;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_STRING;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_GROUP;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_MESSAGE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_BYTES;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_UINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_ENUM;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SFIXED64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX;
+constexpr int FieldDescriptorProto::Type_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[1];
@@ -1289,14 +1289,14 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
-const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
-const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
-const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
-const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
-const int FieldDescriptorProto::Label_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX;
+constexpr int FieldDescriptorProto::Label_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[2];
@@ -1312,14 +1312,14 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const FileOptions_OptimizeMode FileOptions::SPEED;
-const FileOptions_OptimizeMode FileOptions::CODE_SIZE;
-const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
-const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
-const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
-const int FileOptions::OptimizeMode_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr FileOptions_OptimizeMode FileOptions::SPEED;
+constexpr FileOptions_OptimizeMode FileOptions::CODE_SIZE;
+constexpr FileOptions_OptimizeMode FileOptions::LITE_RUNTIME;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN;
+constexpr FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX;
+constexpr int FileOptions::OptimizeMode_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[3];
@@ -1335,14 +1335,14 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const FieldOptions_CType FieldOptions::STRING;
-const FieldOptions_CType FieldOptions::CORD;
-const FieldOptions_CType FieldOptions::STRING_PIECE;
-const FieldOptions_CType FieldOptions::CType_MIN;
-const FieldOptions_CType FieldOptions::CType_MAX;
-const int FieldOptions::CType_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr FieldOptions_CType FieldOptions::STRING;
+constexpr FieldOptions_CType FieldOptions::CORD;
+constexpr FieldOptions_CType FieldOptions::STRING_PIECE;
+constexpr FieldOptions_CType FieldOptions::CType_MIN;
+constexpr FieldOptions_CType FieldOptions::CType_MAX;
+constexpr int FieldOptions::CType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[4];
@@ -1358,14 +1358,14 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const FieldOptions_JSType FieldOptions::JS_NORMAL;
-const FieldOptions_JSType FieldOptions::JS_STRING;
-const FieldOptions_JSType FieldOptions::JS_NUMBER;
-const FieldOptions_JSType FieldOptions::JSType_MIN;
-const FieldOptions_JSType FieldOptions::JSType_MAX;
-const int FieldOptions::JSType_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr FieldOptions_JSType FieldOptions::JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions::JS_STRING;
+constexpr FieldOptions_JSType FieldOptions::JS_NUMBER;
+constexpr FieldOptions_JSType FieldOptions::JSType_MIN;
+constexpr FieldOptions_JSType FieldOptions::JSType_MAX;
+constexpr int FieldOptions::JSType_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[5];
@@ -1381,14 +1381,14 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN;
-const MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS;
-const MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT;
-const MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
-const MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
-const int MethodOptions::IdempotencyLevel_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::NO_SIDE_EFFECTS;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IDEMPOTENT;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
+constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 
 // ===================================================================
 
@@ -1465,52 +1465,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FileDescriptorSet::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FileDescriptorSet*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FileDescriptorSet::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.FileDescriptorProto file = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_file(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::FileDescriptorProto::_InternalParse;
-          object = msg->add_file();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FileDescriptorSet::MergePartialFromCodedStream(
@@ -1919,237 +1903,139 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FileDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FileDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FileDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.FileDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string package = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_package(), ptr, ctx, "google.protobuf.FileDescriptorProto.package");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.package");
-        object = msg->mutable_package();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated string dependency = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(add_dependency(), ptr, ctx, "google.protobuf.FileDescriptorProto.dependency");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.dependency");
-          object = msg->add_dependency();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.DescriptorProto message_type = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_message_type(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::DescriptorProto::_InternalParse;
-          object = msg->add_message_type();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_enum_type(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::EnumDescriptorProto::_InternalParse;
-          object = msg->add_enum_type();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.ServiceDescriptorProto service = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_service(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::ServiceDescriptorProto::_InternalParse;
-          object = msg->add_service();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.FieldDescriptorProto extension = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_extension(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::FieldDescriptorProto::_InternalParse;
-          object = msg->add_extension();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 58 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 58 && (ptr += 1));
         break;
       }
       // optional .google.protobuf.FileOptions options = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::FileOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
       case 9: {
         if (static_cast<::google::protobuf::uint8>(tag) != 74) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_source_code_info(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::SourceCodeInfo::_InternalParse;
-        object = msg->mutable_source_code_info();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // repeated int32 public_dependency = 10;
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) == 80) {
           do {
-            msg->add_public_dependency(::google::protobuf::internal::ReadVarint(&ptr));
+            add_public_dependency(::google::protobuf::internal::ReadVarint(&ptr));
             GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-            if (ptr >= end) break;
-          } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 80 && (ptr += 1));
+            if (ctx->Done(&ptr)) return ptr;
+          } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 80 && (ptr += 1));
           break;
         } else if (static_cast<::google::protobuf::uint8>(tag) != 82) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::PackedInt32Parser(mutable_public_dependency(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::internal::PackedInt32Parser;
-        object = msg->mutable_public_dependency();
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
         break;
       }
       // repeated int32 weak_dependency = 11;
       case 11: {
         if (static_cast<::google::protobuf::uint8>(tag) == 88) {
           do {
-            msg->add_weak_dependency(::google::protobuf::internal::ReadVarint(&ptr));
+            add_weak_dependency(::google::protobuf::internal::ReadVarint(&ptr));
             GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-            if (ptr >= end) break;
-          } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 88 && (ptr += 1));
+            if (ctx->Done(&ptr)) return ptr;
+          } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 88 && (ptr += 1));
           break;
         } else if (static_cast<::google::protobuf::uint8>(tag) != 90) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::PackedInt32Parser(mutable_weak_dependency(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::internal::PackedInt32Parser;
-        object = msg->mutable_weak_dependency();
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
         break;
       }
       // optional string syntax = 12;
       case 12: {
         if (static_cast<::google::protobuf::uint8>(tag) != 98) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_syntax(), ptr, ctx, "google.protobuf.FileDescriptorProto.syntax");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.syntax");
-        object = msg->mutable_syntax();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FileDescriptorProto::MergePartialFromCodedStream(
@@ -2939,63 +2825,47 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* DescriptorProto_ExtensionRange::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<DescriptorProto_ExtensionRange*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_start(::google::protobuf::internal::ReadVarint(&ptr));
+        set_start(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 end = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_end(::google::protobuf::internal::ReadVarint(&ptr));
+        set_end(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional .google.protobuf.ExtensionRangeOptions options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::ExtensionRangeOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream(
@@ -3351,43 +3221,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* DescriptorProto_ReservedRange::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<DescriptorProto_ReservedRange*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_start(::google::protobuf::internal::ReadVarint(&ptr));
+        set_start(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 end = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_end(::google::protobuf::internal::ReadVarint(&ptr));
+        set_end(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -3775,200 +3638,120 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* DescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<DescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* DescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.DescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.FieldDescriptorProto field = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_field(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::FieldDescriptorProto::_InternalParse;
-          object = msg->add_field();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.DescriptorProto nested_type = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_nested_type(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::DescriptorProto::_InternalParse;
-          object = msg->add_nested_type();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_enum_type(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::EnumDescriptorProto::_InternalParse;
-          object = msg->add_enum_type();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_extension_range(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::DescriptorProto_ExtensionRange::_InternalParse;
-          object = msg->add_extension_range();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.FieldDescriptorProto extension = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_extension(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::FieldDescriptorProto::_InternalParse;
-          object = msg->add_extension();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
       }
       // optional .google.protobuf.MessageOptions options = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::MessageOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_oneof_decl(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::OneofDescriptorProto::_InternalParse;
-          object = msg->add_oneof_decl();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 66 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 66 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
       case 9: {
         if (static_cast<::google::protobuf::uint8>(tag) != 74) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_reserved_range(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::DescriptorProto_ReservedRange::_InternalParse;
-          object = msg->add_reserved_range();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 74 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 74 && (ptr += 1));
         break;
       }
       // repeated string reserved_name = 10;
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) != 82) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(add_reserved_name(), ptr, ctx, "google.protobuf.DescriptorProto.reserved_name");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.reserved_name");
-          object = msg->add_reserved_name();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 82 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 82 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool DescriptorProto::MergePartialFromCodedStream(
@@ -4631,60 +4414,42 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ExtensionRangeOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<ExtensionRangeOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool ExtensionRangeOptions::MergePartialFromCodedStream(
@@ -5110,54 +4875,30 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FieldDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FieldDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.FieldDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string extendee = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_extendee(), ptr, ctx, "google.protobuf.FieldDescriptorProto.extendee");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.extendee");
-        object = msg->mutable_extendee();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional int32 number = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_number(::google::protobuf::internal::ReadVarint(&ptr));
+        set_number(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -5165,116 +4906,75 @@
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 32) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::FieldDescriptorProto_Label_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(4, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(4, val, mutable_unknown_fields());
           break;
         }
-        msg->set_label(static_cast<::google::protobuf::FieldDescriptorProto_Label>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_label(static_cast<::google::protobuf::FieldDescriptorProto_Label>(val));
         break;
       }
       // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::FieldDescriptorProto_Type_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(5, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(5, val, mutable_unknown_fields());
           break;
         }
-        msg->set_type(static_cast<::google::protobuf::FieldDescriptorProto_Type>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_type(static_cast<::google::protobuf::FieldDescriptorProto_Type>(val));
         break;
       }
       // optional string type_name = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_type_name(), ptr, ctx, "google.protobuf.FieldDescriptorProto.type_name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.type_name");
-        object = msg->mutable_type_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string default_value = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_default_value(), ptr, ctx, "google.protobuf.FieldDescriptorProto.default_value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.default_value");
-        object = msg->mutable_default_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional .google.protobuf.FieldOptions options = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::FieldOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // optional int32 oneof_index = 9;
       case 9: {
         if (static_cast<::google::protobuf::uint8>(tag) != 72) goto handle_unusual;
-        msg->set_oneof_index(::google::protobuf::internal::ReadVarint(&ptr));
+        set_oneof_index(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional string json_name = 10;
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) != 82) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_json_name(), ptr, ctx, "google.protobuf.FieldDescriptorProto.json_name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.json_name");
-        object = msg->mutable_json_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FieldDescriptorProto::MergePartialFromCodedStream(
@@ -5991,69 +5691,40 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* OneofDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<OneofDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.OneofDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.OneofDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional .google.protobuf.OneofOptions options = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::OneofOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool OneofDescriptorProto::MergePartialFromCodedStream(
@@ -6388,43 +6059,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumDescriptorProto_EnumReservedRange*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional int32 start = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_start(::google::protobuf::internal::ReadVarint(&ptr));
+        set_start(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 end = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_end(::google::protobuf::internal::ReadVarint(&ptr));
+        set_end(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -6792,120 +6456,70 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.EnumDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_value(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::EnumValueDescriptorProto::_InternalParse;
-          object = msg->add_value();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // optional .google.protobuf.EnumOptions options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::EnumOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_reserved_range(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::EnumDescriptorProto_EnumReservedRange::_InternalParse;
-          object = msg->add_reserved_range();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
         break;
       }
       // repeated string reserved_name = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(add_reserved_name(), ptr, ctx, "google.protobuf.EnumDescriptorProto.reserved_name");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.reserved_name");
-          object = msg->add_reserved_name();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool EnumDescriptorProto::MergePartialFromCodedStream(
@@ -7411,76 +7025,47 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumValueDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumValueDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.EnumValueDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValueDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional int32 number = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_number(::google::protobuf::internal::ReadVarint(&ptr));
+        set_number(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional .google.protobuf.EnumValueOptions options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::EnumValueOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool EnumValueDescriptorProto::MergePartialFromCodedStream(
@@ -7888,85 +7473,50 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ServiceDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<ServiceDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.ServiceDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.ServiceDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.MethodDescriptorProto method = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_method(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::MethodDescriptorProto::_InternalParse;
-          object = msg->add_method();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // optional .google.protobuf.ServiceOptions options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::ServiceOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool ServiceDescriptorProto::MergePartialFromCodedStream(
@@ -8421,115 +7971,68 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* MethodDescriptorProto::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<MethodDescriptorProto*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name(), ptr, ctx, "google.protobuf.MethodDescriptorProto.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string input_type = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_input_type(), ptr, ctx, "google.protobuf.MethodDescriptorProto.input_type");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.input_type");
-        object = msg->mutable_input_type();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string output_type = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_output_type(), ptr, ctx, "google.protobuf.MethodDescriptorProto.output_type");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.output_type");
-        object = msg->mutable_output_type();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional .google.protobuf.MethodOptions options = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_options(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::MethodOptions::_InternalParse;
-        object = msg->mutable_options();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // optional bool client_streaming = 5 [default = false];
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
-        msg->set_client_streaming(::google::protobuf::internal::ReadVarint(&ptr));
+        set_client_streaming(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool server_streaming = 6 [default = false];
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 48) goto handle_unusual;
-        msg->set_server_streaming(::google::protobuf::internal::ReadVarint(&ptr));
+        set_server_streaming(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool MethodDescriptorProto::MergePartialFromCodedStream(
@@ -9217,299 +8720,187 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FileOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FileOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FileOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional string java_package = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_java_package(), ptr, ctx, "google.protobuf.FileOptions.java_package");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_package");
-        object = msg->mutable_java_package();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string java_outer_classname = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_java_outer_classname(), ptr, ctx, "google.protobuf.FileOptions.java_outer_classname");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_outer_classname");
-        object = msg->mutable_java_outer_classname();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
       case 9: {
         if (static_cast<::google::protobuf::uint8>(tag) != 72) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::FileOptions_OptimizeMode_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(9, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(9, val, mutable_unknown_fields());
           break;
         }
-        msg->set_optimize_for(static_cast<::google::protobuf::FileOptions_OptimizeMode>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_optimize_for(static_cast<::google::protobuf::FileOptions_OptimizeMode>(val));
         break;
       }
       // optional bool java_multiple_files = 10 [default = false];
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) != 80) goto handle_unusual;
-        msg->set_java_multiple_files(::google::protobuf::internal::ReadVarint(&ptr));
+        set_java_multiple_files(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional string go_package = 11;
       case 11: {
         if (static_cast<::google::protobuf::uint8>(tag) != 90) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_go_package(), ptr, ctx, "google.protobuf.FileOptions.go_package");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.go_package");
-        object = msg->mutable_go_package();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional bool cc_generic_services = 16 [default = false];
       case 16: {
         if (static_cast<::google::protobuf::uint8>(tag) != 128) goto handle_unusual;
-        msg->set_cc_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
+        set_cc_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool java_generic_services = 17 [default = false];
       case 17: {
         if (static_cast<::google::protobuf::uint8>(tag) != 136) goto handle_unusual;
-        msg->set_java_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
+        set_java_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool py_generic_services = 18 [default = false];
       case 18: {
         if (static_cast<::google::protobuf::uint8>(tag) != 144) goto handle_unusual;
-        msg->set_py_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
+        set_py_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
       case 20: {
         if (static_cast<::google::protobuf::uint8>(tag) != 160) goto handle_unusual;
-        msg->set_java_generate_equals_and_hash(::google::protobuf::internal::ReadVarint(&ptr));
+        set_java_generate_equals_and_hash(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool deprecated = 23 [default = false];
       case 23: {
         if (static_cast<::google::protobuf::uint8>(tag) != 184) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool java_string_check_utf8 = 27 [default = false];
       case 27: {
         if (static_cast<::google::protobuf::uint8>(tag) != 216) goto handle_unusual;
-        msg->set_java_string_check_utf8(::google::protobuf::internal::ReadVarint(&ptr));
+        set_java_string_check_utf8(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool cc_enable_arenas = 31 [default = false];
       case 31: {
         if (static_cast<::google::protobuf::uint8>(tag) != 248) goto handle_unusual;
-        msg->set_cc_enable_arenas(::google::protobuf::internal::ReadVarint(&ptr));
+        set_cc_enable_arenas(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional string objc_class_prefix = 36;
       case 36: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_objc_class_prefix(), ptr, ctx, "google.protobuf.FileOptions.objc_class_prefix");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.objc_class_prefix");
-        object = msg->mutable_objc_class_prefix();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string csharp_namespace = 37;
       case 37: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_csharp_namespace(), ptr, ctx, "google.protobuf.FileOptions.csharp_namespace");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.csharp_namespace");
-        object = msg->mutable_csharp_namespace();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string swift_prefix = 39;
       case 39: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_swift_prefix(), ptr, ctx, "google.protobuf.FileOptions.swift_prefix");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.swift_prefix");
-        object = msg->mutable_swift_prefix();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string php_class_prefix = 40;
       case 40: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_php_class_prefix(), ptr, ctx, "google.protobuf.FileOptions.php_class_prefix");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_class_prefix");
-        object = msg->mutable_php_class_prefix();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string php_namespace = 41;
       case 41: {
         if (static_cast<::google::protobuf::uint8>(tag) != 74) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_php_namespace(), ptr, ctx, "google.protobuf.FileOptions.php_namespace");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_namespace");
-        object = msg->mutable_php_namespace();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional bool php_generic_services = 42 [default = false];
       case 42: {
         if (static_cast<::google::protobuf::uint8>(tag) != 80) goto handle_unusual;
-        msg->set_php_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
+        set_php_generic_services(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional string php_metadata_namespace = 44;
       case 44: {
         if (static_cast<::google::protobuf::uint8>(tag) != 98) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_php_metadata_namespace(), ptr, ctx, "google.protobuf.FileOptions.php_metadata_namespace");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_metadata_namespace");
-        object = msg->mutable_php_metadata_namespace();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string ruby_package = 45;
       case 45: {
         if (static_cast<::google::protobuf::uint8>(tag) != 106) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_ruby_package(), ptr, ctx, "google.protobuf.FileOptions.ruby_package");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.ruby_package");
-        object = msg->mutable_ruby_package();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FileOptions::MergePartialFromCodedStream(
@@ -10654,43 +10045,37 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* MessageOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<MessageOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* MessageOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional bool message_set_wire_format = 1 [default = false];
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_message_set_wire_format(::google::protobuf::internal::ReadVarint(&ptr));
+        set_message_set_wire_format(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool no_standard_descriptor_accessor = 2 [default = false];
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_no_standard_descriptor_accessor(::google::protobuf::internal::ReadVarint(&ptr));
+        set_no_standard_descriptor_accessor(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool deprecated = 3 [default = false];
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool map_entry = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 56) goto handle_unusual;
-        msg->set_map_entry(::google::protobuf::internal::ReadVarint(&ptr));
+        set_map_entry(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -10698,44 +10083,32 @@
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool MessageOptions::MergePartialFromCodedStream(
@@ -11201,48 +10574,42 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FieldOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FieldOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FieldOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::FieldOptions_CType_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(1, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(1, val, mutable_unknown_fields());
           break;
         }
-        msg->set_ctype(static_cast<::google::protobuf::FieldOptions_CType>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_ctype(static_cast<::google::protobuf::FieldOptions_CType>(val));
         break;
       }
       // optional bool packed = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_packed(::google::protobuf::internal::ReadVarint(&ptr));
+        set_packed(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool deprecated = 3 [default = false];
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool lazy = 5 [default = false];
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
-        msg->set_lazy(::google::protobuf::internal::ReadVarint(&ptr));
+        set_lazy(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -11250,18 +10617,18 @@
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 48) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::FieldOptions_JSType_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(6, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(6, val, mutable_unknown_fields());
           break;
         }
-        msg->set_jstype(static_cast<::google::protobuf::FieldOptions_JSType>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_jstype(static_cast<::google::protobuf::FieldOptions_JSType>(val));
         break;
       }
       // optional bool weak = 10 [default = false];
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) != 80) goto handle_unusual;
-        msg->set_weak(::google::protobuf::internal::ReadVarint(&ptr));
+        set_weak(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -11269,44 +10636,32 @@
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FieldOptions::MergePartialFromCodedStream(
@@ -11818,60 +11173,42 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* OneofOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<OneofOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* OneofOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool OneofOptions::MergePartialFromCodedStream(
@@ -12181,29 +11518,23 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional bool allow_alias = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_allow_alias(::google::protobuf::internal::ReadVarint(&ptr));
+        set_allow_alias(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional bool deprecated = 3 [default = false];
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -12211,44 +11542,32 @@
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool EnumOptions::MergePartialFromCodedStream(
@@ -12621,22 +11940,16 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumValueOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumValueOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumValueOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional bool deprecated = 1 [default = false];
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -12644,44 +11957,32 @@
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool EnumValueOptions::MergePartialFromCodedStream(
@@ -13016,22 +12317,16 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ServiceOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<ServiceOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* ServiceOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional bool deprecated = 33 [default = false];
       case 33: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -13039,44 +12334,32 @@
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool ServiceOptions::MergePartialFromCodedStream(
@@ -13424,22 +12707,16 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* MethodOptions::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<MethodOptions*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* MethodOptions::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // optional bool deprecated = 33 [default = false];
       case 33: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
+        set_deprecated(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -13447,56 +12724,44 @@
       case 34: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         if (!::google::protobuf::MethodOptions_IdempotencyLevel_IsValid(val)) {
-          ::google::protobuf::internal::WriteVarint(34, val, msg->mutable_unknown_fields());
+          ::google::protobuf::internal::WriteVarint(34, val, mutable_unknown_fields());
           break;
         }
-        msg->set_idempotency_level(static_cast<::google::protobuf::MethodOptions_IdempotencyLevel>(val));
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_idempotency_level(static_cast<::google::protobuf::MethodOptions_IdempotencyLevel>(val));
         break;
       }
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
       case 999: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_uninterpreted_option(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption::_InternalParse;
-          object = msg->add_uninterpreted_option();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 65535) == 16058 && (ptr += 2));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
-        auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
-            internal_default_instance(), &msg->_internal_metadata_, ctx);
-        ptr = res.first;
+        ptr = _extensions_.ParseField(tag, ptr, 
+            internal_default_instance(), &_internal_metadata_, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
-        continue;
+        break;
       }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool MethodOptions::MergePartialFromCodedStream(
@@ -13886,63 +13151,40 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* UninterpretedOption_NamePart::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<UninterpretedOption_NamePart*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // required string name_part = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_name_part(), ptr, ctx, "google.protobuf.UninterpretedOption.NamePart.name_part");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.NamePart.name_part");
-        object = msg->mutable_name_part();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // required bool is_extension = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_is_extension(::google::protobuf::internal::ReadVarint(&ptr));
+        set_is_extension(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool UninterpretedOption_NamePart::MergePartialFromCodedStream(
@@ -14342,124 +13584,78 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* UninterpretedOption::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<UninterpretedOption*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* UninterpretedOption::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_name(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::UninterpretedOption_NamePart::_InternalParse;
-          object = msg->add_name();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // optional string identifier_value = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_identifier_value(), ptr, ctx, "google.protobuf.UninterpretedOption.identifier_value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.identifier_value");
-        object = msg->mutable_identifier_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional uint64 positive_int_value = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 32) goto handle_unusual;
-        msg->set_positive_int_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_positive_int_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int64 negative_int_value = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
-        msg->set_negative_int_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_negative_int_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional double double_value = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 49) goto handle_unusual;
-        msg->set_double_value(::google::protobuf::io::UnalignedLoad<double>(ptr));
+        set_double_value(::google::protobuf::internal::UnalignedLoad<double>(ptr));
         ptr += sizeof(double);
         break;
       }
       // optional bytes string_value = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParser(mutable_string_value(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        object = msg->mutable_string_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string aggregate_value = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 66) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_aggregate_value(), ptr, ctx, "google.protobuf.UninterpretedOption.aggregate_value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.aggregate_value");
-        object = msg->mutable_aggregate_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool UninterpretedOption::MergePartialFromCodedStream(
@@ -15008,131 +14204,78 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* SourceCodeInfo_Location::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<SourceCodeInfo_Location*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated int32 path = 1 [packed = true];
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) == 10) {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::PackedInt32Parser(mutable_path(), ptr, ctx);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::internal::PackedInt32Parser;
-          object = msg->mutable_path();
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
           break;
         } else if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
         do {
-          msg->add_path(::google::protobuf::internal::ReadVarint(&ptr));
+          add_path(::google::protobuf::internal::ReadVarint(&ptr));
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 8 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 8 && (ptr += 1));
         break;
       }
       // repeated int32 span = 2 [packed = true];
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) == 18) {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::PackedInt32Parser(mutable_span(), ptr, ctx);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::internal::PackedInt32Parser;
-          object = msg->mutable_span();
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
           break;
         } else if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
         do {
-          msg->add_span(::google::protobuf::internal::ReadVarint(&ptr));
+          add_span(::google::protobuf::internal::ReadVarint(&ptr));
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 16 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 16 && (ptr += 1));
         break;
       }
       // optional string leading_comments = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_leading_comments(), ptr, ctx, "google.protobuf.SourceCodeInfo.Location.leading_comments");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_comments");
-        object = msg->mutable_leading_comments();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional string trailing_comments = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_trailing_comments(), ptr, ctx, "google.protobuf.SourceCodeInfo.Location.trailing_comments");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.trailing_comments");
-        object = msg->mutable_trailing_comments();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated string leading_detached_comments = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(add_leading_detached_comments(), ptr, ctx, "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
-          object = msg->add_leading_detached_comments();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool SourceCodeInfo_Location::MergePartialFromCodedStream(
@@ -15623,52 +14766,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* SourceCodeInfo::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<SourceCodeInfo*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* SourceCodeInfo::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_location(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::SourceCodeInfo_Location::_InternalParse;
-          object = msg->add_location();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool SourceCodeInfo::MergePartialFromCodedStream(
@@ -15970,90 +15097,61 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<GeneratedCodeInfo_Annotation*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated int32 path = 1 [packed = true];
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) == 10) {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::PackedInt32Parser(mutable_path(), ptr, ctx);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::internal::PackedInt32Parser;
-          object = msg->mutable_path();
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
           break;
         } else if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
         do {
-          msg->add_path(::google::protobuf::internal::ReadVarint(&ptr));
+          add_path(::google::protobuf::internal::ReadVarint(&ptr));
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 8 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 8 && (ptr += 1));
         break;
       }
       // optional string source_file = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8Verify(mutable_source_file(), ptr, ctx, "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.GeneratedCodeInfo.Annotation.source_file");
-        object = msg->mutable_source_file();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // optional int32 begin = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_begin(::google::protobuf::internal::ReadVarint(&ptr));
+        set_begin(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // optional int32 end = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 32) goto handle_unusual;
-        msg->set_end(::google::protobuf::internal::ReadVarint(&ptr));
+        set_end(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream(
@@ -16462,52 +15560,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* GeneratedCodeInfo::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<GeneratedCodeInfo*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_annotation(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::GeneratedCodeInfo_Annotation::_InternalParse;
-          object = msg->add_annotation();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool GeneratedCodeInfo::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 1860184..7df5d38 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -32,6 +32,13 @@
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fdescriptor_2eproto PROTOBUF_EXPORT
@@ -185,9 +192,9 @@
   FieldDescriptorProto_Type_TYPE_SINT64 = 18
 };
 PROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
-const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
-const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
-const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
+constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
+constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
 inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) {
@@ -205,9 +212,9 @@
   FieldDescriptorProto_Label_LABEL_REPEATED = 3
 };
 PROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
-const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
-const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
-const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
+constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
+constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
 inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) {
@@ -225,9 +232,9 @@
   FileOptions_OptimizeMode_LITE_RUNTIME = 3
 };
 PROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
-const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
-const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
-const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1;
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
+constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
+constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
 inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) {
@@ -245,9 +252,9 @@
   FieldOptions_CType_STRING_PIECE = 2
 };
 PROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
-const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING;
-const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
-const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1;
+constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING;
+constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
+constexpr int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor();
 inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) {
@@ -265,9 +272,9 @@
   FieldOptions_JSType_JS_NUMBER = 2
 };
 PROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
-const FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
-const FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
-const int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
+constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
+constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor();
 inline const ::std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) {
@@ -285,9 +292,9 @@
   MethodOptions_IdempotencyLevel_IDEMPOTENT = 2
 };
 PROTOBUF_EXPORT bool MethodOptions_IdempotencyLevel_IsValid(int value);
-const MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
-const MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT;
-const int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1;
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
+constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT;
+constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor();
 inline const ::std::string& MethodOptions_IdempotencyLevel_Name(MethodOptions_IdempotencyLevel value) {
@@ -378,8 +385,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -391,10 +397,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FileDescriptorSet* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorSet";
+  }
   protected:
   explicit FileDescriptorSet(::google::protobuf::Arena* arena);
   private:
@@ -519,8 +529,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -532,10 +541,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FileDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FileDescriptorProto";
+  }
   protected:
   explicit FileDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -849,8 +862,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -862,10 +874,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(DescriptorProto_ExtensionRange* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ExtensionRange";
+  }
   protected:
   explicit DescriptorProto_ExtensionRange(::google::protobuf::Arena* arena);
   private:
@@ -1006,8 +1022,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1019,10 +1034,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(DescriptorProto_ReservedRange* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto.ReservedRange";
+  }
   protected:
   explicit DescriptorProto_ReservedRange(::google::protobuf::Arena* arena);
   private:
@@ -1150,8 +1169,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1163,10 +1181,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(DescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.DescriptorProto";
+  }
   protected:
   explicit DescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -1433,8 +1455,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1446,10 +1467,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(ExtensionRangeOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.ExtensionRangeOptions";
+  }
   protected:
   explicit ExtensionRangeOptions(::google::protobuf::Arena* arena);
   private:
@@ -1577,8 +1602,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1590,10 +1614,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FieldDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FieldDescriptorProto";
+  }
   protected:
   explicit FieldDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -1613,50 +1641,50 @@
   // nested types ----------------------------------------------------
 
   typedef FieldDescriptorProto_Type Type;
-  static const Type TYPE_DOUBLE =
+  static constexpr Type TYPE_DOUBLE =
     FieldDescriptorProto_Type_TYPE_DOUBLE;
-  static const Type TYPE_FLOAT =
+  static constexpr Type TYPE_FLOAT =
     FieldDescriptorProto_Type_TYPE_FLOAT;
-  static const Type TYPE_INT64 =
+  static constexpr Type TYPE_INT64 =
     FieldDescriptorProto_Type_TYPE_INT64;
-  static const Type TYPE_UINT64 =
+  static constexpr Type TYPE_UINT64 =
     FieldDescriptorProto_Type_TYPE_UINT64;
-  static const Type TYPE_INT32 =
+  static constexpr Type TYPE_INT32 =
     FieldDescriptorProto_Type_TYPE_INT32;
-  static const Type TYPE_FIXED64 =
+  static constexpr Type TYPE_FIXED64 =
     FieldDescriptorProto_Type_TYPE_FIXED64;
-  static const Type TYPE_FIXED32 =
+  static constexpr Type TYPE_FIXED32 =
     FieldDescriptorProto_Type_TYPE_FIXED32;
-  static const Type TYPE_BOOL =
+  static constexpr Type TYPE_BOOL =
     FieldDescriptorProto_Type_TYPE_BOOL;
-  static const Type TYPE_STRING =
+  static constexpr Type TYPE_STRING =
     FieldDescriptorProto_Type_TYPE_STRING;
-  static const Type TYPE_GROUP =
+  static constexpr Type TYPE_GROUP =
     FieldDescriptorProto_Type_TYPE_GROUP;
-  static const Type TYPE_MESSAGE =
+  static constexpr Type TYPE_MESSAGE =
     FieldDescriptorProto_Type_TYPE_MESSAGE;
-  static const Type TYPE_BYTES =
+  static constexpr Type TYPE_BYTES =
     FieldDescriptorProto_Type_TYPE_BYTES;
-  static const Type TYPE_UINT32 =
+  static constexpr Type TYPE_UINT32 =
     FieldDescriptorProto_Type_TYPE_UINT32;
-  static const Type TYPE_ENUM =
+  static constexpr Type TYPE_ENUM =
     FieldDescriptorProto_Type_TYPE_ENUM;
-  static const Type TYPE_SFIXED32 =
+  static constexpr Type TYPE_SFIXED32 =
     FieldDescriptorProto_Type_TYPE_SFIXED32;
-  static const Type TYPE_SFIXED64 =
+  static constexpr Type TYPE_SFIXED64 =
     FieldDescriptorProto_Type_TYPE_SFIXED64;
-  static const Type TYPE_SINT32 =
+  static constexpr Type TYPE_SINT32 =
     FieldDescriptorProto_Type_TYPE_SINT32;
-  static const Type TYPE_SINT64 =
+  static constexpr Type TYPE_SINT64 =
     FieldDescriptorProto_Type_TYPE_SINT64;
   static inline bool Type_IsValid(int value) {
     return FieldDescriptorProto_Type_IsValid(value);
   }
-  static const Type Type_MIN =
+  static constexpr Type Type_MIN =
     FieldDescriptorProto_Type_Type_MIN;
-  static const Type Type_MAX =
+  static constexpr Type Type_MAX =
     FieldDescriptorProto_Type_Type_MAX;
-  static const int Type_ARRAYSIZE =
+  static constexpr int Type_ARRAYSIZE =
     FieldDescriptorProto_Type_Type_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   Type_descriptor() {
@@ -1671,20 +1699,20 @@
   }
 
   typedef FieldDescriptorProto_Label Label;
-  static const Label LABEL_OPTIONAL =
+  static constexpr Label LABEL_OPTIONAL =
     FieldDescriptorProto_Label_LABEL_OPTIONAL;
-  static const Label LABEL_REQUIRED =
+  static constexpr Label LABEL_REQUIRED =
     FieldDescriptorProto_Label_LABEL_REQUIRED;
-  static const Label LABEL_REPEATED =
+  static constexpr Label LABEL_REPEATED =
     FieldDescriptorProto_Label_LABEL_REPEATED;
   static inline bool Label_IsValid(int value) {
     return FieldDescriptorProto_Label_IsValid(value);
   }
-  static const Label Label_MIN =
+  static constexpr Label Label_MIN =
     FieldDescriptorProto_Label_Label_MIN;
-  static const Label Label_MAX =
+  static constexpr Label Label_MAX =
     FieldDescriptorProto_Label_Label_MAX;
-  static const int Label_ARRAYSIZE =
+  static constexpr int Label_ARRAYSIZE =
     FieldDescriptorProto_Label_Label_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   Label_descriptor() {
@@ -1961,8 +1989,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1974,10 +2001,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(OneofDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.OneofDescriptorProto";
+  }
   protected:
   explicit OneofDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -2127,8 +2158,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -2140,10 +2170,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumDescriptorProto_EnumReservedRange* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto.EnumReservedRange";
+  }
   protected:
   explicit EnumDescriptorProto_EnumReservedRange(::google::protobuf::Arena* arena);
   private:
@@ -2271,8 +2305,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -2284,10 +2317,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumDescriptorProto";
+  }
   protected:
   explicit EnumDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -2488,8 +2525,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -2501,10 +2537,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumValueDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueDescriptorProto";
+  }
   protected:
   explicit EnumValueDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -2662,8 +2702,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -2675,10 +2714,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(ServiceDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceDescriptorProto";
+  }
   protected:
   explicit ServiceDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -2841,8 +2884,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -2854,10 +2896,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(MethodDescriptorProto* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.MethodDescriptorProto";
+  }
   protected:
   explicit MethodDescriptorProto(::google::protobuf::Arena* arena);
   private:
@@ -3073,8 +3119,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -3086,10 +3131,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FileOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FileOptions";
+  }
   protected:
   explicit FileOptions(::google::protobuf::Arena* arena);
   private:
@@ -3109,20 +3158,20 @@
   // nested types ----------------------------------------------------
 
   typedef FileOptions_OptimizeMode OptimizeMode;
-  static const OptimizeMode SPEED =
+  static constexpr OptimizeMode SPEED =
     FileOptions_OptimizeMode_SPEED;
-  static const OptimizeMode CODE_SIZE =
+  static constexpr OptimizeMode CODE_SIZE =
     FileOptions_OptimizeMode_CODE_SIZE;
-  static const OptimizeMode LITE_RUNTIME =
+  static constexpr OptimizeMode LITE_RUNTIME =
     FileOptions_OptimizeMode_LITE_RUNTIME;
   static inline bool OptimizeMode_IsValid(int value) {
     return FileOptions_OptimizeMode_IsValid(value);
   }
-  static const OptimizeMode OptimizeMode_MIN =
+  static constexpr OptimizeMode OptimizeMode_MIN =
     FileOptions_OptimizeMode_OptimizeMode_MIN;
-  static const OptimizeMode OptimizeMode_MAX =
+  static constexpr OptimizeMode OptimizeMode_MAX =
     FileOptions_OptimizeMode_OptimizeMode_MAX;
-  static const int OptimizeMode_ARRAYSIZE =
+  static constexpr int OptimizeMode_ARRAYSIZE =
     FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   OptimizeMode_descriptor() {
@@ -3575,8 +3624,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -3588,10 +3636,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(MessageOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.MessageOptions";
+  }
   protected:
   explicit MessageOptions(::google::protobuf::Arena* arena);
   private:
@@ -3751,8 +3803,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -3764,10 +3815,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FieldOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FieldOptions";
+  }
   protected:
   explicit FieldOptions(::google::protobuf::Arena* arena);
   private:
@@ -3787,20 +3842,20 @@
   // nested types ----------------------------------------------------
 
   typedef FieldOptions_CType CType;
-  static const CType STRING =
+  static constexpr CType STRING =
     FieldOptions_CType_STRING;
-  static const CType CORD =
+  static constexpr CType CORD =
     FieldOptions_CType_CORD;
-  static const CType STRING_PIECE =
+  static constexpr CType STRING_PIECE =
     FieldOptions_CType_STRING_PIECE;
   static inline bool CType_IsValid(int value) {
     return FieldOptions_CType_IsValid(value);
   }
-  static const CType CType_MIN =
+  static constexpr CType CType_MIN =
     FieldOptions_CType_CType_MIN;
-  static const CType CType_MAX =
+  static constexpr CType CType_MAX =
     FieldOptions_CType_CType_MAX;
-  static const int CType_ARRAYSIZE =
+  static constexpr int CType_ARRAYSIZE =
     FieldOptions_CType_CType_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   CType_descriptor() {
@@ -3815,20 +3870,20 @@
   }
 
   typedef FieldOptions_JSType JSType;
-  static const JSType JS_NORMAL =
+  static constexpr JSType JS_NORMAL =
     FieldOptions_JSType_JS_NORMAL;
-  static const JSType JS_STRING =
+  static constexpr JSType JS_STRING =
     FieldOptions_JSType_JS_STRING;
-  static const JSType JS_NUMBER =
+  static constexpr JSType JS_NUMBER =
     FieldOptions_JSType_JS_NUMBER;
   static inline bool JSType_IsValid(int value) {
     return FieldOptions_JSType_IsValid(value);
   }
-  static const JSType JSType_MIN =
+  static constexpr JSType JSType_MIN =
     FieldOptions_JSType_JSType_MIN;
-  static const JSType JSType_MAX =
+  static constexpr JSType JSType_MAX =
     FieldOptions_JSType_JSType_MAX;
-  static const int JSType_ARRAYSIZE =
+  static constexpr int JSType_ARRAYSIZE =
     FieldOptions_JSType_JSType_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   JSType_descriptor() {
@@ -3999,8 +4054,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4012,10 +4066,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(OneofOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.OneofOptions";
+  }
   protected:
   explicit OneofOptions(::google::protobuf::Arena* arena);
   private:
@@ -4143,8 +4201,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4156,10 +4213,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumOptions";
+  }
   protected:
   explicit EnumOptions(::google::protobuf::Arena* arena);
   private:
@@ -4303,8 +4364,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4316,10 +4376,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumValueOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValueOptions";
+  }
   protected:
   explicit EnumValueOptions(::google::protobuf::Arena* arena);
   private:
@@ -4455,8 +4519,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4468,10 +4531,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(ServiceOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.ServiceOptions";
+  }
   protected:
   explicit ServiceOptions(::google::protobuf::Arena* arena);
   private:
@@ -4607,8 +4674,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4620,10 +4686,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(MethodOptions* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.MethodOptions";
+  }
   protected:
   explicit MethodOptions(::google::protobuf::Arena* arena);
   private:
@@ -4643,20 +4713,20 @@
   // nested types ----------------------------------------------------
 
   typedef MethodOptions_IdempotencyLevel IdempotencyLevel;
-  static const IdempotencyLevel IDEMPOTENCY_UNKNOWN =
+  static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN =
     MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
-  static const IdempotencyLevel NO_SIDE_EFFECTS =
+  static constexpr IdempotencyLevel NO_SIDE_EFFECTS =
     MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
-  static const IdempotencyLevel IDEMPOTENT =
+  static constexpr IdempotencyLevel IDEMPOTENT =
     MethodOptions_IdempotencyLevel_IDEMPOTENT;
   static inline bool IdempotencyLevel_IsValid(int value) {
     return MethodOptions_IdempotencyLevel_IsValid(value);
   }
-  static const IdempotencyLevel IdempotencyLevel_MIN =
+  static constexpr IdempotencyLevel IdempotencyLevel_MIN =
     MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN;
-  static const IdempotencyLevel IdempotencyLevel_MAX =
+  static constexpr IdempotencyLevel IdempotencyLevel_MAX =
     MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX;
-  static const int IdempotencyLevel_ARRAYSIZE =
+  static constexpr int IdempotencyLevel_ARRAYSIZE =
     MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   IdempotencyLevel_descriptor() {
@@ -4795,8 +4865,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4808,10 +4877,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(UninterpretedOption_NamePart* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption.NamePart";
+  }
   protected:
   explicit UninterpretedOption_NamePart(::google::protobuf::Arena* arena);
   private:
@@ -4959,8 +5032,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -4972,10 +5044,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(UninterpretedOption* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.UninterpretedOption";
+  }
   protected:
   explicit UninterpretedOption(::google::protobuf::Arena* arena);
   private:
@@ -5201,8 +5277,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -5214,10 +5289,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(SourceCodeInfo_Location* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo.Location";
+  }
   protected:
   explicit SourceCodeInfo_Location(::google::protobuf::Arena* arena);
   private:
@@ -5430,8 +5509,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -5443,10 +5521,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(SourceCodeInfo* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.SourceCodeInfo";
+  }
   protected:
   explicit SourceCodeInfo(::google::protobuf::Arena* arena);
   private:
@@ -5573,8 +5655,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -5586,10 +5667,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(GeneratedCodeInfo_Annotation* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo.Annotation";
+  }
   protected:
   explicit GeneratedCodeInfo_Annotation(::google::protobuf::Arena* arena);
   private:
@@ -5756,8 +5841,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -5769,10 +5853,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(GeneratedCodeInfo* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.GeneratedCodeInfo";
+  }
   protected:
   explicit GeneratedCodeInfo(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index ed08fcb..87201c7 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -486,7 +486,7 @@
   //
   // Implementations may choose not to generate the map_entry=true message, but
   // use a native map in the target language to hold the keys and values.
-  // The reflection APIs in such implementions still need to work as
+  // The reflection APIs in such implementations still need to work as
   // if the field is a repeated message field.
   //
   // NOTE: Do not set the option in .proto files. Always use the maps syntax
@@ -763,7 +763,7 @@
   //   beginning of the "extend" block and is shared by all extensions within
   //   the block.
   // - Just because a location's span is a subset of some other location's span
-  //   does not mean that it is a descendent.  For example, a "group" defines
+  //   does not mean that it is a descendant.  For example, a "group" defines
   //   both a type and a field in a single declaration.  Thus, the locations
   //   corresponding to the type and field and their components will overlap.
   // - Code which tries to interpret locations should probably be designed to
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 3ed11aa..ad32f81 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -2910,9 +2910,8 @@
   ASSERT_TRUE(pool_->FindMessageTypeByName("undeclared.Quux") == NULL);
 }
 
-INSTANTIATE_TEST_CASE_P(DatabaseSource,
-                        AllowUnknownDependenciesTest,
-                        testing::Values(NO_DATABASE, FALLBACK_DATABASE));
+INSTANTIATE_TEST_SUITE_P(DatabaseSource, AllowUnknownDependenciesTest,
+                         testing::Values(NO_DATABASE, FALLBACK_DATABASE));
 
 // ===================================================================
 
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 1e29f3c..ed8bcee 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Duration_google_2fprotobuf_2fduration_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fduration_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fduration_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -63,7 +63,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Duration_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fduration_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fduration_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fduration_2eproto, "google/protobuf/duration.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fduration_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fduration_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto, file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
@@ -77,7 +77,7 @@
   "f/ptypes/duration\370\001\001\242\002\003GPB\252\002\036Google.Prot"
   "obuf.WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fduration_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
   "google/protobuf/duration.proto", &assign_descriptors_table_google_2fprotobuf_2fduration_2eproto, 227,
@@ -173,43 +173,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Duration::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Duration*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Duration::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // int64 seconds = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_seconds(::google::protobuf::internal::ReadVarint(&ptr));
+        set_seconds(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // int32 nanos = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_nanos(::google::protobuf::internal::ReadVarint(&ptr));
+        set_nanos(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 86c6b5b..65e147b 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fduration_2eproto PROTOBUF_EXPORT
@@ -131,8 +138,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -144,10 +150,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Duration* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Duration";
+  }
   protected:
   explicit Duration(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 94446b0..e96f658 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -316,7 +316,7 @@
   delete message;
 }
 
-INSTANTIATE_TEST_CASE_P(UseArena, DynamicMessageTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(UseArena, DynamicMessageTest, ::testing::Bool());
 
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index a8d1d01..5c34b5f 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Empty_google_2fprotobuf_2fempty_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fempty_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fempty_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -61,7 +61,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Empty_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fempty_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fempty_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fempty_2eproto, "google/protobuf/empty.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fempty_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fempty_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto, file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
@@ -74,7 +74,7 @@
   "/ptypes/empty\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
   ".WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fempty_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
   "google/protobuf/empty.proto", &assign_descriptors_table_google_2fprotobuf_2fempty_2eproto, 183,
@@ -159,28 +159,21 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Empty::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Empty*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Empty::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       default: {
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index f901439..58f7eec 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fempty_2eproto PROTOBUF_EXPORT
@@ -131,8 +138,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -144,10 +150,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Empty* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Empty";
+  }
   protected:
   explicit Empty(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index f63afef..61b5598 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -177,11 +177,7 @@
   GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
         type == WireFormatLite::TYPE_GROUP);
   ExtensionInfo info(type, is_repeated, is_packed);
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  info.message_info = {prototype, prototype->_ParseFunc()};
-#else
   info.message_info = {prototype};
-#endif
   Register(containing_type, number, info);
 }
 
@@ -1204,9 +1200,8 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-std::pair<const char*, bool> ExtensionSet::ParseField(
-    uint64 tag, ParseClosure parent, const char* begin, const char* end,
-    const MessageLite* containing_type,
+const char* ExtensionSet::ParseField(
+    uint64 tag, const char* ptr, const MessageLite* containing_type,
     internal::InternalMetadataWithArenaLite* metadata,
     internal::ParseContext* ctx) {
   GeneratedExtensionFinder finder(containing_type);
@@ -1215,12 +1210,19 @@
   ExtensionInfo extension;
   if (!FindExtensionInfoFromFieldNumber(tag & 7, number, &finder, &extension,
                                         &was_packed_on_wire)) {
-    return UnknownFieldParse(tag, parent, begin, end,
-                             metadata->mutable_unknown_fields(), ctx);
+    return UnknownFieldParse(tag, metadata->mutable_unknown_fields(), ptr, ctx);
   }
   return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
-                                     metadata, parent, begin, end, ctx);
+                                     metadata, ptr, ctx);
 }
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const MessageLite* containing_type,
+    internal::InternalMetadataWithArenaLite* metadata,
+    internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl(ptr, containing_type, metadata, ctx);
+}
+
 #endif
 
 bool ExtensionSet::ParseFieldWithExtensionInfo(
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index e5ae3d4..f29a0b5 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -121,9 +121,6 @@
 
   struct MessageInfo {
     const MessageLite* prototype;
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-    ParseFunc parse_func;
-#endif
   };
 
   union {
@@ -401,33 +398,45 @@
                   io::CodedOutputStream* unknown_fields);
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  template <typename T>
-  std::pair<const char*, bool> ParseFieldWithExtensionInfo(
-      int number, bool was_packed_on_wire, const ExtensionInfo& info,
-      T* metadata, ParseClosure parent, const char* begin, const char* end,
-      internal::ParseContext* ctx);
   // Lite parser
-  std::pair<const char*, bool> ParseField(
-      uint64 tag, ParseClosure parent, const char* begin, const char* end,
-      const MessageLite* containing_type,
-      internal::InternalMetadataWithArenaLite* metadata,
-      internal::ParseContext* ctx);
+  const char* ParseField(uint64 tag, const char* ptr,
+                         const MessageLite* containing_type,
+                         internal::InternalMetadataWithArenaLite* metadata,
+                         internal::ParseContext* ctx);
   // Full parser
-  std::pair<const char*, bool> ParseField(
-      uint64 tag, ParseClosure parent, const char* begin, const char* end,
-      const Message* containing_type,
-      internal::InternalMetadataWithArena* metadata,
-      internal::ParseContext* ctx);
-  std::pair<const char*, bool> ParseFieldMaybeLazily(
-      uint64 tag, ParseClosure parent, const char* begin, const char* end,
-      const Message* containing_type,
-      internal::InternalMetadataWithArena* metadata,
-      internal::ParseContext* ctx);
-  const char* ParseMessageSetItem(ParseClosure parent, const char* begin,
-                                  const char* end,
-                                  const Message* containing_type,
-                                  internal::InternalMetadataWithArena* metadata,
-                                  internal::ParseContext* ctx);
+  const char* ParseField(uint64 tag, const char* ptr,
+                         const Message* containing_type,
+                         internal::InternalMetadataWithArena* metadata,
+                         internal::ParseContext* ctx);
+  template <typename Msg, typename Metadata>
+  const char* ParseMessageSet(const char* ptr, const Msg* containing_type,
+                              Metadata* metadata, internal::ParseContext* ctx) {
+    struct MessageSetItem {
+      const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+        return me->ParseMessageSetItem(ptr, containing_type, metadata, ctx);
+      }
+      ExtensionSet* me;
+      const Msg* containing_type;
+      Metadata* metadata;
+    } item{this, containing_type, metadata};
+    while (!ctx->Done(&ptr)) {
+      uint32 tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == WireFormatLite::kMessageSetItemStartTag) {
+        ptr = ctx->ParseGroup(&item, ptr, tag);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      } else {
+        if (tag == 0 || (tag & 7) == 4) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = ParseField(tag, ptr, containing_type, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      }
+    }
+    return ptr;
+  }
 #endif
 
   // Parse an entire message in MessageSet format.  Such messages have no
@@ -527,6 +536,9 @@
 
     virtual bool ReadMessage(const MessageLite& prototype,
                              io::CodedInputStream* input) = 0;
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+    virtual const char* _InternalParse(const char* ptr, ParseContext* ctx) = 0;
+#endif
     virtual void WriteMessage(int number,
                               io::CodedOutputStream* output) const = 0;
     virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
@@ -697,13 +709,6 @@
   // Merges existing Extension from other_extension
   void InternalExtensionMergeFrom(int number, const Extension& other_extension);
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  bool FindExtension(int wire_type, uint32 field,
-                     const Message* containing_type,
-                     const internal::ParseContext* ctx,
-                     ExtensionInfo* extension, bool* was_packed_on_wire);
-#endif
-
   // Returns true and fills field_number and extension if extension is found.
   // Note to support packed repeated field compatibility, it also fills whether
   // the tag on wire is packed, which can be different from
@@ -757,6 +762,53 @@
                            ExtensionFinder* extension_finder,
                            MessageSetFieldSkipper* field_skipper);
 
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+  bool FindExtension(int wire_type, uint32 field,
+                     const MessageLite* containing_type,
+                     const internal::ParseContext* ctx,
+                     ExtensionInfo* extension, bool* was_packed_on_wire) {
+    GeneratedExtensionFinder finder(containing_type);
+    return FindExtensionInfoFromFieldNumber(wire_type, field, &finder,
+                                            extension, was_packed_on_wire);
+  }
+  inline bool FindExtension(int wire_type, uint32 field,
+                            const Message* containing_type,
+                            const internal::ParseContext* ctx,
+                            ExtensionInfo* extension, bool* was_packed_on_wire);
+  // Used for MessageSet only
+  const char* ParseFieldMaybeLazily(
+      uint64 tag, const char* ptr, const MessageLite* containing_type,
+      internal::InternalMetadataWithArenaLite* metadata,
+      internal::ParseContext* ctx) {
+    // Lite MessageSet doesn't implement lazy.
+    return ParseField(tag, ptr, containing_type, metadata, ctx);
+  }
+  const char* ParseFieldMaybeLazily(
+      uint64 tag, const char* ptr, const Message* containing_type,
+      internal::InternalMetadataWithArena* metadata,
+      internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(
+      const char* ptr, const MessageLite* containing_type,
+      internal::InternalMetadataWithArenaLite* metadata,
+      internal::ParseContext* ctx);
+  const char* ParseMessageSetItem(const char* ptr,
+                                  const Message* containing_type,
+                                  internal::InternalMetadataWithArena* metadata,
+                                  internal::ParseContext* ctx);
+
+  // Implemented in extension_set_inl.h to keep code out of the header file.
+  template <typename T>
+  const char* ParseFieldWithExtensionInfo(int number, bool was_packed_on_wire,
+                                          const ExtensionInfo& info,
+                                          T* metadata, const char* ptr,
+                                          internal::ParseContext* ctx);
+  template <typename Msg, typename Metadata>
+  const char* ParseMessageSetItemTmpl(const char* ptr,
+                                      const Msg* containing_type,
+                                      Metadata* metadata,
+                                      internal::ParseContext* ctx);
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
   // Hack:  RepeatedPtrFieldBase declares ExtensionSet as a friend.  This
   //   friendship should automatically extend to ExtensionSet::Extension, but
   //   unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
@@ -804,44 +856,6 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
 };
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-
-template <typename Msg, typename Metadata>
-const char* ParseMessageSet(const char* begin, const char* end, Msg* msg,
-                            ExtensionSet* ext, Metadata* metadata,
-                            internal::ParseContext* ctx) {
-  auto ptr = begin;
-  int depth = 0;
-  while (ptr < end) {
-    uint32 tag;
-    ptr = io::Parse32(ptr, &tag);
-    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-    if (tag == WireFormatLite::kMessageSetItemStartTag) {
-      ctx->extra_parse_data().payload.clear();
-      auto res = ctx->ParseGroup(tag, {Msg::InternalParseMessageSetItem, msg},
-                                 ptr, end, &depth);
-      ptr = res.first;
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      if (res.second) {
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup(
-            {Msg::_InternalParse, msg}, {Msg::InternalParseMessageSetItem, msg},
-            depth, tag));
-        return ptr;
-      }
-    } else {
-      auto res =
-          ext->ParseField(tag, {Msg::_InternalParse, msg}, ptr, end,
-                          Msg::internal_default_instance(), metadata, ctx);
-      ptr = res.first;
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      if (res.second) break;
-    }
-  }
-  return ptr;
-}
-
-#endif
-
 // These are just for convenience...
 inline void ExtensionSet::SetString(int number, FieldType type,
                                     const std::string& value,
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 3642250..53aec2b 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -309,10 +309,6 @@
       GOOGLE_CHECK(output->message_info.prototype != nullptr)
           << "Extension factory's GetPrototype() returned NULL for extension: "
           << extension->full_name();
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-      output->message_info.parse_func =
-          output->message_info.prototype->_ParseFunc();
-#endif
     } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
       output->enum_validity_check.func = ValidateEnumUsingDescriptor;
       output->enum_validity_check.arg = extension->enum_type();
@@ -329,15 +325,14 @@
                                  const internal::ParseContext* ctx,
                                  ExtensionInfo* extension,
                                  bool* was_packed_on_wire) {
-  if (ctx->extra_parse_data().pool == nullptr) {
+  if (ctx->data().pool == nullptr) {
     GeneratedExtensionFinder finder(containing_type);
     if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
                                           was_packed_on_wire)) {
       return false;
     }
   } else {
-    DescriptorPoolExtensionFinder finder(ctx->extra_parse_data().pool,
-                                         ctx->extra_parse_data().factory,
+    DescriptorPoolExtensionFinder finder(ctx->data().pool, ctx->data().factory,
                                          containing_type->GetDescriptor());
     if (!FindExtensionInfoFromFieldNumber(wire_type, field, &finder, extension,
                                           was_packed_on_wire)) {
@@ -347,9 +342,8 @@
   return true;
 }
 
-std::pair<const char*, bool> ExtensionSet::ParseField(
-    uint64 tag, ParseClosure parent, const char* begin, const char* end,
-    const Message* containing_type,
+const char* ExtensionSet::ParseField(
+    uint64 tag, const char* ptr, const Message* containing_type,
     internal::InternalMetadataWithArena* metadata,
     internal::ParseContext* ctx) {
   int number = tag >> 3;
@@ -357,20 +351,26 @@
   ExtensionInfo extension;
   if (!FindExtension(tag & 7, number, containing_type, ctx, &extension,
                      &was_packed_on_wire)) {
-    return UnknownFieldParse(tag, parent, begin, end,
-                             metadata->mutable_unknown_fields(), ctx);
+    return UnknownFieldParse(tag, metadata->mutable_unknown_fields(), ptr, ctx);
   }
   return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
-                                     metadata, parent, begin, end, ctx);
+                                     metadata, ptr, ctx);
 }
 
-std::pair<const char*, bool> ExtensionSet::ParseFieldMaybeLazily(
-    uint64 tag, ParseClosure parent, const char* begin, const char* end,
-    const Message* containing_type,
+const char* ExtensionSet::ParseFieldMaybeLazily(
+    uint64 tag, const char* ptr, const Message* containing_type,
     internal::InternalMetadataWithArena* metadata,
     internal::ParseContext* ctx) {
-  return ParseField(tag, parent, begin, end, containing_type, metadata, ctx);
+  return ParseField(tag, ptr, containing_type, metadata, ctx);
 }
+
+const char* ExtensionSet::ParseMessageSetItem(
+    const char* ptr, const Message* containing_type,
+    internal::InternalMetadataWithArena* metadata,
+    internal::ParseContext* ctx) {
+  return ParseMessageSetItemTmpl(ptr, containing_type, metadata, ctx);
+}
+
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
@@ -388,83 +388,6 @@
   }
 }
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ExtensionSet::ParseMessageSetItem(
-    ParseClosure parent, const char* begin, const char* end,
-    const Message* containing_type,
-    internal::InternalMetadataWithArena* metadata,
-    internal::ParseContext* ctx) {
-  auto ptr = begin;
-  while (ptr < end) {
-    uint32 tag = *ptr++;
-    if (tag == WireFormatLite::kMessageSetTypeIdTag) {
-      uint32 type_id;
-      ptr = io::Parse32(ptr, &type_id);
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-
-      if (ctx->extra_parse_data().payload.empty()) {
-        tag = *ptr++;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(tag ==
-                                       WireFormatLite::kMessageSetMessageTag);
-        auto res =
-            ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, parent,
-                                  ptr, end, containing_type, metadata, ctx);
-        ptr = res.first;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) break;
-      } else {
-        ExtensionInfo extension;
-        bool was_packed_on_wire;
-        if (!FindExtension(2, type_id, containing_type, ctx, &extension,
-                           &was_packed_on_wire)) {
-          metadata->mutable_unknown_fields()->AddLengthDelimited(
-              type_id, ctx->extra_parse_data().payload);
-          continue;
-        }
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
-                             *extension.message_info.prototype,
-                             extension.descriptor)
-                : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
-                                 *extension.message_info.prototype,
-                                 extension.descriptor);
-        ParseClosure parser = {extension.message_info.parse_func, value};
-        StringPiece chunk(ctx->extra_parse_data().payload);
-        bool ok = ctx->ParseExactRange(parser, chunk.begin(), chunk.end());
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
-      }
-    } else if (tag == WireFormatLite::kMessageSetItemEndTag) {
-      ctx->EndGroup(tag);
-      break;
-    } else if (tag == WireFormatLite::kMessageSetMessageTag) {
-      uint32 size;
-      ptr = io::Parse32(ptr, &size);
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      ParseClosure child = {internal::StringParser,
-                            &ctx->extra_parse_data().payload};
-      if (size > end - ptr + internal::ParseContext::kSlopBytes) {
-        ctx->extra_parse_data().payload.clear();
-        return ctx->StoreAndTailCall(ptr, end, parent, child, size);
-      } else {
-        ctx->extra_parse_data().payload.assign(ptr, size);
-        ptr += size;
-      }
-    } else {
-      ptr--;
-      ptr = io::Parse32(ptr, &tag);
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      auto res =
-          ParseField(tag, parent, ptr, end, containing_type, metadata, ctx);
-      ptr = res.first;
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      if (res.second) break;
-    }
-  }
-  return ptr;
-}
-#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-
 bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
                                    const Message* containing_type,
                                    UnknownFieldSet* unknown_fields) {
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
index ed9f19c..b73913a 100644
--- a/src/google/protobuf/extension_set_inl.h
+++ b/src/google/protobuf/extension_set_inl.h
@@ -31,6 +31,7 @@
 #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>
 
 namespace google {
@@ -39,22 +40,17 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 template <typename T>
-std::pair<const char*, bool> ExtensionSet::ParseFieldWithExtensionInfo(
+const char* ExtensionSet::ParseFieldWithExtensionInfo(
     int number, bool was_packed_on_wire, const ExtensionInfo& extension,
-    T* metadata, ParseClosure parent, const char* begin, const char* end,
-    internal::ParseContext* ctx) {
-  auto ptr = begin;
-  ParseClosure child;
-  int depth;
+    T* metadata, const char* ptr, internal::ParseContext* ctx) {
   if (was_packed_on_wire) {
     switch (extension.type) {
 #define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
   case WireFormatLite::TYPE_##UPPERCASE:                                     \
-    child = {                                                                \
-        internal::Packed##CPP_CAMELCASE##Parser,                             \
+    return internal::Packed##CPP_CAMELCASE##Parser(                          \
         MutableRawRepeatedField(number, extension.type, extension.is_packed, \
-                                extension.descriptor)};                      \
-    goto length_delim
+                                extension.descriptor),                       \
+        ptr, ctx);
       HANDLE_TYPE(INT32, Int32);
       HANDLE_TYPE(INT64, Int64);
       HANDLE_TYPE(UINT32, UInt32);
@@ -71,15 +67,12 @@
 #undef HANDLE_TYPE
 
       case WireFormatLite::TYPE_ENUM:
-        ctx->extra_parse_data().SetEnumValidatorArg(
-            extension.enum_validity_check.func,
+        return internal::PackedEnumParserArg(
+            MutableRawRepeatedField(number, extension.type, extension.is_packed,
+                                    extension.descriptor),
+            ptr, ctx, extension.enum_validity_check.func,
             extension.enum_validity_check.arg,
             metadata->mutable_unknown_fields(), number);
-        child = {
-            internal::PackedValidEnumParserLiteArg,
-            MutableRawRepeatedField(number, extension.type, extension.is_packed,
-                                    extension.descriptor)};
-        goto length_delim;
       case WireFormatLite::TYPE_STRING:
       case WireFormatLite::TYPE_BYTES:
       case WireFormatLite::TYPE_GROUP:
@@ -92,8 +85,8 @@
 #define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
     uint64 value;                                                           \
-    ptr = io::Parse64(ptr, &value);                                     \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
+    ptr = ParseVarint64(ptr, &value);                                       \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     if (extension.is_repeated) {                                            \
       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
                          extension.is_packed, value, extension.descriptor); \
@@ -111,8 +104,8 @@
 #define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
   case WireFormatLite::TYPE_##UPPERCASE: {                                  \
     uint64 val;                                                             \
-    ptr = io::Parse64(ptr, &val);                                       \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
+    ptr = ParseVarint64(ptr, &val);                                         \
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);                                    \
     auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
     if (extension.is_repeated) {                                            \
       Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
@@ -151,8 +144,8 @@
 
       case WireFormatLite::TYPE_ENUM: {
         uint64 val;
-        ptr = io::Parse64(ptr, &val);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+        ptr = ParseVarint64(ptr, &val);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         int value = val;
 
         if (!extension.enum_validity_check.func(
@@ -175,8 +168,9 @@
                                         extension.descriptor)
                             : MutableString(number, WireFormatLite::TYPE_STRING,
                                             extension.descriptor);
-        child = {StringParser, value};
-        goto length_delim;
+        int size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        return ctx->ReadString(ptr, size, value);
       }
 
       case WireFormatLite::TYPE_GROUP: {
@@ -188,18 +182,8 @@
                 : MutableMessage(number, WireFormatLite::TYPE_GROUP,
                                  *extension.message_info.prototype,
                                  extension.descriptor);
-        child = {extension.message_info.parse_func, value};
         uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
-        auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
-        ptr = res.first;
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-        if (res.second) {
-          GOOGLE_PROTOBUF_ASSERT_RETURN(
-              ctx->StoreGroup(parent, child, depth, tag),
-              std::make_pair(nullptr, true));
-          return std::make_pair(ptr, true);
-        }
-        break;
+        return ctx->ParseGroup(value, ptr, tag);
       }
 
       case WireFormatLite::TYPE_MESSAGE: {
@@ -211,31 +195,77 @@
                 : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
                                  *extension.message_info.prototype,
                                  extension.descriptor);
-        child = {extension.message_info.parse_func, value};
-        goto length_delim;
+        return ctx->ParseMessage(value, ptr);
       }
     }
   }
-
-  return std::make_pair(ptr, false);
-
-length_delim:
-  uint32 size;
-  ptr = io::Parse32(ptr, &size);
-  GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-  if (size > end - ptr) goto len_delim_till_end;
-  {
-    auto newend = ptr + size;
-    bool ok = ctx->ParseExactRange(child, ptr, newend);
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-    ptr = newend;
-  }
-  return std::make_pair(ptr, false);
-len_delim_till_end:
-  return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
-                        true);
+  return ptr;
 }
-#endif
+
+template <typename Msg, typename Metadata>
+const char* ExtensionSet::ParseMessageSetItemTmpl(const char* ptr,
+                                                  const Msg* containing_type,
+                                                  Metadata* metadata,
+                                                  internal::ParseContext* ctx) {
+  std::string payload;
+  uint32 type_id = 0;
+  while (!ctx->Done(&ptr)) {
+    uint32 tag;
+    ptr = ReadTag(ptr, &tag);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (tag == WireFormatLite::kMessageSetTypeIdTag) {
+      ptr = _Parse32(ptr, &type_id);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (!payload.empty()) {
+        ExtensionInfo extension;
+        bool was_packed_on_wire;
+        if (!FindExtension(2, type_id, containing_type, ctx, &extension,
+                           &was_packed_on_wire)) {
+          WriteLengthDelimited(type_id, payload,
+                               metadata->mutable_unknown_fields());
+        } else {
+          MessageLite* value =
+              extension.is_repeated
+                  ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                               *extension.message_info.prototype,
+                               extension.descriptor)
+                  : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
+                                   *extension.message_info.prototype,
+                                   extension.descriptor);
+
+          const char* p;
+          ParseContext tmp_ctx(ctx->depth(), false, &p, payload);
+          tmp_ctx.data().pool = ctx->data().pool;
+          tmp_ctx.data().factory = ctx->data().factory;
+          GOOGLE_PROTOBUF_PARSER_ASSERT(
+              tmp_ctx.AtLegitimateEnd(value->_InternalParse(p, &tmp_ctx)));
+        }
+        type_id = 0;
+      }
+    } else if (tag == WireFormatLite::kMessageSetMessageTag) {
+      if (type_id != 0) {
+        ptr = ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, ptr,
+                                    containing_type, metadata, ctx);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+        type_id = 0;
+      } else {
+        int32 size = ReadSize(&ptr);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        ptr = ctx->ReadString(ptr, size, &payload);
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      }
+    } else {
+      if (tag == 0 || (tag & 7) == 4) {
+        ctx->SetLastTag(tag);
+        return ptr;
+      }
+      ptr = ParseField(tag, ptr, containing_type, metadata, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+  }
+  return ptr;
+}
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index e5a8fe6..0607b91 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_FieldMask_google_2fprotobuf_2ffield_5fmask_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -62,7 +62,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_FieldMask_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2ffield_5fmask_2eproto, "google/protobuf/field_mask.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2ffield_5fmask_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
@@ -76,7 +76,7 @@
   "ield_mask;field_mask\370\001\001\242\002\003GPB\252\002\036Google.P"
   "rotobuf.WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
   false, InitDefaults_google_2fprotobuf_2ffield_5fmask_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
   "google/protobuf/field_mask.proto", &assign_descriptors_table_google_2fprotobuf_2ffield_5fmask_2eproto, 230,
@@ -167,59 +167,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FieldMask::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FieldMask*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FieldMask::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated string paths = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(add_paths(), ptr, ctx, "google.protobuf.FieldMask.paths");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.FieldMask.paths");
-          object = msg->add_paths();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool FieldMask::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index a74e3b4..02e629d 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ffield_5fmask_2eproto PROTOBUF_EXPORT
@@ -131,8 +138,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -144,10 +150,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FieldMask* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FieldMask";
+  }
   protected:
   explicit FieldMask(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/generated_message_table_driven.h b/src/google/protobuf/generated_message_table_driven.h
index 8fee7ab..d06a260 100644
--- a/src/google/protobuf/generated_message_table_driven.h
+++ b/src/google/protobuf/generated_message_table_driven.h
@@ -209,15 +209,12 @@
 // The tables must be composed of POD components to ensure link-time
 // initialization.
 static_assert(std::is_pod<ParseTableField>::value, "");
+static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
 static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
 static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
 static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
 static_assert(std::is_pod<ParseTable>::value, "");
 
-#ifndef __NVCC__  // This assertion currently fails under NVCC.
-static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
-#endif
-
 // 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,
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 6230153..8003d17 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -44,9 +44,9 @@
 #include <string>
 #include <vector>
 
-#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/parse_context.h>
+#include <google/protobuf/arenastring.h>
 #include <google/protobuf/has_bits.h>
 #include <google/protobuf/implicit_weak_message.h>
 #include <google/protobuf/message_lite.h>
@@ -218,31 +218,6 @@
   OnShutdownRun(DestroyString, ptr);
 }
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-// To simplify generation of the parse loop code we take objects by void ptr.
-inline void InlineGreedyStringParser(void* str, const char* begin, int size,
-                                     ParseContext*) {
-  static_cast<std::string*>(str)->assign(begin, size);
-}
-
-
-inline bool StringCheck(const char* begin, int size, ParseContext* ctx) {
-  return true;
-}
-
-inline bool StringCheckUTF8(const char* begin, int size, ParseContext* ctx) {
-  return VerifyUTF8(StringPiece(begin, size), ctx);
-}
-
-inline bool StringCheckUTF8Verify(const char* begin, int size,
-                                  ParseContext* ctx) {
-#ifndef NDEBUG
-  VerifyUTF8(StringPiece(begin, size), ctx);
-#endif
-  return true;
-}
-
-#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
index 5cc718f..4cd0968 100644
--- a/src/google/protobuf/implicit_weak_message.cc
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -48,11 +48,9 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ImplicitWeakMessage::_InternalParse(const char* begin,
-                                                const char* end, void* object,
+const char* ImplicitWeakMessage::_InternalParse(const char* ptr,
                                                 ParseContext* ctx) {
-  return internal::StringParser(
-      begin, end, &(static_cast<ImplicitWeakMessage*>(object)->data_), ctx);
+  return ctx->AppendString(ptr, &data_);
 }
 #endif
 
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
index 5d3b479..16b9164 100644
--- a/src/google/protobuf/implicit_weak_message.h
+++ b/src/google/protobuf/implicit_weak_message.h
@@ -79,10 +79,7 @@
   bool MergePartialFromCodedStream(io::CodedInputStream* input) override;
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  ParseFunc _ParseFunc() const override { return _InternalParse; }
-
-  static const char* _InternalParse(const char* begin, const char* end,
-                                    void* object, ParseContext* ctx);
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
 #endif
 
   size_t ByteSizeLong() const override { return data_.size(); }
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index d75095d..740571b 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -144,8 +144,12 @@
 
 class DescriptorPool;
 class MessageFactory;
+class ZeroCopyCodedInputStream;
 
-namespace internal { void MapTestForceDeterministic(); }
+namespace internal {
+void MapTestForceDeterministic();
+class EpsCopyByteStream;
+}  // namespace internal
 
 namespace io {
 
@@ -157,64 +161,6 @@
 class ZeroCopyInputStream;           // zero_copy_stream.h
 class ZeroCopyOutputStream;          // zero_copy_stream.h
 
-template <typename T>
-T UnalignedLoad(const void* p) {
-  T res;
-  memcpy(&res, p, sizeof(T));
-  return res;
-}
-
-// TODO(gerbens) Experiment with best implementation.
-// Clang unrolls loop and generating pretty good code on O2, gcc doesn't.
-// Unclear if we want 64 bit parse loop unrolled, inlined or opaque function
-// call. Hence experimentation is needed.
-// Important guarantee is that it doesn't read more than size bytes from p.
-template <int size, typename T>
-const char* VarintParse(const char* p, T* out) {
-  T res = 0;
-  T extra = 0;
-  for (int i = 0; i < size; i++) {
-    T byte = static_cast<uint8>(p[i]);
-    res += byte << (i * 7);
-    int j = i + 1;
-    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
-      *out = res - extra;
-      return p + j;
-    }
-    extra += 128ull << (i * 7);
-  }
-  *out = 0;
-  return nullptr;
-}
-
-inline const char* Parse32(const char* p, uint32* out) {
-  return VarintParse<5>(p, out);
-}
-inline const char* Parse64(const char* p, uint64* out) {
-  return VarintParse<10>(p, out);
-}
-
-inline const char* ReadSize(const char* p, int32* out) {
-  int32 res = 0;
-  int32 extra = 0;
-  for (int i = 0; i < 4; i++) {
-    uint32 byte = static_cast<uint8>(p[i]);
-    res += byte << (i * 7);
-    int j = i + 1;
-    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
-      *out = res - extra;
-      return p + j;
-    }
-    extra += 128ull << (i * 7);
-  }
-  uint32 byte = static_cast<uint8>(p[4]);
-  // size may not be negative, so only the lowest 3 bits can be set.
-  if (byte >= 8) return nullptr;
-  res += byte << (4 * 7);
-  *out = res - extra;
-  return p + 5;
-}
-
 // Class which reads and decodes binary data which is composed of varint-
 // encoded integers and fixed-width pieces.  Wraps a ZeroCopyInputStream.
 // Most users will not need to deal with CodedInputStream.
@@ -693,6 +639,9 @@
   static const int kDefaultTotalBytesLimit = INT_MAX;
 
   static int default_recursion_limit_;  // 100 by default.
+
+  friend class google::protobuf::ZeroCopyCodedInputStream;
+  friend class google::protobuf::internal::EpsCopyByteStream;
 };
 
 // Class which encodes and writes binary data which is composed of varint-
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc
index dd92113..ea18ae6 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.cc
+++ b/src/google/protobuf/io/zero_copy_stream_impl.cc
@@ -78,7 +78,6 @@
 
 }  // namespace
 
-
 // ===================================================================
 
 FileInputStream::FileInputStream(int file_descriptor, int block_size)
diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h
index 90d9380..ea8681b 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl.h
@@ -53,7 +53,6 @@
 namespace protobuf {
 namespace io {
 
-
 // ===================================================================
 
 // A ZeroCopyInputStream which reads from a file descriptor.
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 624f84d..40f35e9 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -414,7 +414,7 @@
           : node_(NodePtrFromKeyPtr(*tree_it)), m_(m), bucket_index_(index) {
         // Invariant: iterators that use buckets with trees have an even
         // bucket_index_.
-        GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0);
+        GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0u);
       }
 
       // Advance through buckets, looking for the first that isn't empty.
@@ -454,7 +454,7 @@
           if (is_list) {
             SearchFrom(bucket_index_ + 1);
           } else {
-            GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0);
+            GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0u);
             Tree* tree = static_cast<Tree*>(m_->table_[bucket_index_]);
             if (++tree_it == tree->end()) {
               SearchFrom(bucket_index_ + 2);
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 2b36b0b..5ebc82a 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -36,6 +36,7 @@
 
 #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/arenastring.h>
 #include <google/protobuf/map.h>
@@ -193,6 +194,31 @@
     MergeFromInternal(*::google::protobuf::down_cast<const Derived*>(&other));
   }
 
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
+    while (!ctx->Done(&ptr)) {
+      uint32 tag;
+      ptr = ReadTag(ptr, &tag);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+      if (tag == kKeyTag) {
+        set_has_key();
+        ptr = KeyTypeHandler::Read(ptr, ctx, mutable_key());
+      } else if (tag == kValueTag) {
+        set_has_value();
+        ptr = ValueTypeHandler::Read(ptr, ctx, mutable_value());
+      } else {
+        if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
+                            WireFormatLite::WIRETYPE_END_GROUP) {
+          ctx->SetLastTag(tag);
+          return ptr;
+        }
+        ptr = UnknownFieldParse(tag, nullptr, ptr, ctx);
+      }
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    }
+    return ptr;
+  }
+#else
   bool MergePartialFromCodedStream(io::CodedInputStream* input) override {
     uint32 tag;
 
@@ -233,6 +259,7 @@
       }
     }
   }
+#endif
 
   size_t ByteSizeLong() const override {
     size_t size = 0;
@@ -386,35 +413,12 @@
       return result;
     }
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-    bool ParseMap(const char* begin, const char* end) {
-      io::CodedInputStream input(reinterpret_cast<const uint8*>(begin),
-                                 end - begin);
-      return MergePartialFromCodedStream(&input) &&
-             input.ConsumedEntireMessage();
-    }
-    template <typename Metadata>
-    bool ParseMapEnumValidation(const char* begin, const char* end, uint32 num,
-                                Metadata* metadata,
-                                bool (*validate_enum)(int)) {
-      io::CodedInputStream input(reinterpret_cast<const uint8*>(begin),
-                                 static_cast<int>(end - begin));
+    const char* _InternalParse(const char* ptr, ParseContext* ctx) {
       auto entry = NewEntry();
-      // TODO(gerbens) implement _InternalParse for maps. We can't use
-      // ParseFromString as this will call _InternalParse
-      if (!(entry->MergePartialFromCodedStream(&input) &&
-            input.ConsumedEntireMessage()))
-        return false;
-      if (!validate_enum(entry->value())) {
-        auto unknown_fields = metadata->mutable_unknown_fields();
-        WriteLengthDelimited(num, StringPiece(begin, end - begin),
-                             unknown_fields);
-        return true;
-      }
-      (*map_)[entry->key()] = static_cast<Value>(entry->value());
-      return true;
+      ptr = entry->_InternalParse(ptr, ctx);
+      UseKeyAndValueFromEntry();
+      return ptr;
     }
-#endif
 
     MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
 
@@ -425,7 +429,7 @@
     const Value& entry_value() const { return entry_->value(); }
 
    private:
-    void UseKeyAndValueFromEntry() PROTOBUF_COLD {
+    void UseKeyAndValueFromEntry() {
       // Update key_ in case we need it later (because key() is called).
       // This is potentially inefficient, especially if the key is
       // expensive to copy (e.g., a long string), but this is a cold
@@ -477,7 +481,7 @@
   bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
   void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
 
- private:
+ public:
   // Serializing a generated message containing map field involves serializing
   // key-value pairs from Map. The wire format of each key-value pair
   // after serialization should be the same as that of a MapEntry message
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index ef1804b..91be966 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -288,6 +288,10 @@
     return impl_.NewEntryWrapper(key, t);
   }
 
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return impl_._InternalParse(ptr, ctx);
+  }
+
  private:
   MapFieldLiteType impl_;
 
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index 5b8d2e4..4e5f898 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -32,6 +32,7 @@
 #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/map.h>
 #include <google/protobuf/map_entry_lite.h>
@@ -108,6 +109,11 @@
     return EntryType::Wrap(key, t, arena_);
   }
 
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    typename Derived::template Parser<MapFieldLite, Map<Key, T>> parser(this);
+    return parser._InternalParse(ptr, ctx);
+  }
+
  private:
   typedef void DestructorSkippable_;
 
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index ab75f8e..731d578 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -309,8 +309,8 @@
   State state_;
 };
 
-INSTANTIATE_TEST_CASE_P(MapFieldStateTestInstance, MapFieldStateTest,
-                        ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
+INSTANTIATE_TEST_SUITE_P(MapFieldStateTestInstance, MapFieldStateTest,
+                         ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
 
 TEST_P(MapFieldStateTest, GetMap) {
   map_field_->GetMap();
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index a8220b6..ddfedc8 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -31,7 +31,10 @@
 #ifndef GOOGLE_PROTOBUF_TYPE_HANDLER_H__
 #define GOOGLE_PROTOBUF_TYPE_HANDLER_H__
 
+#include <google/protobuf/parse_context.h>
+#include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
+#include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite_inl.h>
 
 #ifdef SWIG
@@ -165,6 +168,9 @@
   static inline int GetCachedSize(const MapEntryAccessorType& value);
   static inline bool Read(io::CodedInputStream* input,
                           MapEntryAccessorType* value);
+  static inline const char* Read(const char* ptr, ParseContext* ctx,
+                                 MapEntryAccessorType* value);
+
   static inline void Write(int field, const MapEntryAccessorType& value,
                            io::CodedOutputStream* output);
   static inline uint8* WriteToArray(int field,
@@ -221,6 +227,8 @@
     static inline int GetCachedSize(const MapEntryAccessorType& value);       \
     static inline bool Read(io::CodedInputStream* input,                      \
                             MapEntryAccessorType* value);                     \
+    static inline const char* Read(const char* begin, ParseContext* ctx,      \
+                                   MapEntryAccessorType* value);              \
     static inline void Write(int field, const MapEntryAccessorType& value,    \
                              io::CodedOutputStream* output);                  \
     static inline uint8* WriteToArray(int field,                              \
@@ -422,6 +430,96 @@
   return WireFormatLite::ReadBytes(input, value);
 }
 
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  return ctx->ParseMessage(value, ptr);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+template <typename Type>
+const char* MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read(
+    const char* ptr, ParseContext* ctx, MapEntryAccessorType* value) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  return ctx->ReadString(ptr, size, value);
+}
+
+inline const char* ReadINT64(const char* ptr, int64* value) {
+  return ParseVarint64(ptr, reinterpret_cast<uint64*>(value));
+}
+inline const char* ReadUINT64(const char* ptr, uint64* value) {
+  return ParseVarint64(ptr, value);
+}
+inline const char* ReadINT32(const char* ptr, int32* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = static_cast<uint32>(tmp);
+  return res;
+}
+inline const char* ReadUINT32(const char* ptr, uint32* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = static_cast<uint32>(tmp);
+  return res;
+}
+inline const char* ReadSINT64(const char* ptr, int64* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = WireFormatLite::ZigZagDecode64(tmp);
+  return res;
+}
+inline const char* ReadSINT32(const char* ptr, int32* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = WireFormatLite::ZigZagDecode32(static_cast<uint32>(tmp));
+  return res;
+}
+template <typename E>
+inline const char* ReadENUM(const char* ptr, E* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = static_cast<E>(tmp);
+  return res;
+}
+inline const char* ReadBOOL(const char* ptr, bool* value) {
+  uint64 tmp;
+  auto res = ParseVarint64(ptr, &tmp);
+  *value = static_cast<bool>(tmp);
+  return res;
+}
+
+template <typename F>
+inline const char* ReadUnaligned(const char* ptr, F* value) {
+  *value = UnalignedLoad<F>(ptr);
+  return ptr + sizeof(F);
+}
+inline const char* ReadFLOAT(const char* ptr, float* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadDOUBLE(const char* ptr, double* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED64(const char* ptr, uint64* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadFIXED32(const char* ptr, uint32* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED64(const char* ptr, int64* value) {
+  return ReadUnaligned(ptr, value);
+}
+inline const char* ReadSFIXED32(const char* ptr, int32* value) {
+  return ReadUnaligned(ptr, value);
+}
+
 #define READ_METHOD(FieldType)                                              \
   template <typename Type>                                                  \
   inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
@@ -429,6 +527,11 @@
     return WireFormatLite::ReadPrimitive<TypeOnMemory,                      \
                                          WireFormatLite::TYPE_##FieldType>( \
         input, value);                                                      \
+  }                                                                         \
+  template <typename Type>                                                  \
+  const char* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \
+      const char* begin, ParseContext* ctx, MapEntryAccessorType* value) {  \
+    return Read##FieldType(begin, value);                                   \
   }
 
 READ_METHOD(INT64)
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 3772594..d31f624 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -66,9 +66,6 @@
 namespace google {
 namespace protobuf {
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-using internal::ParseClosure;
-#endif
 using internal::ReflectionOps;
 using internal::WireFormat;
 using internal::WireFormatLite;
@@ -269,14 +266,14 @@
   return d->FindValueByNumber(val) != nullptr;
 }
 
-ParseClosure GetPackedField(const FieldDescriptor* field, Message* msg,
-                            const Reflection* reflection,
-                            internal::ParseContext* ctx) {
+const char* ParsePackedField(const FieldDescriptor* field, Message* msg,
+                             const Reflection* reflection, const char* ptr,
+                             internal::ParseContext* ctx) {
   switch (field->type()) {
 #define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, METHOD_NAME) \
   case FieldDescriptor::TYPE_##TYPE:                   \
-    return {internal::Packed##METHOD_NAME##Parser,     \
-            reflection->MutableRepeatedField<CPPTYPE>(msg, field)}
+    return internal::Packed##METHOD_NAME##Parser(      \
+        reflection->MutableRepeatedField<CPPTYPE>(msg, field), ptr, ctx)
     HANDLE_PACKED_TYPE(INT32, int32, Int32);
     HANDLE_PACKED_TYPE(INT64, int64, Int64);
     HANDLE_PACKED_TYPE(SINT32, int32, SInt32);
@@ -288,12 +285,11 @@
       auto object =
           internal::ReflectionAccessor::GetRepeatedEnum(reflection, field, msg);
       if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
-        return {internal::PackedEnumParser, object};
+        return internal::PackedEnumParser(object, ptr, ctx);
       } else {
-        ctx->extra_parse_data().SetEnumValidatorArg(
-            ReflectiveValidator, field->enum_type(),
+        return internal::PackedEnumParserArg(
+            object, ptr, ctx, ReflectiveValidator, field->enum_type(),
             reflection->MutableUnknownFields(msg), field->number());
-        return {internal::PackedValidEnumParserArg, object};
       }
     }
       HANDLE_PACKED_TYPE(FIXED32, uint32, Fixed32);
@@ -310,30 +306,40 @@
   }
 }
 
-ParseClosure GetLenDelim(int field_number, const FieldDescriptor* field,
-                         Message* msg, const Reflection* reflection,
-                         internal::ParseContext* ctx) {
+const char* ParseLenDelim(int field_number, const FieldDescriptor* field,
+                          Message* msg, const Reflection* reflection,
+                          const char* ptr, internal::ParseContext* ctx) {
   if (WireFormat::WireTypeForFieldType(field->type()) !=
       WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
     GOOGLE_DCHECK(field->is_packable());
-    return GetPackedField(field, msg, reflection, ctx);
+    return ParsePackedField(field, msg, reflection, ptr, ctx);
   }
   enum { kNone = 0, kVerify, kStrict } utf8_level = kNone;
-  internal::ParseFunc string_parsers[] = {internal::StringParser,
-                                          internal::StringParserUTF8Verify,
-                                          internal::StringParserUTF8};
+  const char* field_name = nullptr;
+  auto parse_string = [ptr, ctx, &utf8_level, &field_name](string* s) {
+    switch (utf8_level) {
+      case kNone:
+        return internal::InlineGreedyStringParser(s, ptr, ctx);
+      case kVerify:
+        return internal::InlineGreedyStringParserUTF8Verify(s, ptr, ctx,
+                                                            field_name);
+      case kStrict:
+        return internal::InlineGreedyStringParserUTF8(s, ptr, ctx, field_name);
+    }
+  };
   switch (field->type()) {
-    case FieldDescriptor::TYPE_STRING:
-      if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3
-      ) {
-        ctx->extra_parse_data().SetFieldName(field->full_name().c_str());
+    case FieldDescriptor::TYPE_STRING: {
+      bool enforce_utf8 = true;
+      bool utf8_verification = true;
+      if (enforce_utf8 &&
+          field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
         utf8_level = kStrict;
-      } else if (
-          true) {
-        ctx->extra_parse_data().SetFieldName(field->full_name().c_str());
+      } else if (utf8_verification) {
         utf8_level = kVerify;
       }
+      field_name = field->full_name().c_str();
       PROTOBUF_FALLTHROUGH_INTENDED;
+    }
     case FieldDescriptor::TYPE_BYTES: {
       if (field->is_repeated()) {
         int index = reflection->FieldSize(*msg, field);
@@ -343,11 +349,11 @@
             field->is_extension()) {
           auto object = reflection->MutableRepeatedPtrField<string>(msg, field)
                             ->Mutable(index);
-          return {string_parsers[utf8_level], object};
+          return parse_string(object);
         } else {
           auto object = reflection->MutableRepeatedPtrField<string>(msg, field)
                             ->Mutable(index);
-          return {string_parsers[utf8_level], object};
+          return parse_string(object);
         }
       } else {
         // Clear value and make sure it's set.
@@ -357,45 +363,42 @@
           // HACK around inability to get mutable_string in reflection
           string* object = &const_cast<string&>(
               reflection->GetStringReference(*msg, field, nullptr));
-          return {string_parsers[utf8_level], object};
+          return parse_string(object);
         } else {
           // HACK around inability to get mutable_string in reflection
           string* object = &const_cast<string&>(
               reflection->GetStringReference(*msg, field, nullptr));
-          return {string_parsers[utf8_level], object};
+          return parse_string(object);
         }
       }
       GOOGLE_LOG(FATAL) << "No other type than string supported";
     }
     case FieldDescriptor::TYPE_MESSAGE: {
       Message* object;
-      auto factory = ctx->extra_parse_data().factory;
       if (field->is_repeated()) {
-        object = reflection->AddMessage(msg, field, factory);
+        object = reflection->AddMessage(msg, field, ctx->data().factory);
       } else {
-        object = reflection->MutableMessage(msg, field, factory);
+        object = reflection->MutableMessage(msg, field, ctx->data().factory);
       }
-      return {object->_ParseFunc(), object};
+      return ctx->ParseMessage(object, ptr);
     }
     default:
       GOOGLE_LOG(FATAL) << "Wrong type for length delim " << field->type();
   }
-  return {};  // Make compiler happy.
+  return nullptr;  // Make compiler happy.
 }
 
-ParseClosure GetGroup(int field_number, const FieldDescriptor* field,
-                      Message* msg, const Reflection* reflection) {
-  Message* object;
+Message* GetGroup(int field_number, const FieldDescriptor* field, Message* msg,
+                  const Reflection* reflection) {
   if (field->is_repeated()) {
-    object = reflection->AddMessage(msg, field, nullptr);
+    return reflection->AddMessage(msg, field, nullptr);
   } else {
-    object = reflection->MutableMessage(msg, field, nullptr);
+    return reflection->MutableMessage(msg, field, nullptr);
   }
-  return {object->_ParseFunc(), object};
 }
 
-const char* Message::_InternalParse(const char* begin, const char* end,
-                                    void* object, internal::ParseContext* ctx) {
+const char* Message::_InternalParse(const char* ptr,
+                                    internal::ParseContext* ctx) {
   class ReflectiveFieldParser {
    public:
     ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx)
@@ -403,19 +406,18 @@
 
     void AddVarint(uint32 num, uint64 value) {
       if (is_item_ && num == 2) {
-        if (!ctx_->extra_parse_data().payload.empty()) {
+        if (!payload_.empty()) {
           auto field = Field(value, 2);
           if (field && field->message_type()) {
             auto child = reflection_->MutableMessage(msg_, field);
             // TODO(gerbens) signal error
-            child->ParsePartialFromString(ctx_->extra_parse_data().payload);
+            child->ParsePartialFromString(payload_);
           } else {
-            MutableUnknown()->AddLengthDelimited(value)->swap(
-                ctx_->extra_parse_data().payload);
+            MutableUnknown()->AddLengthDelimited(value)->swap(payload_);
           }
           return;
         }
-        ctx_->extra_parse_data().field_number = value;
+        type_id_ = value;
         return;
       }
       auto field = Field(num, 0);
@@ -433,38 +435,41 @@
         MutableUnknown()->AddFixed64(num, value);
       }
     }
-    ParseClosure AddLengthDelimited(uint32 num, uint32) {
+    const char* ParseLengthDelimited(uint32 num, const char* ptr,
+                                     internal::ParseContext* ctx) {
       if (is_item_ && num == 3) {
-        int type_id = ctx_->extra_parse_data().field_number;
-        if (type_id == 0) {
-          return {internal::StringParser, &ctx_->extra_parse_data().payload};
+        if (type_id_ == 0) {
+          return InlineGreedyStringParser(&payload_, ptr, ctx);
         }
-        ctx_->extra_parse_data().field_number = 0;
-        num = type_id;
+        num = type_id_;
+        type_id_ = 0;
       }
       auto field = Field(num, 2);
       if (field) {
-        return GetLenDelim(num, field, msg_, reflection_, ctx_);
+        return ParseLenDelim(num, field, msg_, reflection_, ptr, ctx);
       } else {
-        return {internal::StringParser,
-                MutableUnknown()->AddLengthDelimited(num)};
+        return InlineGreedyStringParser(
+            MutableUnknown()->AddLengthDelimited(num), ptr, ctx);
       }
     }
-    ParseClosure StartGroup(uint32 num) {
+    const char* ParseGroup(uint32 num, const char* ptr,
+                           internal::ParseContext* ctx) {
       if (!is_item_ && descriptor_->options().message_set_wire_format() &&
           num == 1) {
-        ctx_->extra_parse_data().payload.clear();
-        ctx_->extra_parse_data().field_number = 0;
-        return {ItemParser, msg_};
+        is_item_ = true;
+        ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
+        is_item_ = false;
+        type_id_ = 0;
+        return ptr;
       }
       auto field = Field(num, 3);
       if (field) {
-        return GetGroup(num, field, msg_, reflection_);
+        auto msg = GetGroup(num, field, msg_, reflection_);
+        return ctx->ParseGroup(msg, ptr, num * 8 + 3);
       } else {
-        return {internal::UnknownGroupParse, MutableUnknown()->AddGroup(num)};
+        return UnknownFieldParse(num * 8 + 3, MutableUnknown(), ptr, ctx);
       }
     }
-    void EndGroup(uint32 num) {}
     void AddFixed32(uint32 num, uint32 value) {
       auto field = Field(num, 5);
       if (field) {
@@ -474,6 +479,12 @@
       }
     }
 
+    const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) {
+      // We're parsing the a MessageSetItem
+      GOOGLE_DCHECK(is_item_);
+      return internal::WireFormatParser(*this, ptr, ctx);
+    }
+
    private:
     Message* msg_;
     const Descriptor* descriptor_;
@@ -481,6 +492,8 @@
     internal::ParseContext* ctx_;
     UnknownFieldSet* unknown_ = nullptr;
     bool is_item_ = false;
+    uint32 type_id_ = 0;
+    string payload_;
 
     ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx,
                           bool is_item)
@@ -498,7 +511,7 @@
 
       // If that failed, check if the field is an extension.
       if (field == nullptr && descriptor_->IsExtensionNumber(num)) {
-        const DescriptorPool* pool = ctx_->extra_parse_data().pool;
+        const DescriptorPool* pool = ctx_->data().pool;
         if (pool == NULL) {
           field = reflection_->FindKnownExtensionByNumber(num);
         } else {
@@ -524,19 +537,10 @@
       if (unknown_) return unknown_;
       return unknown_ = reflection_->MutableUnknownFields(msg_);
     }
-
-    static const char* ItemParser(const char* begin, const char* end,
-                                  void* object, internal::ParseContext* ctx) {
-      auto msg = static_cast<Message*>(object);
-      ReflectiveFieldParser field_parser(msg, ctx, true);
-      return internal::WireFormatParser({ItemParser, object}, field_parser,
-                                        begin, end, ctx);
-    }
   };
 
-  ReflectiveFieldParser field_parser(static_cast<Message*>(object), ctx);
-  return internal::WireFormatParser({_InternalParse, object}, field_parser,
-                                    begin, end, ctx);
+  ReflectiveFieldParser field_parser(this, ctx);
+  return internal::WireFormatParser(field_parser, ptr, ctx);
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 02cca53..7fa17ed 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -321,20 +321,16 @@
   void Clear() override;
   bool IsInitialized() const override;
   void CheckTypeAndMergeFrom(const MessageLite& other) override;
-#if !GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+  // Reflective parser
+  const char* _InternalParse(const char* ptr,
+                             internal::ParseContext* ctx) override;
+#else
   bool MergePartialFromCodedStream(io::CodedInputStream* input) override;
 #endif
   size_t ByteSizeLong() const override;
   void SerializeWithCachedSizes(io::CodedOutputStream* output) const override;
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  internal::ParseFunc _ParseFunc() const override { return _InternalParse; }
-
-  // Reflective parser
-  static const char* _InternalParse(const char* begin, const char* end,
-                                    void* object, internal::ParseContext* ctx);
-#endif
-
  private:
   // This is called only by the default implementation of ByteSize(), to
   // update the cached size.  If you override ByteSize(), you do not need
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 2f1261c..1df371a 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -44,8 +44,8 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/arena.h>
-#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/stubs/strutil.h>
@@ -117,92 +117,39 @@
 namespace internal {
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-template <typename Next>
-bool ParseStream(const Next& next, MessageLite* msg) {
-  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
-  EpsCopyParser<false> parser({msg->_ParseFunc(), msg}, &ctx);
-  auto range = next();
-  while (!range.empty()) {
-    if (!parser.Parse(range)) return false;
-    range = next();
-  }
-  return parser.Done();
-}
 
 template <bool aliasing>
 bool MergePartialFromImpl(StringPiece input, MessageLite* msg) {
-  auto begin = input.data();
-  int size = input.size();
-  ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
-  internal::ParseClosure parser = {msg->_ParseFunc(), msg};
-  // TODO(gerbens) fine tune
-  constexpr int kThreshold = 48;
-  static_assert(kThreshold >= ParseContext::kSlopBytes,
-                "Requires enough room for at least kSlopBytes to be copied.");
-  // TODO(gerbens) This could be left uninitialized and given an MSAN
-  // annotation instead.
-  char buffer[kThreshold + ParseContext::kSlopBytes] = {};
-  if (size <= kThreshold) {
-    std::memcpy(buffer, begin, size);
-    if (aliasing) {
-      ctx.extra_parse_data().aliasing =
-          reinterpret_cast<std::uintptr_t>(begin) -
-          reinterpret_cast<std::uintptr_t>(buffer);
-    }
-    return ctx.ParseExactRange(parser, buffer, buffer + size);
-  }
-  if (aliasing) {
-    ctx.extra_parse_data().aliasing = ParseContext::ExtraParseData::kNoDelta;
-  }
-  size -= ParseContext::kSlopBytes;
-  int overrun = 0;
-  ctx.StartParse(parser);
-  if (!ctx.ParseRange(StringPiece(begin, size), &overrun)) return false;
-  begin += size;
-  std::memcpy(buffer, begin, ParseContext::kSlopBytes);
-  if (aliasing) {
-    ctx.extra_parse_data().aliasing = reinterpret_cast<std::uintptr_t>(begin) -
-        reinterpret_cast<std::uintptr_t>(buffer);
-  }
-  return ctx.ParseRange({buffer, ParseContext::kSlopBytes}, &overrun) &&
-         ctx.ValidEnd(overrun);
-}
-
-StringPiece Next(BoundedZCIS* input) {
-  const void* data;
-  int size;
-  if (input->limit == 0) return {};
-  while (input->zcis->Next(&data, &size)) {
-    if (size != 0) {
-      input->limit -= size;
-      if (input->limit < 0) {
-        size += input->limit;
-        input->zcis->BackUp(-input->limit);
-        input->limit = 0;
-      }
-      return StringPiece(static_cast<const char*>(data), size);
-    }
-  }
-  return {};
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  return ctx.AtLegitimateEnd(msg->_InternalParse(ptr, &ctx));
 }
 
 template <bool aliasing>
 bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg) {
-  // TODO(gerbens) implement aliasing
-  auto next = [&input]() { return Next(&input); };
-  return ParseStream(next, msg) && input.limit == 0;
+  // TODO(gerbens) Circumvent CIS, to prevent slop region check overhead.
+  // Tricky case. If we limit ZeroCopyInputStream we need to make sure it's
+  // left precisely at the limit. However EpsCopyInputStream will always be
+  // 16 (kSlopBytes) bytes ahead of ZeroCopyInputStream, which means it's
+  // potentially a buffer ahead from which we can't rollback. Hence we must
+  // ensure we don't read more than the limit.
+  // TODO(gerbens) consider putting logic in EpsCopyInputStream to put an
+  // overall limit on the number of bytes it pulls from the underlying stream.
+  io::CodedInputStream cis(input.zcis);
+  cis.PushLimit(input.limit);
+  return msg->MergePartialFromCodedStream(&cis) && cis.BytesUntilLimit() == 0;
 }
 
 template <bool aliasing>
 bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg) {
-  // TODO(gerbens) implement aliasing
-  BoundedZCIS bounded_zcis{input, INT_MAX};
-  auto next = [&bounded_zcis]() { return Next(&bounded_zcis); };
-  return ParseStream(next, msg) && bounded_zcis.limit > 0;
+  const char* ptr;
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
+                             aliasing, &ptr, input);
+  return ctx.AtLegitimateEnd(msg->_InternalParse(ptr, &ctx));
 }
 
-
-#else
+#else  // !GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 inline bool InlineMergePartialEntireStream(io::CodedInputStream* cis,
                                            MessageLite* message,
@@ -232,7 +179,7 @@
   return InlineMergePartialEntireStream(&decoder, msg, aliasing);
 }
 
-#endif
+#endif  // !GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 template bool MergePartialFromImpl<false>(StringPiece input,
                                           MessageLite* msg);
@@ -256,43 +203,46 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
-  // MergePartialFromCodedStream must leave input in "exactly" the same state
-  // as the old implementation. At least when the parse is successful. For
-  // MergePartialFromCodedStream a successful parse can also occur by ending
-  // on a zero tag or an end-group tag. In these cases input is left precisely
-  // past the terminating tag and last_tag_ is set to the terminating tags
-  // value. If the parse ended on a limit (either a pushed limit or end of the
-  // ZeroCopyInputStream) legitimate_end_ is set to true.
-  int size = 0;
-  auto next = [input, &size]() {
-    const void* ptr;
-    input->Skip(size);  // skip previous buffer
-    if (!input->GetDirectBufferPointer(&ptr, &size)) return StringPiece{};
-    return StringPiece(static_cast<const char*>(ptr), size);
-  };
-  internal::ParseContext ctx(input->RecursionBudget());
-  ctx.extra_parse_data().pool = input->GetExtensionPool();
-  ctx.extra_parse_data().factory = input->GetExtensionFactory();
-  internal::EpsCopyParser<true> parser({_ParseFunc(), this}, &ctx);
-  auto range = next();
-  while (!range.empty()) {
-    if (!parser.Parse(range)) {
-      if (!ctx.EndedOnTag()) return false;
-      // Parse ended on a zero or end-group tag, leave the stream in the
-      // appropriate state. Note we only skip forward, due to using
-      // ensure_non_negative_skip being set to true in parser.
-      input->Skip(parser.Skip());
-      input->SetLastTag(ctx.LastTag());
-      return true;
-    }
-    range = next();
+class ZeroCopyCodedInputStream : public io::ZeroCopyInputStream {
+ public:
+  ZeroCopyCodedInputStream(io::CodedInputStream* cis) : cis_(cis) {}
+  bool Next(const void** data, int* size) final {
+    if (!cis_->GetDirectBufferPointer(data, size)) return false;
+    cis_->Skip(*size);
+    return true;
   }
-  if (!parser.Done()) return false;
-  input->SetConsumed();
+  void BackUp(int count) final { cis_->Advance(-count); }
+  bool Skip(int count) final { return cis_->Skip(count); }
+  int64 ByteCount() const final { return 0; }
+
+  bool aliasing_enabled() { return cis_->aliasing_enabled_; }
+
+ private:
+  io::CodedInputStream* cis_;
+};
+
+bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
+  ZeroCopyCodedInputStream zcis(input);
+  const char* ptr;
+  internal::ParseContext ctx(input->RecursionBudget(), zcis.aliasing_enabled(),
+                             &ptr, &zcis);
+  // MergePartialFromCodedStream allows terminating the wireformat by 0 or
+  // end-group tag. Leaving it up to the caller to verify correct ending by
+  // calling LastTagWas on input. We need to maintain this behavior.
+  ctx.TrackCorrectEnding();
+  ctx.data().pool = input->GetExtensionPool();
+  ctx.data().factory = input->GetExtensionFactory();
+  ptr = _InternalParse(ptr, &ctx);
+  if (!ptr) return false;
+  ctx.BackUp(ptr);
+  if (ctx.LastTagMinus1() != 0) {
+    input->SetLastTag(ctx.LastTagMinus1() + 1);
+    return true;
+  }
+  if (ctx.AtLimit(ptr)) input->SetConsumed();
   return true;
 }
-#endif
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
   return MergePartialFromCodedStream(input) && IsInitializedWithErrors();
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 1e07141..61c2d2a 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -41,6 +41,7 @@
 
 #include <climits>
 #include <string>
+
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/arena.h>
@@ -71,12 +72,8 @@
 }  // namespace io
 namespace internal {
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 // See parse_context.h for explanation
 class ParseContext;
-typedef const char* (*ParseFunc)(const char* ptr, const char* end, void* object,
-                                 ParseContext* ctx);
-#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
 class RepeatedPtrFieldBase;
 class WireFormatLite;
@@ -401,9 +398,8 @@
   virtual int GetCachedSize() const = 0;
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  virtual internal::ParseFunc _ParseFunc() const {
-    GOOGLE_LOG(FATAL) << "Type " << GetTypeName()
-               << " doesn't implement _InternalParse";
+  virtual const char* _InternalParse(const char* ptr,
+                                     internal::ParseContext* ctx) {
     return nullptr;
   }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -496,7 +492,6 @@
 extern template bool MergePartialFromImpl<true>(BoundedZCIS input,
                                                 MessageLite* msg);
 
-
 template <typename T>
 struct SourceWrapper;
 
@@ -511,8 +506,8 @@
 bool MessageLite::ParseFrom(const T& input) {
   if (flags & kParse) Clear();
   constexpr bool alias = flags & kMergeWithAliasing;
-  return internal::MergePartialFromImpl<alias>(input, this) &&
-         ((flags & kMergePartial) || IsInitializedWithErrors());
+  bool res = internal::MergePartialFromImpl<alias>(input, this);
+  return res && ((flags & kMergePartial) || IsInitializedWithErrors());
 }
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index a522966..2954105 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -32,6 +32,7 @@
 
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -43,51 +44,18 @@
 namespace protobuf {
 namespace internal {
 
-bool ParseContext::ParseEndsInSlopRegion(const char* begin, int overrun) const {
+namespace {
+
+// Only call if at start of tag.
+bool ParseEndsInSlopRegion(const char* begin, int overrun, int d) {
+  constexpr int kSlopBytes = EpsCopyInputStream::kSlopBytes;
   GOOGLE_DCHECK(overrun >= 0);
   GOOGLE_DCHECK(overrun <= kSlopBytes);
   auto ptr = begin + overrun;
   auto end = begin + kSlopBytes;
-  int n = end - ptr;
-  if (n == 0) return false;
-  // If limit_ != -1 then the parser will continue to parse at least limit_
-  // bytes (or more if on the stack there are further limits)
-  int d = depth_;
-  if (limit_ != -1) {
-    GOOGLE_DCHECK(d < start_depth_);  // Top-level never has a limit.
-    // rewind the stack until all limits disappear.
-    int limit = limit_;
-    if (limit >= n) return false;
-    while (d < start_depth_) {
-      int delta = stack_[d++].delta_or_group_num;
-      if (delta == -1) {
-        // We found the first limit that was pushed. We should inspect from
-        // this point on.
-        ptr += limit;
-        break;
-      } else if (delta >= 0) {
-        // We reached end of a length delimited subfield. Adjust limit
-        limit += delta;
-        if (limit >= n) return false;
-      } else {
-        // It's a group we assume the format is correct and this group
-        // is properly ended before the limit is reached.
-      }
-    }
-  }
-  d = start_depth_ - d;  // We just keep track of the depth from start.
-  // We verify that a generic parse of the buffer won't, validly, end the parse
-  // before end, due to ending the top-level on a 0 or end-group tag.
-  // IMPORTANT NOTE: we return false in failure cases. This is
-  // important because we could fail due to overrunning the buffer and read
-  // garbage data beyond the buffer (valid reads just left over garbage). So
-  // failure doesn't imply the parse will fail. So if this loops fails while
-  // the real parse would succeed it means the real parse will read beyond the
-  // boundary. If the real parse fails we can't reasonably continue the stream
-  // any way so we make no attempt to leave the stream at a well specified pos.
   while (ptr < end) {
     uint32 tag;
-    ptr = io::Parse32(ptr, &tag);
+    ptr = ReadTag(ptr, &tag);
     if (ptr == nullptr || ptr > end) return false;
     // ending on 0 tag is allowed and is the major reason for the necessity of
     // this function.
@@ -95,7 +63,7 @@
     switch (tag & 7) {
       case 0: {  // Varint
         uint64 val;
-        ptr = io::Parse64(ptr, &val);
+        ptr = ParseVarint64(ptr, &val);
         if (ptr == nullptr) return false;
         break;
       }
@@ -104,9 +72,8 @@
         break;
       }
       case 2: {  // len delim
-        uint32 size;
-        ptr = io::Parse32(ptr, &size);
-        if (ptr == nullptr) return false;
+        int32 size = ReadSize(&ptr);
+        if (ptr == nullptr || size > end - ptr) return false;
         ptr += size;
         break;
       }
@@ -129,312 +96,151 @@
   return false;
 }
 
-void ParseContext::SwitchStack() {
-  stack_ = new State[start_depth_];
-  std::memcpy(stack_ + inlined_depth_, inline_stack_, sizeof(inline_stack_));
-  inlined_depth_ = -1;  // Special value to indicate stack_ needs to be deleted
+}  // namespace
+
+const char* EpsCopyInputStream::Next(int overrun, int d) {
+  if (next_chunk_ == nullptr) return nullptr;  // We've reached end of stream.
+  if (next_chunk_ != buffer_) {
+    GOOGLE_DCHECK(size_ > kSlopBytes);
+    // The chunk is large enough to be used directly
+    buffer_end_ = next_chunk_ + size_ - kSlopBytes;
+    auto res = next_chunk_;
+    next_chunk_ = buffer_;
+    if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+    return res;
+  }
+  // Move the slop bytes of previous buffer to start of the patch buffer.
+  // Note we must use memmove because the previous buffer could be part of
+  // buffer_.
+  std::memmove(buffer_, buffer_end_, kSlopBytes);
+  if (zcis_ && (d < 0 || !ParseEndsInSlopRegion(buffer_, overrun, d))) {
+    const void* data;
+    // ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
+    // we loop.
+    while (zcis_->Next(&data, &size_)) {
+      if (size_ > kSlopBytes) {
+        // We got a large chunk
+        std::memcpy(buffer_ + kSlopBytes, data, kSlopBytes);
+        next_chunk_ = static_cast<const char*>(data);
+        buffer_end_ = buffer_ + kSlopBytes;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      } else if (size_ > 0) {
+        std::memcpy(buffer_ + kSlopBytes, data, size_);
+        next_chunk_ = buffer_;
+        buffer_end_ = buffer_ + size_;
+        if (aliasing_ >= kNoDelta) aliasing_ = kOnPatch;
+        return buffer_;
+      }
+      GOOGLE_DCHECK(size_ == 0) << size_;
+    }
+  }
+  // End of stream or array
+  if (aliasing_ == kNoDelta) {
+    // If there is no more block and aliasing is true, the previous block
+    // is still valid and we can alias. We have users relying on string_view's
+    // obtained from protos to outlive the proto, when the parse was from an
+    // array. This guarantees string_view's are always aliased if parsed from
+    // an array.
+    aliasing_ = reinterpret_cast<std::uintptr_t>(buffer_end_) -
+                reinterpret_cast<std::uintptr_t>(buffer_);
+  }
+  next_chunk_ = nullptr;
+  buffer_end_ = buffer_ + kSlopBytes;
+  size_ = 0;
+  return buffer_;
 }
 
-std::pair<bool, int> ParseContext::ParseRangeWithLimit(const char* begin,
-                                                       const char* end) {
-  auto ptr = begin;
+std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
+                                                              int d) {
+  GOOGLE_DCHECK(ptr >= limit_end_);
+  int overrun = ptr - buffer_end_;
+  GOOGLE_DCHECK(overrun <= kSlopBytes);  // Guaranteed by parse loop.
+  GOOGLE_DCHECK(overrun != limit_);
+  // We either exceeded the limit (parse error) or we need to get new data.
+  // Did we exceed the limit? Is so parse error.
+  if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) {
+    return {nullptr, true};
+  }
+  GOOGLE_DCHECK(overrun <= limit_);  // Follows from above
+  // At this point we know the following assertion holds.
+  GOOGLE_DCHECK(limit_ > 0);
+  GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
   do {
-    GOOGLE_DCHECK(ptr < end);
-    const char* limited_end;
-    if (limit_ == -1) {
-      limited_end = end;
-    } else {
-      GOOGLE_DCHECK(limit_ > 0);
-      limited_end = ptr + std::min(static_cast<int32>(end - ptr), limit_);
-      limit_ -= limited_end - ptr;
-    }
-    // Parse the range [ptr, limited_end). The only case (except for error) that
-    // the parser can return prematurely (before limited_end) is on encountering
-    // an end-group. If this is the case we continue parsing the range with
-    // the parent parser.
-    do {
-      GOOGLE_DCHECK(ptr < limited_end);
-      ptr = parser_(ptr, limited_end, this);
-      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
-        // Clear last_tag_minus_1_ so that the hard error encountered is not
-        // mistaken for ending on a tag.
-        last_tag_minus_1_ = 0;
-        return {};
-      }
-      if (!EndedOnTag()) {
-        // The parser ended still parsing the initial message. This can only
-        // happen because it crossed the end.
-        GOOGLE_DCHECK(ptr >= limited_end);
-        break;
-      }
-      // Child parser terminated on an end-group / 0 tag.
-      GOOGLE_DCHECK(depth_ <= start_depth_);
-      if (depth_ == start_depth_) {
-        // The parse was already at the top-level and there is no parent.
-        // This can happen due to encountering 0 or due to this parser being
-        // called for parsing a sub-group message in custom parsing code.
-        return {false, static_cast<int>(ptr - end)};
-      }
-      auto state = Pop();
-      // Verify the ending tag is correct and continue parsing the range with
-      // the parent parser.
-      uint32 group_number = last_tag_minus_1_ >> 3;
-      // We need to clear last_tag_minus_1_, either for the next iteration
-      // or if the if statement below returns.
-      last_tag_minus_1_ = 0;
-      if (state.delta_or_group_num != ~group_number) return {};
-      parser_ = state.parser;  // Load parent parser
-    } while (ptr < limited_end);
-    int overrun = ptr - limited_end;
+    // We are past the end of buffer_end_, in the slop region.
     GOOGLE_DCHECK(overrun >= 0);
-    GOOGLE_DCHECK(overrun <= kSlopBytes);  // wireformat guarantees this limit
-    if (limit_ != -1) {
-      limit_ -= overrun;  // Adjust limit relative to new position.
-      if (limit_ < 0) return {};  // We overrun the limit
-      while (limit_ == 0) {
-        // We are at an actual ending of a length delimited field.
-        // The top level has no limit (ie. limit_ == -1) so we can assert
-        // that the stack is non-empty.
-        GOOGLE_DCHECK(depth_ < start_depth_);
-        // else continue parsing the parent message.
-        auto state = Pop();
-        parser_ = state.parser;
-        limit_ = state.delta_or_group_num;
-        // No group ending is possible here. Any group on the stack still
-        // needs to read its end-group tag and can't be on a limit_ == 0.
-        if (limit_ < -1) return {};
+    auto p = Next(overrun, d);
+    if (p == nullptr) {
+      // We are at the end of the stream
+      if (PROTOBUF_PREDICT_FALSE(overrun != 0)) {
+        return {nullptr, true};
       }
+      GOOGLE_DCHECK(limit_ > 0);
+      limit_end_ = buffer_end_;
+      return {ptr, true};
     }
-  } while (ptr < end);
-  return {true, static_cast<int>(ptr - end)};
+    limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
+    ptr = p + overrun;
+    overrun = ptr - buffer_end_;
+  } while (overrun >= 0);
+  limit_end_ = buffer_end_ + std::min(0, limit_);
+  return {ptr, false};
 }
 
-const char* StringParser(const char* begin, const char* end, void* object,
-                         ParseContext*) {
-  auto str = static_cast<string*>(object);
-  str->append(begin, end - begin);
-  return end;
+const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
+  return AppendSize(ptr, size, [](const char* p, int s) {});
 }
 
-// Defined in wire_format_lite.cc
-void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
-                       bool emit_stacktrace);
-
-bool VerifyUTF8(StringPiece str, ParseContext* ctx) {
-  if (!IsStructurallyValidUTF8(str)) {
-    PrintUTF8ErrorLog(ctx->extra_parse_data().FieldName(), "parsing", false);
-    return false;
-  }
-  return true;
+const char* EpsCopyInputStream::ReadStringFallback(const char* ptr, int size,
+                                                   string* s) {
+  s->clear();
+  return AppendStringFallback(ptr, size, s);
 }
 
-const char* StringParserUTF8(const char* begin, const char* end, void* object,
-                             ParseContext* ctx) {
-  StringParser(begin, end, object, ctx);
-  if (ctx->AtLimit()) {
-    auto str = static_cast<string*>(object);
-    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
-  }
-  return end;
-}
-
-const char* StringParserUTF8Verify(const char* begin, const char* end,
-                                   void* object, ParseContext* ctx) {
-  StringParser(begin, end, object, ctx);
-#ifndef NDEBUG
-  if (ctx->AtLimit()) {
-    auto str = static_cast<string*>(object);
-    VerifyUTF8(*str, ctx);
-  }
-#endif
-  return end;
+const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
+                                                     string* str) {
+  return AppendSize(ptr, size,
+                    [str](const char* p, int s) { str->append(p, s); });
 }
 
 
-const char* GreedyStringParser(const char* begin, const char* end, void* object,
-                         ParseContext* ctx) {
-  auto str = static_cast<string*>(object);
-  auto limit = ctx->CurrentLimit();
-  GOOGLE_DCHECK(limit != -1);  // Always length delimited
-  end += std::min<int>(limit, ParseContext::kSlopBytes);
-  str->append(begin, end - begin);
-  return end;
+template <typename Tag, typename T>
+const char* EpsCopyInputStream::ReadRepeatedFixed(const char* ptr,
+                                                  Tag expected_tag,
+                                                  RepeatedField<T>* out) {
+  do {
+    out->Add(UnalignedLoad<T>(ptr));
+    ptr += sizeof(T);
+    if (PROTOBUF_PREDICT_FALSE(ptr >= limit_end_)) return ptr;
+  } while (UnalignedLoad<Tag>(ptr) == expected_tag&& ptr += sizeof(Tag));
+  return ptr;
 }
 
-const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
-                             ParseContext* ctx) {
-  auto limit = ctx->CurrentLimit();
-  GOOGLE_DCHECK(limit != -1);  // Always length delimited
-  bool at_end;
-  if (limit <= ParseContext::kSlopBytes) {
-    end += limit;
-    at_end = true;
-  } else {
-    end += ParseContext::kSlopBytes;
-    at_end =false;
-  }
-  auto str = static_cast<string*>(object);
-  str->append(begin, end - begin);
-  if (at_end) {
-    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
-  }
-  return end;
-}
-
-const char* GreedyStringParserUTF8Verify(const char* begin, const char* end, void* object,
-                             ParseContext* ctx) {
-  auto limit = ctx->CurrentLimit();
-  GOOGLE_DCHECK(limit != -1);  // Always length delimited
-  bool at_end;
-  if (limit <= ParseContext::kSlopBytes) {
-    end += limit;
-    at_end = true;
-  } else {
-    end += ParseContext::kSlopBytes;
-    at_end =false;
-  }
-  auto str = static_cast<string*>(object);
-  str->append(begin, end - begin);
-  if (at_end) {
-#ifndef NDEBUG
-    VerifyUTF8(*str, ctx);
-#endif
-  }
-  return end;
-}
-
-template <typename T, bool sign>
-const char* VarintParser(const char* begin, const char* end, void* object,
-                         ParseContext*) {
-  auto repeated_field = static_cast<RepeatedField<T>*>(object);
-  auto ptr = begin;
-  while (ptr < end) {
-    uint64 varint;
-    ptr = io::Parse64(ptr, &varint);
-    if (!ptr) return nullptr;
-    T val;
-    if (sign) {
-      if (sizeof(T) == 8) {
-        val = WireFormatLite::ZigZagDecode64(varint);
-      } else {
-        val = WireFormatLite::ZigZagDecode32(varint);
-      }
+const char* EpsCopyInputStream::InitFrom(io::ZeroCopyInputStream* zcis) {
+  zcis_ = zcis;
+  const void* data;
+  int size;
+  if (zcis->Next(&data, &size)) {
+    if (size > kSlopBytes) {
+      auto ptr = static_cast<const char*>(data);
+      limit_ -= size - kSlopBytes;
+      limit_end_ = buffer_end_ = ptr + size - kSlopBytes;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return ptr;
     } else {
-      val = varint;
+      auto ptr = buffer_ + 2 * kSlopBytes - size;
+      std::memcpy(ptr, data, size);
+      return ptr;
     }
-    repeated_field->Add(val);
   }
-  return ptr;
+  next_chunk_ = nullptr;
+  size_ = 0;
+  limit_ = 0;
+  limit_end_ = buffer_end_ = buffer_;
+  return buffer_;
 }
 
-template <typename T>
-const char* FixedParser(const char* begin, const char* end, void* object,
-                        ParseContext*) {
-  auto repeated_field = static_cast<RepeatedField<T>*>(object);
-  int num = (end - begin + sizeof(T) - 1) / sizeof(T);
-
-  const int old_entries = repeated_field->size();
-  repeated_field->Reserve(old_entries + num);
-  std::memcpy(repeated_field->AddNAlreadyReserved(num), begin, num * sizeof(T));
-  return begin + num * sizeof(T);
-}
-
-const char* PackedInt32Parser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx) {
-  return VarintParser<int32, false>(begin, end, object, ctx);
-}
-const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx) {
-  return VarintParser<uint32, false>(begin, end, object, ctx);
-}
-const char* PackedInt64Parser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx) {
-  return VarintParser<int64, false>(begin, end, object, ctx);
-}
-const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx) {
-  return VarintParser<uint64, false>(begin, end, object, ctx);
-}
-const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx) {
-  return VarintParser<int32, true>(begin, end, object, ctx);
-}
-const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx) {
-  return VarintParser<int64, true>(begin, end, object, ctx);
-}
-
-const char* PackedEnumParser(const char* begin, const char* end, void* object,
-                             ParseContext* ctx) {
-  return VarintParser<int, false>(begin, end, object, ctx);
-}
-
-const char* PackedValidEnumParserLite(const char* begin, const char* end,
-                                      void* object, ParseContext* ctx) {
-  auto repeated_field = static_cast<RepeatedField<int>*>(object);
-  auto ptr = begin;
-  while (ptr < end) {
-    uint64 varint;
-    ptr = io::Parse64(ptr, &varint);
-    if (!ptr) return nullptr;
-    int val = varint;
-    if (ctx->extra_parse_data().ValidateEnum<string>(val))
-      repeated_field->Add(val);
-  }
-  return ptr;
-}
-
-const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
-                                         void* object, ParseContext* ctx) {
-  auto repeated_field = static_cast<RepeatedField<int>*>(object);
-  auto ptr = begin;
-  while (ptr < end) {
-    uint64 varint;
-    ptr = io::Parse64(ptr, &varint);
-    if (!ptr) return nullptr;
-    int val = varint;
-    if (ctx->extra_parse_data().ValidateEnumArg<string>(val))
-      repeated_field->Add(val);
-  }
-  return ptr;
-}
-
-const char* PackedBoolParser(const char* begin, const char* end, void* object,
-                             ParseContext* ctx) {
-  return VarintParser<bool, false>(begin, end, object, ctx);
-}
-
-const char* PackedFixed32Parser(const char* begin, const char* end,
-                                void* object, ParseContext* ctx) {
-  return FixedParser<uint32>(begin, end, object, ctx);
-}
-const char* PackedSFixed32Parser(const char* begin, const char* end,
-                                 void* object, ParseContext* ctx) {
-  return FixedParser<int32>(begin, end, object, ctx);
-}
-const char* PackedFixed64Parser(const char* begin, const char* end,
-                                void* object, ParseContext* ctx) {
-  return FixedParser<uint64>(begin, end, object, ctx);
-}
-const char* PackedSFixed64Parser(const char* begin, const char* end,
-                                 void* object, ParseContext* ctx) {
-  return FixedParser<int64>(begin, end, object, ctx);
-}
-const char* PackedFloatParser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx) {
-  return FixedParser<float>(begin, end, object, ctx);
-}
-const char* PackedDoubleParser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx) {
-  return FixedParser<double>(begin, end, object, ctx);
-}
-
-const char* NullParser(const char* begin, const char* end, void* object,
-                       ParseContext* ctx) {
-  return end;
-}
-
-void WriteVarint(uint64 val, string* s) {
+inline void WriteVarint(uint64 val, string* s) {
   while (val >= 128) {
     uint8 c = val | 0x80;
     s->push_back(c);
@@ -454,6 +260,255 @@
   s->append(val.data(), val.size());
 }
 
+std::pair<const char*, uint32> Parse32Fallback(const char* p, uint32 res) {
+  uint32 extra = 128 + 128 * 128;
+  for (std::uint32_t i = 0; i < 3; i++) {
+    std::uint32_t byte = static_cast<uint8>(p[i]);
+    res += byte << (7 * (i + 2));
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res - extra};
+    }
+    extra += (1ull << (7 * (i + 3)));
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint32> FinishReadTag1Fallback(const char* p, uint32 res) {
+  uint32 extra = 128;
+  for (std::uint32_t i = 0; i < 4; i++) {
+    std::uint32_t byte = static_cast<uint8>(p[i]);
+    res += byte << (7 * (i + 1));
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res - extra};
+    }
+    extra += (1ull << (7 * (i + 2)));
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint32> FinishReadTag2Fallback(const char* p, uint32 res) {
+  uint32 extra = 128 * 128;
+  for (std::uint32_t i = 0; i < 3; i++) {
+    std::uint32_t byte = static_cast<uint8>(p[i]);
+    res += byte << (7 * (i + 2));
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      return {p + i + 1, res - extra};
+    }
+    extra += (1ull << (7 * (i + 3)));
+  }
+  return {nullptr, 0};
+}
+
+std::pair<const char*, uint64> ParseVarint64Fallback(const char* p, uint64 res) {
+  res >>= 1;
+  for (std::uint32_t i = 0; i < 4; i++) {
+    std::uint32_t tmp;
+    auto pnew = DecodeTwoBytes(p + 2 * i, &tmp);
+    res += (static_cast<std::uint64_t>(tmp) - 2) << (14 * (i + 1) - 1);
+    if (PROTOBUF_PREDICT_TRUE(std::int16_t(tmp) >= 0)) {
+      return {pnew, res};
+    }
+  }
+  return {nullptr, res};
+}
+
+std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 first) {
+  uint32 tmp;
+  auto res = VarintParse<4>(p + 1, &tmp);
+  if (tmp >= (1 << 24) - ParseContext::kSlopBytes) return {nullptr, 0};
+  return {res, (tmp << 7) + first - 0x80};
+}
+
+const char* StringParser(const char* begin, const char* end, void* object,
+                         ParseContext*) {
+  auto str = static_cast<string*>(object);
+  str->append(begin, end - begin);
+  return end;
+}
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(const char* 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);
+    return false;
+  }
+  return true;
+}
+
+const char* InlineGreedyStringParserUTF8(string* s, const char* ptr,
+                                         ParseContext* ctx,
+                                         const char* field_name) {
+  auto p = InlineGreedyStringParser(s, ptr, ctx);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*s, field_name));
+  return p;
+}
+
+const char* InlineGreedyStringParserUTF8Verify(string* s, const char* ptr,
+                                               ParseContext* ctx,
+                                               const char* field_name) {
+  auto p = InlineGreedyStringParser(s, ptr, ctx);
+#ifndef NDEBUG
+  VerifyUTF8(*s, field_name);
+#endif  // !NDEBUG
+  return p;
+}
+
+
+template <typename T, bool sign>
+const char* VarintParser(void* object, const char* ptr, ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  if (old < 0) return nullptr;
+  auto repeated_field = static_cast<RepeatedField<T>*>(object);
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
+    uint64 varint;
+    ptr = ParseVarint64(ptr, &varint);
+    if (!ptr) return nullptr;
+    T val;
+    if (sign) {
+      if (sizeof(T) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    repeated_field->Add(val);
+  }
+  ctx->PopLimit(old);
+  return ptr;
+}
+
+template <typename T>
+const char* FixedParser(void* object, const char* ptr, ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(old >= 0);
+  auto repeated_field = static_cast<RepeatedField<T>*>(object);
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
+    int num = (ctx->ConsecutiveBytes(ptr) + sizeof(T) - 1) / sizeof(T);
+
+    const int old_entries = repeated_field->size();
+    repeated_field->Reserve(old_entries + num);
+    std::memcpy(repeated_field->AddNAlreadyReserved(num), ptr, num * sizeof(T));
+    ptr = ptr + num * sizeof(T);
+  }
+  ctx->PopLimit(old);
+  return ptr;
+}
+
+const char* PackedInt32Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int32, false>(object, ptr, ctx);
+}
+const char* PackedUInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint32, false>(object, ptr, ctx);
+}
+const char* PackedInt64Parser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return VarintParser<int64, false>(object, ptr, ctx);
+}
+const char* PackedUInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<uint64, false>(object, ptr, ctx);
+}
+const char* PackedSInt32Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int32, true>(object, ptr, ctx);
+}
+const char* PackedSInt64Parser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return VarintParser<int64, true>(object, ptr, ctx);
+}
+
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<int, false>(object, ptr, ctx);
+}
+
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
+                             bool (*is_valid)(int), string* unknown,
+                             int field_num) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(old >= 0);
+  auto repeated_field = static_cast<RepeatedField<int>*>(object);
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
+    uint64 varint;
+    ptr = ParseVarint64(ptr, &varint);
+    if (!ptr) return nullptr;
+    int val = varint;
+    if (is_valid(val)) {
+      repeated_field->Add(val);
+    } else {
+      WriteVarint(field_num, val, unknown);
+    }
+  }
+  ctx->PopLimit(old);
+  return ptr;
+}
+
+const char* PackedEnumParserArg(void* object, const char* ptr,
+                                ParseContext* ctx,
+                                bool (*is_valid)(const void*, int),
+                                const void* data, string* unknown,
+                                int field_num) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(old >= 0);
+  auto repeated_field = static_cast<RepeatedField<int>*>(object);
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
+    uint64 varint;
+    ptr = ParseVarint64(ptr, &varint);
+    if (!ptr) return nullptr;
+    int val = varint;
+    if (is_valid(data, val)) {
+      repeated_field->Add(val);
+    } else {
+      WriteVarint(field_num, val, unknown);
+    }
+  }
+  ctx->PopLimit(old);
+  return ptr;
+}
+
+const char* PackedBoolParser(void* object, const char* ptr, ParseContext* ctx) {
+  return VarintParser<bool, false>(object, ptr, ctx);
+}
+
+const char* PackedFixed32Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint32>(object, ptr, ctx);
+}
+const char* PackedSFixed32Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int32>(object, ptr, ctx);
+}
+const char* PackedFixed64Parser(void* object, const char* ptr,
+                                ParseContext* ctx) {
+  return FixedParser<uint64>(object, ptr, ctx);
+}
+const char* PackedSFixed64Parser(void* object, const char* ptr,
+                                 ParseContext* ctx) {
+  return FixedParser<int64>(object, ptr, ctx);
+}
+const char* PackedFloatParser(void* object, const char* ptr,
+                              ParseContext* ctx) {
+  return FixedParser<float>(object, ptr, ctx);
+}
+const char* PackedDoubleParser(void* object, const char* ptr,
+                               ParseContext* ctx) {
+  return FixedParser<double>(object, ptr, ctx);
+}
+
 class UnknownFieldLiteParserHelper {
  public:
   explicit UnknownFieldLiteParserHelper(string* unknown) : unknown_(unknown) {}
@@ -470,20 +525,21 @@
     std::memcpy(buffer, &value, 8);
     unknown_->append(buffer, 8);
   }
-  ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
-    if (unknown_ == nullptr) return {NullParser, nullptr};
+  const char* ParseLengthDelimited(uint32 num, const char* ptr,
+                                   ParseContext* ctx) {
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_ == nullptr) return ctx->Skip(ptr, size);
     WriteVarint(num * 8 + 2, unknown_);
     WriteVarint(size, unknown_);
-    return {StringParser, unknown_};
+    return ctx->AppendString(ptr, size, unknown_);
   }
-  ParseClosure StartGroup(uint32 num) {
-    if (unknown_ == nullptr) return {UnknownGroupLiteParse, nullptr};
-    WriteVarint(num * 8 + 3, unknown_);
-    return {UnknownGroupLiteParse, unknown_};
-  }
-  void EndGroup(uint32 num) {
-    if (unknown_ == nullptr) return;
-    WriteVarint(num * 8 + 4, unknown_);
+  const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
+    if (unknown_) WriteVarint(num * 8 + 3, unknown_);
+    ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    if (unknown_) WriteVarint(num * 8 + 4, unknown_);
+    return ptr;
   }
   void AddFixed32(uint32 num, uint32 value) {
     if (unknown_ == nullptr) return;
@@ -493,39 +549,24 @@
     unknown_->append(buffer, 4);
   }
 
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
  private:
   string* unknown_;
 };
 
-const char* UnknownGroupLiteParse(const char* begin, const char* end,
-                                  void* object, ParseContext* ctx) {
-  UnknownFieldLiteParserHelper field_parser(static_cast<string*>(object));
-  return WireFormatParser({UnknownGroupLiteParse, object}, field_parser, begin,
-                          end, ctx);
-}
-
-std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
-                                               const char* begin,
-                                               const char* end, string* unknown,
-                                               ParseContext* ctx) {
+const char* UnknownGroupLiteParse(string* unknown, const char* ptr,
+                                  ParseContext* ctx) {
   UnknownFieldLiteParserHelper field_parser(unknown);
-  return FieldParser(tag, parent, field_parser, begin, end, ctx);
+  return WireFormatParser(field_parser, ptr, ctx);
 }
 
-const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
-                               internal::ParseContext* ctx) {
-  ctx->extra_parse_data().payload.append(begin, end - begin);
-  if (ctx->AtLimit()) {
-    // Move payload out of extra_parse_data. Parsing maps could trigger
-    // payload on recursive maps.
-    string to_parse = std::move(ctx->extra_parse_data().payload);
-    StringPiece chunk = to_parse;
-    if (!ctx->extra_parse_data().parse_map(chunk.begin(), chunk.end(), object,
-                                           ctx)) {
-      return nullptr;
-    }
-  }
-  return end;
+const char* UnknownFieldParse(uint32 tag, string* unknown, const char* ptr,
+                              ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return FieldParser(tag, field_parser, ptr, ctx);
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index 43e4144..f8122db 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -34,13 +34,18 @@
 #include <cstring>
 #include <string>
 
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/implicit_weak_message.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>
 
 #include <google/protobuf/port_def.inc>
 
+
 namespace google {
 namespace protobuf {
 
@@ -52,24 +57,15 @@
 
 // Template code below needs to know about the existence of these functions.
 PROTOBUF_EXPORT void WriteVarint(uint32 num, uint64 val, std::string* s);
-PROTOBUF_EXPORT
-void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s);
+PROTOBUF_EXPORT void WriteLengthDelimited(uint32 num, StringPiece val,
+                                          std::string* s);
 // Inline because it is just forwarding to s->WriteVarint
 inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* s);
 inline void WriteLengthDelimited(uint32 num, StringPiece val,
                                  UnknownFieldSet* s);
 
 
-// ParseContext contains state that needs to be preserved across buffer seams.
-
-class ParseContext;
-
-// The parser works by composing elementary parse functions, that are generated
-// by the compiler, together to perform the full parse. To accomplish this the
-// functionality of the elementary parse function is slightly increased which
-// allows it to become composable.
-
-// The basic abstraction ParseContext is designed for is a slight modification
+// The basic abstraction the parser is designed for is a slight modification
 // of the ZeroCopyInputStream (ZCIS) abstraction. A ZCIS presents a serialized
 // stream as a series of buffers that concatenate to the full stream.
 // Pictorially a ZCIS presents a stream in chunks like so
@@ -79,11 +75,11 @@
 //                                          chunk 3 [--------------]
 //
 // Where the '-' represent the bytes which are vertically lined up with the
-// bytes of the stream.
-// ParseContext requires its input to be presented similarily with the extra
-// property that the last kSlopBytes of a chunk overlaps with the first
-// kSlopBytes of the next chunk, or if there is no next chunk at least its still
-// valid to read those bytes. Again, pictorially, we now have
+// bytes of the stream. The proto parser requires its input to be presented
+// similarily with the extra
+// property that each chunk has kSlopBytes past its end that overlaps with the
+// first kSlopBytes of the next chunk, or if there is no next chunk at least its
+// still valid to read those bytes. Again, pictorially, we now have
 //
 // [---------------------------------------------------------------]
 // [-------------------....] chunk 1
@@ -99,523 +95,473 @@
 //
 // The reason for this, admittedly, unconventional invariant is to ruthlessly
 // optimize the protobuf parser. Having an overlap helps in two important ways.
-// Firstly it alleviates having to performing bounds checks, if a piece of code
-// will never read more than kSlopBytes. Secondly, and more importantly, the
-// protobuf wireformat is such that there is always a fresh start of a tag
-// within kSlopBytes. This allows the parser to exit parsing a chunk leaving
-// the parse on a position inside the overlap where a fresh tag starts.
+// Firstly it alleviates having to performing bounds checks if a piece of code
+// is guaranteed to not read more than kSlopBytes. Secondly, and more
+// importantly, the protobuf wireformat is such that reading a key/value pair is
+// always less than 16 bytes. This removes the need to change to next buffer in
+// the middle of reading primitive values. Hence there is no need to store and
+// load the current position.
 
-// The elementary parse function has the following signature
-
-typedef const char* (*ParseFunc)(const char* ptr, const char* end, void* object,
-                                 ParseContext* ctx);
-
-// which parses the serialized data stored in the range [ptr, end) into object.
-// A parse function together with its object forms a callable closure.
-struct ParseClosure {
-  ParseFunc func;
-  void* object;
-
-  // Pre-conditions
-  //   ptr < end is a non-empty range where ptr points to the start of a tag
-  //     and it's okay to read the bytes in [end, end + kSlopBytes).
-  //     Which will contain the bytes of the next chunk if the stream continues,
-  //     or undefined in which case the parse will be guaranteed to fail.
-  //
-  // Post-conditions
-  //   Parsed all tag/value pairs starting before end or if a group end
-  //   tag is encountered returns the pointer to that tag.
-  //   If a group end is encountered it verifies it matches the one that was
-  //   pushed and the stack is popped.
-  //   Otherwise it will parses the entire range pushing if end is inside one
-  //   of the children those are pushed on the stack.
-  //
-  //   If an element is popped from the stack it ended on the correct end group
-  //   returns pointer after end-group tag (posibly in overlap, but the start
-  //   of end-group tag will be before end).
-  //   If the stack is the same or deeper, returns pointer in overlap region
-  //   (end <= retval < end + kSlopBytes).
-  //   All tag/value pairs between in [begin, retval) are parsed and retval
-  //   points to start of a tag.
-  PROTOBUF_ALWAYS_INLINE  // Don't pay for extra stack frame in debug mode
-      const char*
-      operator()(const char* ptr, const char* end, ParseContext* ctx) {
-    GOOGLE_DCHECK(ptr < end);
-    return func(ptr, end, object, ctx);
-  }
-};
-
-// To fully parse a stream, a driver loop repeatedly calls the parse function
-// at the top of the stack, popping and resume parsing the parent message
-// according to the recursive structure of the wireformat. This loop will also
-// need to provide new buffer chunks and align the ptr correctly over the seams.
-// The point of this framework is that chunk refresh logic is located in the
-// outer loop, while the inner loop is almost free of it. The two code paths in
-// the parse code dealing with seams are located in fallback paths whose checks
-// are folded with input limit checks that are necessary anyway. In other words,
-// all the parser code that deals with seams is located in what would otherwise
-// be error paths of a parser that wouldn't need to deal with seams.
-
-class PROTOBUF_EXPORT ParseContext {
+class PROTOBUF_EXPORT EpsCopyInputStream {
  public:
-  enum {
-    // Tag is atmost 5 bytes, varint is atmost 10 resulting in 15 bytes. We
-    // choose
-    // 16 bytes for the obvious reason of alignment.
-    kSlopBytes = 16,
-    // Inlined stack size
-    kInlinedDepth = 15,
-  };
+  enum { kSlopBytes = 16 };
 
-  // Arghh!!! here be tech-debt dragons
-  struct ExtraParseData {
-    const DescriptorPool* pool = nullptr;
-    MessageFactory* factory = nullptr;
+  explicit EpsCopyInputStream(bool enable_aliasing)
+      : aliasing_(enable_aliasing ? kOnPatch : kNoAliasing) {}
 
-    // payload is used for MessageSetItem and maps
-    std::string payload;
-    bool (*parse_map)(const char* begin, const char* end, void* map_field,
-                      ParseContext* ctx);
-
-    void SetEnumValidator(bool (*validator)(int), void* unknown,
-                          int field_num) {
-      enum_validator = validator;
-      unknown_fields = unknown;
-      field_number = field_num;
-    }
-    void SetEnumValidatorArg(bool (*validator)(const void*, int),
-                             const void* arg, void* unknown, int field_num) {
-      arg_enum_validator = {validator, arg};
-      unknown_fields = unknown;
-      field_number = field_num;
-    }
-    template <typename Unknown>
-    bool ValidateEnum(int val) const {
-      if (enum_validator(val)) return true;
-      WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
-      return false;
-    }
-    template <typename Unknown>
-    bool ValidateEnumArg(int val) const {
-      if (arg_enum_validator(val)) return true;
-      WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
-      return false;
-    }
-
-    void SetFieldName(const void* name) {
-      unknown_fields = const_cast<void*>(name);
-    }
-    const char* FieldName() const {
-      return static_cast<const char*>(unknown_fields);
-    }
-
-    union {
-      bool (*enum_validator)(int);
-      struct {
-        bool operator()(int val) const { return validator(arg, val); }
-        bool (*validator)(const void*, int);
-        const void* arg;
-      } arg_enum_validator;
-    };
-    void* unknown_fields;
-    int field_number;
-    // 0 means no aliasing. If not zero aliasing is the delta between the
-    // ptr and the buffer that needs to be aliased. If the value is
-    // kNoDelta (1) this means delta is actually 0 (we're working directly in
-    // the buffer).
-    enum { kNoDelta = 1 };
-    std::uintptr_t aliasing = 0;
-  };
-
-  ExtraParseData& extra_parse_data() { return extra_parse_data_; }
-  const ExtraParseData& extra_parse_data() const { return extra_parse_data_; }
-
-  // Helpers to detect if a parse of length delimited field is completed.
-  bool AtLimit() const { return limit_ == 0; }
-  int32 CurrentLimit() const { return limit_; }
-
-  // Initializes ParseContext with a specific recursion limit (rec_limit)
-  explicit ParseContext(int rec_limit)
-      : depth_(rec_limit),
-        start_depth_(rec_limit),
-        stack_(inline_stack_ + kInlinedDepth - rec_limit),
-        inlined_depth_(std::max(0, rec_limit - kInlinedDepth)) {}
-
-  ~ParseContext() {
-    if (inlined_depth_ == -1) delete[] stack_;
-  }
-
-  void StartParse(ParseClosure parser) { parser_ = parser; }
-
-  // Parses a chunk of memory given the current state of parse context (ie.
-  // the active parser and stack) and overrun.
-  // Pre-condition:
-  //   chunk_ is not empty.
-  //   limit_ > 0 (limit from begin) or -1 (no limit)
-  // Post-condition:
-  //   returns true on success with overrun_ptr adjusted to the new value, or
-  //   false is the parse is finished. False means either a parse failure or
-  //   or because the top-level was terminated on a 0 or end-group tag in which
-  //   case overrun points to the position after the ending tag. You can call
-  //   EndedOnTag() to find if the parse failed due to an error or ended on
-  //   terminating tag.
-  bool ParseRange(StringPiece chunk, int* overrun_ptr) {
-    GOOGLE_DCHECK(!chunk.empty());
-    int& overrun = *overrun_ptr;
-    GOOGLE_DCHECK(overrun >= 0);
-    if (overrun >= static_cast<int>(chunk.size())) {
-      // This case can easily happen in patch buffers and we like to inline
-      // this case.
-      overrun -= chunk.size();
-      return true;
-    }
-    auto res = ParseRangeWithLimit(chunk.begin() + overrun, chunk.end());
-    overrun = res.second;
-    return res.first;
-  }
-
-  bool ValidEnd(int overrun) { return depth_ == start_depth_ && overrun == 0; }
-  bool EndedOnTag() const { return last_tag_minus_1_ != 0; }
-  uint32 LastTag() const { return last_tag_minus_1_ + 1; }
-
-  // Generically verifies for the slop region [begin, begin + kSlopBytes) if
-  // the parse will be terminated by 0 or end-group tag. If true than you can
-  // safely parse the slop region without having to load more data.
-  bool ParseEndsInSlopRegion(const char* begin, int overrun) const;
-
-  // Should only be called by Parse code.
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Fast path helpers. These helpers maintain the state in parse context
-  // through recursive calls. The whole design is to make this as minimal as
-  // possible. Only recursion depth and limit are maintained at every recursion.
-  //////////////////////////////////////////////////////////////////////////////
-
-  bool ParseExactRange(ParseClosure parser, const char* begin,
-                       const char* end) {
-    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
-    auto old_limit = limit_;
-    limit_ = 0;
-    auto ptr = begin;
-    if (ptr < end) ptr = parser(ptr, end, this);
-    if (ptr != end || EndedOnTag()) return false;
-    limit_ = old_limit;
-    ++depth_;
-    return true;
-  }
-
-  // Returns a pair of the pointer the parse is left and a boolean indicating
-  // if the group is still continuing.
-  std::pair<const char*, bool> ParseGroup(uint32 tag, ParseClosure parser,
-                                          const char* begin, const char* end,
-                                          int* depth) {
-    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return {};
-    *depth = depth_;
-    auto ptr = begin;
-    if (ptr < end) ptr = parser(ptr, end, this);
-    if (ptr == nullptr) return {};
-    if (!EndedOnTag()) {
-      // The group hasn't been terminated by an end-group and thus continues,
-      // hence it must have ended because it crossed "end".
-      GOOGLE_DCHECK(ptr >= end);
-      return {ptr, true};
-    }
-    // Verify that the terminating tag matches the start group tag. As an extra
-    // subtlety it could have been terminated by an end-group tag but in a
-    // length delimited sub field of the group. So we must also check that depth
-    // matches, if it doesn't match it means a length delimited subfield got
-    // terminated by an end group which is an error.
-    if (tag != last_tag_minus_1_ || *depth != depth_) return {};
-    last_tag_minus_1_ = 0;  // It must always be cleared.
-    ++depth_;
-    return {ptr, false};
-  }
-
-  void EndGroup(uint32 tag) {
-    GOOGLE_DCHECK(tag == 0 || (tag & 7) == 4);
-    // Because of the above assert last_tag_minus_1 is never set to 0, and the
-    // caller can verify the child parser was terminated, by comparing to 0.
-    last_tag_minus_1_ = tag - 1;
-  }
-
-  //////////////////////////////////////////////////////////////////////////////
-  // Slow path helper functions when a child crosses the "end" of range.
-  // This is either an error (if limit_ = 0) OR we need to store state.
-  // These functions manage the task of updating the state correctly.
-  //////////////////////////////////////////////////////////////////////////////
-
-  // Helper function called by generated code in case of a length delimited
-  // field that is going to cross the boundary.
-  const char* StoreAndTailCall(const char* ptr, const char* end,
-                               ParseClosure current_parser,
-                               ParseClosure child_parser, int32 size) {
-    // At this point ptr could be past end. Hence a malicious size could
-    // overflow.
-    int64 safe_new_limit = size - static_cast<int64>(end - ptr);
-    if (safe_new_limit > INT_MAX) return nullptr;
-    GOOGLE_DCHECK(safe_new_limit > 0);  // only call this if it's crossing end
-    int32 new_limit = static_cast<int32>(safe_new_limit);
-    int32 delta;
-    if (limit_ != -1) {
-      if (PROTOBUF_PREDICT_FALSE(new_limit > limit_)) return nullptr;
-      delta = limit_ - new_limit;
+  void BackUp(const char* ptr) {
+    GOOGLE_DCHECK(ptr <= buffer_end_ + kSlopBytes);
+    int count;
+    if (next_chunk_ == buffer_) {
+      count = buffer_end_ + kSlopBytes - ptr;
     } else {
-      delta = -1;  // special value
+      count = size_ + (buffer_end_ - ptr);
     }
-    limit_ = new_limit;
-    // Save the current closure on the stack.
-    if (!Push(current_parser, delta)) return nullptr;
-    // Ensure the active state is set correctly.
-    parser_ = child_parser;
-    return ptr < end ? child_parser(ptr, end, this) : ptr;
+    if (count > 0) zcis_->BackUp(count);
   }
 
-  // Helper function for a child group that has crossed the boundary.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif  // defined(__GNUC__) && !defined(__clang__)
-  bool StoreGroup(ParseClosure current_parser, ParseClosure child_parser,
-                  int depth, uint32 tag) {
-    // The group must still read an end-group tag, so it can't be at a limit.
-    // By having this check we ensure that when limit_ = 0 we can't end in some
-    // deeper recursion. Hence ParseExactRange does not need to check for
-    // matching depth.
-    if (limit_ == 0) return false;
-    if (depth == depth_) {
-      // This child group is the active parser. The fast path code assumes
-      // everything will be parsed within a chunk and doesn't modify
-      // parse context in this case. We need to make the child parser active.
-      parser_ = child_parser;
-    }
-    if (PROTOBUF_PREDICT_FALSE(depth < inlined_depth_)) SwitchStack();
-    stack_[depth] = {current_parser, static_cast<int32>(~(tag >> 3))};
-    return true;
+  // If return value is negative it's an error
+  PROTOBUF_MUST_USE_RESULT int PushLimit(const char* ptr, int limit) {
+    GOOGLE_DCHECK(limit >= 0);
+    limit += ptr - buffer_end_;
+    if (limit < 0) limit_end_ = buffer_end_ + limit;
+    auto old_limit = limit_;
+    limit_ = limit;
+    return old_limit - limit;
   }
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif  // defined(__GNUC__) && !defined(__clang__)
+
+  void PopLimit(int delta) {
+    // Ensure not to forget to check PushLimit return value
+    GOOGLE_DCHECK(delta >= 0);
+    // In a correct parse this addition can never overflow because all Pop's
+    // are paired with a Push. However on an incorrect parse this might not
+    // be the case. We use unsigned to prevent UB.
+    limit_ =
+        static_cast<unsigned int>(limit_) + static_cast<unsigned int>(delta);
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+  }
+
+  PROTOBUF_MUST_USE_RESULT const char* Skip(const char* ptr, int size) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      return ptr + size;
+    }
+    return SkipFallback(ptr, size);
+  }
+  PROTOBUF_MUST_USE_RESULT const char* ReadString(const char* ptr, int size,
+                                                  std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->assign(ptr, size);
+      return ptr + size;
+    }
+    return ReadStringFallback(ptr, size, s);
+  }
+  PROTOBUF_MUST_USE_RESULT const char* AppendString(const char* ptr, int size,
+                                                    std::string* s) {
+    if (size <= buffer_end_ + kSlopBytes - ptr) {
+      s->append(ptr, size);
+      return ptr + size;
+    }
+    return AppendStringFallback(ptr, size, s);
+  }
+
+  template <typename Tag, typename T>
+  PROTOBUF_MUST_USE_RESULT const char* ReadRepeatedFixed(const char* ptr,
+                                                         Tag expected_tag,
+                                                         RepeatedField<T>* out);
+
+  template <typename T>
+  PROTOBUF_MUST_USE_RESULT const char* ReadPackedFixed(const char* ptr,
+                                                       int size,
+                                                       RepeatedField<T>* out);
+  template <typename T, typename Add>
+  PROTOBUF_MUST_USE_RESULT const char* ReadPackedVarint(const char* ptr,
+                                                        Add add);
+
+  int ConsecutiveBytes(const char* ptr) const { return limit_end_ - ptr; }
+  int BytesUntilLimit(const char* ptr) const {
+    return buffer_end_ - ptr + limit_;
+  }
+  bool AtLimit(const char* ptr) const {
+    return (ptr - buffer_end_ == limit_) ||
+           (next_chunk_ == nullptr && limit_ > 0 && ptr == buffer_end_);
+  }
+
+ protected:
+  // Returns true is limit (either an explicit limit or end of stream) is
+  // reached. It aligns *ptr across buffer seams.
+  // If limit is exceeded it returns true and ptr is set to null.
+  bool DoneWithCheck(const char** ptr, int d) {
+    GOOGLE_DCHECK(*ptr);
+    if (PROTOBUF_PREDICT_TRUE(*ptr < limit_end_)) return false;
+    // No need to fetch buffer if we ended on a limit in the slop region
+    if ((*ptr - buffer_end_) == limit_) return true;
+    auto res = DoneFallback(*ptr, d);
+    *ptr = res.first;
+    return res.second;
+  }
+
+  const char* InitFrom(StringPiece flat) {
+    if (flat.size() > kSlopBytes) {
+      limit_ = kSlopBytes;
+      limit_end_ = buffer_end_ = flat.end() - kSlopBytes;
+      if (aliasing_ == kOnPatch) aliasing_ = kNoDelta;
+      return flat.begin();
+    } else {
+      std::memcpy(buffer_, flat.begin(), flat.size());
+      limit_ = 0;
+      limit_end_ = buffer_end_ = buffer_ + flat.size();
+      next_chunk_ = nullptr;
+      if (aliasing_ == kOnPatch) {
+        aliasing_ = reinterpret_cast<std::uintptr_t>(flat.data()) -
+                    reinterpret_cast<std::uintptr_t>(buffer_);
+      }
+      return buffer_;
+    }
+  }
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis);
+
+  const char* InitFrom(io::ZeroCopyInputStream* zcis, int limit) {
+    auto res = InitFrom(zcis);
+    limit_ = limit - (buffer_end_ - res);
+    limit_end_ = buffer_end_ + (std::min)(0, limit_);
+    return res;
+  }
 
  private:
-  // This the "active" or current parser.
-  ParseClosure parser_;
+  const char* limit_end_ =
+      buffer_ + kSlopBytes;  // buffer_end_ + min(limit_, 0)
+  const char* buffer_end_ = buffer_ + kSlopBytes;
+  const char* next_chunk_ = buffer_;
+  int size_;
+  int limit_ = INT_MAX;  // relative to buffer_end_;
+  io::ZeroCopyInputStream* zcis_ = nullptr;
+  char buffer_[2 * kSlopBytes] = {};
+  enum { kNoAliasing = 0, kOnPatch = 1, kNoDelta = 2 };
+  std::uintptr_t aliasing_ = kNoAliasing;
+
+  std::pair<const char*, bool> DoneFallback(const char* ptr, int d);
+  const char* Next(int overrun, int d);
+  const char* SkipFallback(const char* ptr, int size);
+  const char* AppendStringFallback(const char* ptr, int size, std::string* str);
+  const char* ReadStringFallback(const char* ptr, int size, std::string* str);
+
+  template <typename A>
+  const char* AppendSize(const char* ptr, int size, const A& append) {
+    int chunk_size = buffer_end_ + kSlopBytes - ptr;
+    if (size > buffer_end_ - ptr + limit_) return nullptr;
+    do {
+      GOOGLE_DCHECK(size > chunk_size);
+      append(ptr, chunk_size);
+      ptr += chunk_size;
+      size -= chunk_size;
+      auto res = DoneFallback(ptr, -1);
+      if (res.second) {
+        return nullptr;  // If done we passed the limit
+      }
+      ptr = res.first;
+      chunk_size = buffer_end_ + kSlopBytes - ptr;
+    } while (size > chunk_size);
+    append(ptr, size);
+    return ptr + size;
+  }
+
+  template <typename A>
+  const char* AppendUntilEnd(const char* ptr, const A& append) {
+    while (!DoneWithCheck(&ptr, -1)) {
+      append(ptr, limit_end_ - ptr);
+      ptr = limit_end_;
+    }
+    return ptr;
+  }
+
+  PROTOBUF_MUST_USE_RESULT const char* AppendString(const char* ptr,
+                                                    std::string* str) {
+    return AppendUntilEnd(ptr,
+                          [str](const char* p, int s) { str->append(p, s); });
+  }
+  friend class ImplicitWeakMessage;
+};
+
+// 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
+// matching start/end group tags.
+class PROTOBUF_EXPORT ParseContext
+    : public EpsCopyInputStream {
+ public:
+  struct Data {
+    const DescriptorPool* pool = nullptr;
+    MessageFactory* factory = nullptr;
+  };
+
+  template <typename... T>
+  ParseContext(int depth, bool aliasing, const char** start, T&&... args)
+      : EpsCopyInputStream(aliasing), depth_(depth) {
+    *start = InitFrom(std::forward<T>(args)...);
+  }
+
+  void TrackCorrectEnding() { group_depth_ = 0; }
+
+  bool Done(const char** ptr) { return DoneWithCheck(ptr, group_depth_); }
+  bool DoneNoSlopCheck(const char** ptr) { return DoneWithCheck(ptr, -1); }
+
+  int depth() const { return depth_; }
+  void SetLastTag(uint32 tag) { last_tag_minus_1_ = tag - 1; }
+  uint32 LastTagMinus1() const { return last_tag_minus_1_; }
+
+  bool AtLegitimateEnd(const char* ptr) const {
+    return ptr && AtLimit(ptr) && last_tag_minus_1_ == 0;
+  }
+
+  Data& data() { return data_; }
+  const Data& data() const { return data_; }
+
+  template <typename T>
+  PROTOBUF_MUST_USE_RESULT const char* ParseMessage(T* msg, const char* ptr);
+
+  template <typename T>
+  PROTOBUF_MUST_USE_RESULT const char* ParseGroup(T* msg, const char* ptr,
+                                                  uint32 tag) {
+    if (--depth_ < 0) return nullptr;
+    group_depth_++;
+    ptr = msg->_InternalParse(ptr, this);
+    group_depth_--;
+    depth_++;
+    if (last_tag_minus_1_ != tag) return nullptr;
+    last_tag_minus_1_ = 0;
+    return ptr;
+  }
+
+ private:
   // The context keeps an internal stack to keep track of the recursive
   // part of the parse state.
   // Current depth of the active parser, depth counts down.
   // This is used to limit recursion depth (to prevent overflow on malicious
   // data), but is also used to index in stack_ to store the current state.
   int depth_;
-  int32 limit_ = -1;
-
-  // A state is on the stack to save it, in order to continue parsing after
-  // child is done.
-  struct State {
-    ParseClosure parser;
-    // This element describes how to adjust the parse state after finishing
-    // the child. If the child was a length delimited field, delta describes
-    // the limit relative to the child's limit (hence >= 0).
-    // If child was a sub group limit contains ~field num (hence < 0) in order
-    // to verify the group ended on a correct end tag. No limit adjusting.
-    // Note above the sign of delta is meaningful
-    int32 delta_or_group_num;
-  };
-  int start_depth_;
-  // This is used to return the end group (or 0 tag) that terminated the parse.
-  // Actually it contains last_tag minus 1. Which is either the start group tag
-  // or -1. This member should always be zero and the caller should immediately
-  // check this member to verify what state the parser ended on and clear its
-  // value.
+  // Unfortunately necessary for the fringe case of ending on 0 or end-group tag
+  // in the last kSlopBytes of a ZeroCopyInputStream chunk.
+  int group_depth_ = INT_MIN;
   uint32 last_tag_minus_1_ = 0;
-
-  ExtraParseData extra_parse_data_;
-  State* stack_;
-  State inline_stack_[kInlinedDepth];
-  int inlined_depth_;
-
-  bool Push(ParseClosure parser, int32 delta) {
-    GOOGLE_DCHECK(delta >= -1);  // Make sure it's a valid len-delim
-    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
-    if (PROTOBUF_PREDICT_FALSE(depth_ < inlined_depth_)) SwitchStack();
-    stack_[depth_] = {parser, delta};
-    return true;
-  }
-
-  State Pop() { return stack_[depth_++]; }
-
-  void SwitchStack();
-
-  // Parses a chunk of memory given the current state of parse context (ie.
-  // the active parser and stack).
-  // Pre-condition:
-  //   begin < end (non-empty range)
-  //   limit_ > 0 (limit from begin) or -1 (no limit)
-  // Post-condition:
-  //   returns either (true, overrun) for a successful parse that can continue,
-  //   or (false, overrun) for a parse that can't continue. Either due to a
-  //   corrupt data (parse failure) or because the top-level was terminated on a
-  //   0 or end-group tag in which case overrun points to the position after the
-  //   end.
-  std::pair<bool, int> ParseRangeWithLimit(const char* begin, const char* end);
+  Data data_;
 };
 
-// This is wrapper to parse a sequence of buffers without the overlap property,
-// like the sequence given by ZeroCopyInputStream (ZCIS) or ByteSource. This is
-// done by copying data around the seams, hence the name EpsCopyParser.
-// Pictorially if ZCIS presents a stream in chunks like so
-// [---------------------------------------------------------------]
-// [---------------------] chunk 1
-//                      [----------------------------] chunk 2
-//                                          chunk 3 [--------------]
-// where '-' depicts bytes of the stream or chunks vertically alligned with the
-// corresponding bytes between stream and chunk.
-//
-// This class will present chunks to the ParseContext like this
-// [-----------------....] chunk 1
-//                  [----....] patch
-//                      [------------------------....] chunk 2
-//                                              [----....] patch
-//                                          chunk 3 [----------....]
-//                                                      patch [----****]
-// by using a fixed size buffer to patch over the seams. This requires
-// copying of an "epsilon" neighboorhood around the seams. In the picture above
-// dots mean bytes beyond the end of the new chunks. Each chunk is kSlopBytes
-// smalller as its original chunk (above depicted as 4 dots) and the number of
-// of chunks is doubled because each seam in the original stream introduces a
-// new patch.
-//
-// The algorithm is simple but not entirely trivial. Two complications arise
-// 1) The original chunk could be less than kSlopBytes. Hence we can't simply
-// chop the last kSlopBytes of a chunk.
-// 2) In some (infrequent) use cases, we don't necessarily parse unitl the end
-// of a stream, but instead the parse is terminated by 0 or end-group tag. If
-// this is allowed we must take care to leave the underlying stream at a
-// position precisely after the terminating tag. If this happens in the slop
-// region of a buffer we will already have loaded the next buffer. Not all
-// streams allow backing up to a previous buffer blocking us from leaving the
-// stream in the proper state. If terminating on 0 is allowed (in the old parser
-// this means a call to MergePartialFromCodedStream without a subsequent call to
-// ConsumedEntireMessage), this algorithm needs to ensure the parse won't end
-// in the slop region before moving the next buffer.
-//
-// The core idea of EpsCopyParser is to parse ranges except the last kSlopBytes
-// and store those in the patch buffer, until the next parse provides additional
-// data to fill the slop region. So parsing a range means first parsing the slop
-// bytes of the previous range using the new range to provide slop bytes for the
-// patch, followed by parsing the actual range except the last kSlopBytes and
-// store those. If no more data is available a call to Done finishes the parse
-// by parsing the remaining slopbytes.
-//
-// In order to deal with problem 1, we need to deal with the case that a new
-// chunk can be less or equal than kSlopBytes big. We can just copy the chunk
-// to the end and return (buffer, chunk->size). Pictorially
-// [--------] chunk 1
-//         [--] chunk 2
-//           [---] chunk 3
-// will become
-// [----....] chunk 1
-//     [--....] patch (not full range of the patch buffer, only two hyphens)
-//         [--] chunk 2 (too small so never parsed directly)
-//       [---....] patch (not full range of the buffer, only three hyphens)
-//           [---] chunk 3 (too small so never parsed directly)
-//          [----****] patch (full range, last bytes are garbage)
-// Because of this the source (the dots in above) can overlap with the
-// destination buffer and so we have to use memmove.
-//
-// To solve problem 2, we use a generic parser together with knowledge of the
-// nesting from the side stack to verify if the parse will be terminated in the
-// slop region. If it terminates inside the slop region, we just parse it as
-// well. See ParseEndsInSlopRegion in ParseContext for the implementation. This
-// is only done if ensure_non_negative_skip is true, if it's false Skip() could
-// return a negative number.
-template <bool ensure_non_negative_skip>
-class EpsCopyParser {
- public:
-  EpsCopyParser(ParseClosure parser, ParseContext* ctx) : ctx_(ctx) {
-    ctx_->StartParse(parser);
-  }
+template <typename T>
+T UnalignedLoad(const void* p) {
+  T res;
+  memcpy(&res, p, sizeof(T));
+  return res;
+}
 
-  // Parse the bytes as provided by the non-empty range.
-  // Returns true on a successful parse ready to accept more data, if there is
-  // no more data call Done() to finish the parse.
-  // Returns false if the parse is terminated. Termination is either due to a
-  // parse error or due to termination on an end-group or 0 tag. You can call
-  // EndedOnTag() on the underlying ParseContext to find out if the parse ended
-  // correctly on a terminating tag.
-  bool Parse(StringPiece range) {
-    GOOGLE_DCHECK(!range.empty());
-    auto size = range.size();
-    if (size > kSlopBytes) {
-      // The buffer is large enough to be able to parse the (size - kSlopBytes)
-      // prefix directly. However we still need to parse the data in buffer_,
-      // that holds the slop region of the previous buffer.
-      if (overrun_ == kSlopBytes) {
-        // We overrun the whole slop region of the previous buffer.
-        // Optimization, we can skip the patch buffer.
-        overrun_ = 0;
-      } else {
-        std::memcpy(buffer_ + kSlopBytes, range.begin(), kSlopBytes);
-        if (!ParseRange({buffer_, kSlopBytes}, 0)) return false;
-      }
-      range.remove_suffix(kSlopBytes);
-    } else {
-      std::memcpy(buffer_ + kSlopBytes, range.begin(), size);
-      range = {buffer_, size};
+// TODO(gerbens) Experiment with best implementation.
+// Clang unrolls loop and generating pretty good code on O2, gcc doesn't.
+// Unclear if we want 64 bit parse loop unrolled, inlined or opaque function
+// call. Hence experimentation is needed.
+// Important guarantee is that it doesn't read more than size bytes from p.
+template <int size, typename T>
+PROTOBUF_MUST_USE_RESULT const char* VarintParse(const char* p, T* out) {
+  T res = 1;
+  for (int i = 0; i < size; i++) {
+    T byte = static_cast<uint8>(p[i]);
+    res += (byte - 1) << (i * 7);
+    int j = i + 1;
+    if (PROTOBUF_PREDICT_TRUE(byte < 128)) {
+      *out = res;
+      return p + j;
     }
-    if (!ParseRange(range, size - kSlopBytes)) return false;
-    std::memmove(buffer_, range.end(), kSlopBytes);
-    if (ensure_non_negative_skip &&
-        ctx_->ParseEndsInSlopRegion(buffer_, overrun_)) {
-      // We care about leaving the stream at the right place and the stream will
-      // indeed terminate, so just parse it.
-      auto res = ParseRange({buffer_, kSlopBytes}, size);
-      GOOGLE_DCHECK(!res);
-      return false;
-    }
-    return true;
   }
+  *out = 0;
+  return nullptr;
+}
 
-  // Finish the parse by parsing the remaining data and verify success.
-  bool Done() {
-    return ParseRange({buffer_, kSlopBytes}, 0) && ctx_->ValidEnd(overrun_);
+// Decode 2 consecutive bytes of a varint. Two bytes must be available from
+// ptr. Returns ptr + 1 or ptr + 2 depending if the first byte had continuation
+// bit set. Stores The value of the varint shifted left by one.
+// If bit 15 of *res is set (equivalent to the continuation bits of both bytes
+// being set) the varint continues, otherwise the parse is done. On x86
+// movzx eax, word ptr [rdi]
+// movsx edx, al
+// and eax, edx
+// add eax, edx
+// adc rdi, 1
+inline const char* DecodeTwoBytes(const char* ptr, uint32* res) {
+  uint32_t y = UnalignedLoad<uint16>(ptr);
+  // Sign extend the low byte continuation bit
+  uint32_t x = static_cast<int8_t>(y);
+  y &= x;  // Mask out the high byte iff no continuation
+  // This add is an amazing operation, it cancels the low byte continuation bit
+  // from y transferring it to the carry. Simultaneously it also shifts the 7
+  // LSB left by one tightly against high byte varint bits. Hence y now
+  // contains the unpacked value shifted left by 1.
+  y += x;
+  *res = y;
+  // If the addition above carried the high byte was part of the varint. Alas
+  // in c we don't have access to the carry, but a good optimizer compiles this
+  // down to a "adc" instruction.
+  return ptr + (y < x ? 2 : 1);
+}
+
+inline uint32 ReadSmallVarint(const char** ptr) {
+  uint32 res;
+  *ptr = DecodeTwoBytes(*ptr, &res);
+  return res >> 1;
+}
+
+std::pair<const char*, uint32> Parse32Fallback(const char* p, uint32 res);
+
+inline const char* _Parse32(const char* p, uint32* out) {
+  return VarintParse<5>(p, out);
+}
+
+inline const char* ReadTagOne(const char* p, uint32* out) {
+  *out = static_cast<uint8>(*p);
+  return p + 1;
+}
+
+inline const char* ReadTagTwo(const char* p, uint32* out) {
+  uint32 res = static_cast<uint8>(p[0]);
+  if (res < 128) { *out = res; return p + 1; }
+  uint32 byte = static_cast<uint8>(p[1]);
+  res += (byte << 7) - 128;
+  *out = res;
+  return p + 2;
+}
+
+inline const char* FinishReadTagOne(const char* p, uint32* tag) {
+  if (*tag & 128) {
+    uint32 tmp;
+    p = VarintParse<4>(p, &tmp);
+    *tag += ((tmp - 1) << 7);
   }
+  return p;
+}
 
-  // If the parse was terminated by a end-group or 0 tag. Skip returns the
-  // offset where the parse left off relative to the start of the last range
-  // parsed.
-  // NOTE: This could be negative unless ensure_non_negative_skip is true.
-  int Skip() {
-    // The reason of ensure_non_negative_skip and ParseEndsInSlopRegion is that
-    // the following assert holds. Which implies the stream doesn't need to
-    // backup.
-    GOOGLE_DCHECK(!ensure_non_negative_skip || overrun_ >= 0);
-    return overrun_;
+inline const char* FinishReadTagTwo(const char* p, uint32* tag) {
+  if (*tag & (1 << 14)) {
+    uint32 tmp;
+    p = VarintParse<3>(p, &tmp);
+    *tag += ((tmp - 1) << 14);
   }
+  return p;
+}
 
- private:
-  constexpr static int kSlopBytes = ParseContext::kSlopBytes;
-  // overrun_ stores where in the slop region of the previous parse the parse
-  // was left off. This is used to start the parse of the next region at the
-  // correct point. Initially overrun_ should be set to kSlopBytes which means
-  // that the parse starts at precisely the beginning of new buffer provided.
-  int overrun_ = kSlopBytes;
-  // The first kSlopBytes of buffer_ contains the slop region of the previous
-  // parsed region.
-  char buffer_[2 * kSlopBytes] = {};
-  ParseContext* ctx_;
+// Used for tags, could read up to 5 bytes which must be available.
+// Caller must ensure its safe to call.
+inline const char* ReadTag(const char* p, uint32* out) {
+  return _Parse32(p, out);
+}
 
-  bool ParseRange(StringPiece range, int delta) {
-    auto res = ctx_->ParseRange(range, &overrun_);
-    if (!res) overrun_ += delta;
+std::pair<const char*, uint64> ParseVarint64Fallback(const char* p, uint64 res);
+
+// Used for reading varint wiretype values, could read up to 10 bytes.
+// Caller must ensure its safe to call.
+inline const char* ParseVarint64(const char* p, uint64* out) {
+  std::uint32_t tmp;
+  p = DecodeTwoBytes(p, &tmp);
+  if (PROTOBUF_PREDICT_TRUE(static_cast<int16>(tmp) >= 0)) {
+    *out = tmp >> 1;
+    return p;
+  }
+  auto x = ParseVarint64Fallback(p, tmp);
+  *out = x.second;
+  return x.first;
+}
+
+std::pair<const char*, int32> ReadSizeFallback(const char* p, uint32 first);
+// Used for tags, could read up to 5 bytes which must be available. Additionally
+// it makes sure the unsigned value fits a int32, otherwise returns nullptr.
+// Caller must ensure its safe to call.
+inline uint32 ReadSize(const char** pp) {
+  auto p = *pp;
+  uint32 res = static_cast<uint8>(p[0]);
+  if (res < 128) {
+    *pp = p + 1;
     return res;
   }
-};
+  auto x = ReadSizeFallback(p, res);
+  *pp = x.first;
+  return x.second;
+}
+
+// Some convenience functions to simplify the generated parse loop code.
+// Returning the value and updating the buffer pointer allows for nicer
+// function composition. We rely on the compiler to inline this.
+// Also in debug compiles having local scoped variables tend to generated
+// stack frames that scale as O(num fields).
+inline uint64 ReadVarint(const char** p) {
+  uint64 tmp;
+  *p = ParseVarint64(*p, &tmp);
+  return tmp;
+}
+
+inline int64 ReadVarintZigZag64(const char** p) {
+  uint64 tmp;
+  *p = ParseVarint64(*p, &tmp);
+  return WireFormatLite::ZigZagDecode64(tmp);
+}
+
+inline int32 ReadVarintZigZag32(const char** p) {
+  uint64 tmp;
+  *p = ParseVarint64(*p, &tmp);
+  return WireFormatLite::ZigZagDecode32(tmp);
+}
+
+template <typename T>
+PROTOBUF_MUST_USE_RESULT const char* ParseContext::ParseMessage(
+    T* msg, const char* ptr) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  auto old = PushLimit(ptr, size);
+  if (--depth_ < 0 || old < 0) return nullptr;
+  ptr = msg->_InternalParse(ptr, this);
+  depth_++;
+  PopLimit(old);
+  if (last_tag_minus_1_ != 0) return nullptr;
+  return ptr;
+}
+
+template <typename T, typename Add>
+PROTOBUF_MUST_USE_RESULT const char* EpsCopyInputStream::ReadPackedVarint(
+    const char* ptr, Add add) {
+  int size = ReadSize(&ptr);
+  if (ptr == nullptr) return nullptr;
+  auto old = PushLimit(ptr, size);
+  if (old < 0) return nullptr;
+  while (!DoneWithCheck(&ptr, -1)) {
+    uint64 varint;
+    ptr = ParseVarint64(ptr, &varint);
+    if (!ptr) return nullptr;
+    add(varint);
+  }
+  PopLimit(old);
+  return ptr;
+}
+
+// Helper for verification of utf8
+PROTOBUF_EXPORT
+bool VerifyUTF8(StringPiece s, const char* field_name);
+
+// All the string parsers with or without UTF checking and for all CTypes.
+inline PROTOBUF_MUST_USE_RESULT const char* InlineGreedyStringParser(
+    std::string* s, const char* ptr, ParseContext* ctx) {
+  int size = ReadSize(&ptr);
+  if (!ptr) return nullptr;
+  return ctx->ReadString(ptr, size, s);
+}
+
+PROTOBUF_MUST_USE_RESULT const char* InlineGreedyStringParserUTF8(
+    std::string* s, const char* ptr, ParseContext* ctx, const char* field_name);
+PROTOBUF_MUST_USE_RESULT const char* InlineGreedyStringParserUTF8Verify(
+    std::string* s, const char* ptr, ParseContext* ctx, const char* field_name);
+
 
 // Add any of the following lines to debug which parse function is failing.
 
 #define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
   if (!(predicate)) {                                  \
-    /*  raise(SIGINT); */                              \
-    /*  GOOGLE_LOG(ERROR) << "Parse failure"; */              \
+    /*  ::raise(SIGINT);  */                           \
+    /*  GOOGLE_LOG(ERROR) << "Parse failure";  */             \
     return ret;                                        \
   }
 
@@ -623,231 +569,119 @@
     GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
 
 template <typename T>
-std::pair<const char*, bool> FieldParser(uint64 tag, ParseClosure parent,
-                                         T field_parser, const char* begin,
-                                         const char* end, ParseContext* ctx) {
-  auto ptr = begin;
+PROTOBUF_MUST_USE_RESULT const char* FieldParser(uint64 tag, T& field_parser,
+                                                 const char* ptr,
+                                                 ParseContext* ctx) {
   uint32 number = tag >> 3;
-  if (PROTOBUF_PREDICT_FALSE(number == 0)) {
-    GOOGLE_PROTOBUF_ASSERT_RETURN(tag == 0, {});
-    // Special case scenario of 0 termination.
-    ctx->EndGroup(tag);
-    return {ptr, true};
-  }
+  GOOGLE_PROTOBUF_PARSER_ASSERT(number != 0);
   using WireType = internal::WireFormatLite::WireType;
   switch (tag & 7) {
     case WireType::WIRETYPE_VARINT: {
       uint64 value;
-      ptr = io::Parse64(ptr, &value);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+      ptr = ParseVarint64(ptr, &value);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       field_parser.AddVarint(number, value);
       break;
     }
     case WireType::WIRETYPE_FIXED64: {
-      uint64 value = io::UnalignedLoad<uint64>(ptr);
+      uint64 value = UnalignedLoad<uint64>(ptr);
       ptr += 8;
       field_parser.AddFixed64(number, value);
       break;
     }
     case WireType::WIRETYPE_LENGTH_DELIMITED: {
-      int32 size;
-      ptr = io::ReadSize(ptr, &size);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
-      ParseClosure child = field_parser.AddLengthDelimited(number, size);
-      if (size > end - ptr) {
-        return {ctx->StoreAndTailCall(ptr, end, parent, child, size), true};
-      }
-      auto newend = ptr + size;
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ctx->ParseExactRange(child, ptr, newend),
-                                     {});
-      ptr = newend;
+      ptr = field_parser.ParseLengthDelimited(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       break;
     }
     case WireType::WIRETYPE_START_GROUP: {
-      int depth;
-      ParseClosure child = field_parser.StartGroup(number);
-      auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
-      ptr = res.first;
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
-      if (res.second) {
-        GOOGLE_PROTOBUF_ASSERT_RETURN(
-            ctx->StoreGroup(parent, child, depth, tag), {});
-        return {ptr, true};
-      }
+      ptr = field_parser.ParseGroup(number, ptr, ctx);
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       break;
     }
     case WireType::WIRETYPE_END_GROUP: {
-      field_parser.EndGroup(number);
-      ctx->EndGroup(tag);
-      return {ptr, true};
+      GOOGLE_LOG(FATAL) << "Can't happen";
+      break;
     }
     case WireType::WIRETYPE_FIXED32: {
-      uint32 value = io::UnalignedLoad<uint32>(ptr);
+      uint32 value = UnalignedLoad<uint32>(ptr);
       ptr += 4;
       field_parser.AddFixed32(number, value);
       break;
     }
     default:
-      GOOGLE_PROTOBUF_ASSERT_RETURN(false, {});
-  }
-  GOOGLE_DCHECK(ptr != nullptr);
-  return {ptr, false};
-}
-
-template <typename T>
-const char* WireFormatParser(ParseClosure parent, T field_parser,
-                             const char* begin, const char* end,
-                             ParseContext* ctx) {
-  auto ptr = begin;
-  while (ptr < end) {
-    uint32 tag;
-    ptr = io::Parse32(ptr, &tag);
-    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-    auto res = FieldParser(tag, parent, field_parser, ptr, end, ctx);
-    ptr = res.first;
-    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-    if (res.second) return ptr;
+      return nullptr;
   }
   return ptr;
 }
 
-// Here are the elementary parsers for length delimited subfields that contain
-// plain data (ie not a protobuf). These are trivial as they don't recurse,
-// except for the UnknownGroupLiteParse that parses a group into a string.
-// Some functions need extra arguments that the function signature allows,
-// these are passed through variables in ParseContext::ExtraParseData that the
-// caller needs to set prior to the call.
-
-// The null parser does not do anything, but is useful as a substitute.
-PROTOBUF_EXPORT
-const char* NullParser(const char* begin, const char* end, void* object,
-                       ParseContext*);
-
-// Helper for verification of utf8
-PROTOBUF_EXPORT
-bool VerifyUTF8(StringPiece s, ParseContext* ctx);
-// All the string parsers with or without UTF checking and for all CTypes.
-PROTOBUF_EXPORT
-const char* StringParser(const char* begin, const char* end, void* object,
-                         ParseContext*);
-PROTOBUF_EXPORT
-const char* CordParser(const char* begin, const char* end, void* object,
-                       ParseContext*);
-PROTOBUF_EXPORT
-const char* StringPieceParser(const char* begin, const char* end, void* object,
-                              ParseContext*);
-PROTOBUF_EXPORT
-const char* StringParserUTF8(const char* begin, const char* end, void* object,
-                             ParseContext*);
-PROTOBUF_EXPORT
-const char* CordParserUTF8(const char* begin, const char* end, void* object,
-                           ParseContext*);
-PROTOBUF_EXPORT
-const char* StringPieceParserUTF8(const char* begin, const char* end,
-                                  void* object, ParseContext*);
-PROTOBUF_EXPORT
-const char* StringParserUTF8Verify(const char* begin, const char* end,
-                                   void* object, ParseContext*);
-PROTOBUF_EXPORT
-const char* CordParserUTF8Verify(const char* begin, const char* end,
-                                 void* object, ParseContext*);
-PROTOBUF_EXPORT
-const char* StringPieceParserUTF8Verify(const char* begin, const char* end,
-                                        void* object, ParseContext*);
-// Parsers that also eat the slopbytes if possible. Can only be called in a
-// ParseContext where limit_ is set properly.
-PROTOBUF_EXPORT
-const char* GreedyStringParser(const char* begin, const char* end, void* object,
-                         ParseContext*);
-PROTOBUF_EXPORT
-const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
-                             ParseContext*);
-PROTOBUF_EXPORT
-const char* GreedyStringParserUTF8Verify(const char* begin, const char* end,
-                                   void* object, ParseContext*);
-
-// This is the only recursive parser.
-PROTOBUF_EXPORT
-const char* UnknownGroupLiteParse(const char* begin, const char* end,
-                                  void* object, ParseContext* ctx);
-// This is a helper to for the UnknownGroupLiteParse but is actually also
-// useful in the generated code. It uses overload on string* vs
-// UnknownFieldSet* to make the generated code isomorphic between full and lite.
-PROTOBUF_EXPORT
-std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
-                                               const char* begin,
-                                               const char* end, std::string* unknown,
-                                               ParseContext* ctx);
+template <typename T>
+PROTOBUF_MUST_USE_RESULT const char* WireFormatParser(T& field_parser,
+                                                      const char* ptr,
+                                                      ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    uint32 tag;
+    ptr = ReadTag(ptr, &tag);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+    if (tag == 0 || (tag & 7) == 4) {
+      ctx->SetLastTag(tag);
+      return ptr;
+    }
+    ptr = FieldParser(tag, field_parser, ptr, ctx);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+  }
+  return ptr;
+}
 
 // The packed parsers parse repeated numeric primitives directly into  the
 // corresponding field
 
 // These are packed varints
-PROTOBUF_EXPORT
-const char* PackedInt32Parser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedInt64Parser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedBoolParser(const char* begin, const char* end, void* object,
-                             ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedUInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedUInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedSInt32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedSInt64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParser(
+    void* object, const char* ptr, ParseContext* ctx, bool (*is_valid)(int),
+    std::string* unknown, int field_num);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedEnumParserArg(
+    void* object, const char* ptr, ParseContext* ctx,
+    bool (*is_valid)(const void*, int), const void* data, std::string* unknown,
+    int field_num);
 
-// Enums in proto3 do not require verification
-PROTOBUF_EXPORT
-const char* PackedEnumParser(const char* begin, const char* end, void* object,
-                             ParseContext* ctx);
-// Enums in proto2 require verification. So an additional verification function
-// needs to be passed into ExtraParseData.
-// If it's a generated verification function we only need the function pointer.
-PROTOBUF_EXPORT
-const char* PackedValidEnumParserLite(const char* begin, const char* end,
-                                      void* object, ParseContext* ctx);
-// If it's reflective we need a function that takes an additional argument.
-PROTOBUF_EXPORT
-const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
-                                         void* object, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedBoolParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedSFixed32Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedSFixed64Parser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedFloatParser(
+    void* object, const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* PackedDoubleParser(
+    void* object, const char* ptr, ParseContext* ctx);
 
-// These are the packed fixed field parsers.
-PROTOBUF_EXPORT
-const char* PackedFixed32Parser(const char* begin, const char* end,
-                                void* object, ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedSFixed32Parser(const char* begin, const char* end,
-                                 void* object, ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedFixed64Parser(const char* begin, const char* end,
-                                void* object, ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedSFixed64Parser(const char* begin, const char* end,
-                                 void* object, ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedFloatParser(const char* begin, const char* end, void* object,
-                              ParseContext* ctx);
-PROTOBUF_EXPORT
-const char* PackedDoubleParser(const char* begin, const char* end, void* object,
-                               ParseContext* ctx);
-
-// Maps key/value's are stored in a MapEntry length delimited field. If this
-// crosses a seam we fallback to first store in payload. The object points
-// to a MapField in which we parse the payload upon done (we detect this when
-// this function is called with limit_ == 0), by calling parse_map (also stored
-// in ctx) on the resulting string.
-PROTOBUF_EXPORT
-const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
-                               internal::ParseContext* ctx);
+// This is the only recursive parser.
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* UnknownGroupLiteParse(
+    std::string* unknown, const char* ptr, ParseContext* ctx);
+// This is a helper to for the UnknownGroupLiteParse but is actually also
+// useful in the generated code. It uses overload on string* vs
+// UnknownFieldSet* to make the generated code isomorphic between full and lite.
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* UnknownFieldParse(
+    uint32 tag, std::string* unknown, const char* ptr, ParseContext* ctx);
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 24b3003..dcddb90 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -127,6 +127,9 @@
 #ifdef PROTOC_EXPORT
 #error PROTOC_EXPORT was previously defined
 #endif
+#ifdef PROTOBUF_MUST_USE_RESULT
+#error PROTOBUF_MUST_USE_RESULT was previously defined
+#endif
 
 
 #define PROTOBUF_NAMESPACE "google::protobuf"
@@ -134,6 +137,7 @@
 #define PROTOBUF_DEPRECATED
 #define PROTOBUF_DEPRECATED_MSG(x)
 #define PROTOBUF_SECTION_VARIABLE(x)
+#define PROTOBUF_MUST_USE_RESULT
 
 // ----------------------------------------------------------------------------
 // Annotations:  Some parts of the code have been annotated in ways that might
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index b3177cd..f0cca4e 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -59,6 +59,7 @@
 #undef PROTOBUF_FALLTHROUGH_INTENDED
 #undef PROTOBUF_EXPORT
 #undef PROTOC_EXPORT
+#undef PROTOBUF_MUST_USE_RESULT
 
 // Restore macro that may have been #undef'd in port_def.inc.
 #ifdef _MSC_VER
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 4214422..edb32a3 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -55,6 +55,7 @@
 #include <iterator>
 #include <limits>
 #include <string>
+#include <type_traits>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/arena.h>
@@ -139,6 +140,9 @@
   const Element& operator[](int index) const { return Get(index); }
   Element& operator[](int index) { return *Mutable(index); }
 
+  const Element& at(int index) const;
+  Element& at(int index);
+
   void Set(int index, const Element& value);
   void Add(const Element& value);
   // Appends a new element and return a pointer to it.
@@ -285,7 +289,7 @@
   static const size_t kRepHeaderSize;
 
   // We reuse the Rep* for an Arena* when total_size == 0, to avoid having to do
-  // an allocation in the constructor when we have an Arena.  
+  // an allocation in the constructor when we have an Arena.
   union Pointer {
     Pointer(Arena* a) : arena(a) {}
     Arena* arena;       // When total_size_ == 0.
@@ -412,6 +416,11 @@
   typedef std::true_type type;
 };
 
+template <typename T>
+struct IsMovable
+    : std::integral_constant<bool, std::is_move_constructible<T>::value &&
+                                       std::is_move_assignable<T>::value> {};
+
 // This is the common base class for RepeatedPtrFields.  It deals only in void*
 // pointers.  Users should not use this interface directly.
 //
@@ -447,6 +456,11 @@
   int size() const;
 
   template <typename TypeHandler>
+  const typename TypeHandler::Type& at(int index) const;
+  template <typename TypeHandler>
+  typename TypeHandler::Type& at(int index);
+
+  template <typename TypeHandler>
   typename TypeHandler::Type* Mutable(int index);
   template <typename TypeHandler>
   void Delete(int index);
@@ -476,9 +490,10 @@
   inline void InternalSwap(RepeatedPtrFieldBase* other);
 
  protected:
-  template <typename TypeHandler>
-  void Add(typename TypeHandler::Type&& value,
-           typename std::enable_if<TypeHandler::Moveable>::type* dummy = NULL);
+  template <
+      typename TypeHandler,
+      typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
+  void Add(typename TypeHandler::Type&& value);
 
   template <typename TypeHandler>
   void RemoveLast();
@@ -650,11 +665,14 @@
  public:
   typedef GenericType Type;
   typedef GenericType WeakType;
-  static const bool Moveable = false;
+  using Movable = IsMovable<GenericType>;
 
   static inline GenericType* New(Arena* arena) {
     return Arena::CreateMaybeMessage<Type>(arena);
   }
+  static inline GenericType* New(Arena* arena, GenericType&& value) {
+    return Arena::Create<GenericType>(arena, std::move(value));
+  }
   static inline GenericType* NewFromPrototype(const GenericType* prototype,
                                               Arena* arena = NULL);
   static inline void Delete(GenericType* value, Arena* arena) {
@@ -739,8 +757,7 @@
  public:
   typedef std::string Type;
   typedef std::string WeakType;
-  static const bool Moveable = std::is_move_constructible<Type>::value &&
-                               std::is_move_assignable<Type>::value;
+  using Movable = IsMovable<Type>;
 
   static inline std::string* New(Arena* arena) {
     return Arena::Create<std::string>(arena);
@@ -798,6 +815,9 @@
   const Element& operator[](int index) const { return Get(index); }
   Element& operator[](int index) { return *Mutable(index); }
 
+  const Element& at(int index) const;
+  Element& at(int index);
+
   // Remove the last element in the array.
   // Ownership of the element is retained by the array.
   void RemoveLast();
@@ -1067,10 +1087,19 @@
     ptr_(NULL) {
   int reserve = internal::CalculateReserve(begin, end);
   if (reserve != -1) {
-    Reserve(reserve);
-    for (; begin != end; ++begin) {
-      AddAlreadyReserved(*begin);
+    if (reserve == 0) {
+      return;
     }
+
+    Reserve(reserve);
+    // TODO(ckennelly):  The compiler loses track of the buffer freshly
+    // allocated by Reserve() by the time we call elements, so it cannot
+    // guarantee that elements does not alias [begin(), end()).
+    //
+    // If restrict is available, annotating the pointer obtained from elements()
+    // causes this to lower to memcpy instead of memmove.
+    std::copy(begin, end, elements());
+    current_size_ = reserve;
   } else {
     for (; begin != end; ++begin) {
       Add(*begin);
@@ -1180,6 +1209,20 @@
 }
 
 template <typename Element>
+inline const Element& RepeatedField<Element>::at(int index) const {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
+inline Element& RepeatedField<Element>::at(int index) {
+  GOOGLE_CHECK_GE(index, 0);
+  GOOGLE_CHECK_LT(index, current_size_);
+  return elements()[index];
+}
+
+template <typename Element>
 inline Element* RepeatedField<Element>::Mutable(int index) {
   GOOGLE_DCHECK_GE(index, 0);
   GOOGLE_DCHECK_LT(index, current_size_);
@@ -1516,6 +1559,21 @@
 }
 
 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);
@@ -1546,10 +1604,9 @@
   return result;
 }
 
-template <typename TypeHandler>
-inline void RepeatedPtrFieldBase::Add(
-    typename TypeHandler::Type&& value,
-    typename std::enable_if<TypeHandler::Moveable>::type*) {
+template <typename TypeHandler,
+          typename std::enable_if<TypeHandler::Movable::value>::type*>
+inline void RepeatedPtrFieldBase::Add(typename TypeHandler::Type&& value) {
   if (rep_ != NULL && current_size_ < rep_->allocated_size) {
     *cast<TypeHandler>(rep_->elements[current_size_++]) = std::move(value);
     return;
@@ -1974,6 +2031,16 @@
   return RepeatedPtrFieldBase::Get<TypeHandler>(index);
 }
 
+template <typename Element>
+inline const Element& RepeatedPtrField<Element>::at(int index) const {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
+template <typename Element>
+inline Element& RepeatedPtrField<Element>::at(int index) {
+  return RepeatedPtrFieldBase::at<TypeHandler>(index);
+}
+
 
 template <typename Element>
 inline Element* RepeatedPtrField<Element>::Mutable(int index) {
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 033e343..d054ac9 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -38,6 +38,7 @@
 #include <algorithm>
 #include <limits>
 #include <list>
+#include <type_traits>
 #include <vector>
 
 #include <google/protobuf/repeated_field.h>
@@ -71,26 +72,41 @@
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 1);
   EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
 
   field.Add(42);
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 2);
   EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
   EXPECT_EQ(field.Get(1), 42);
+  EXPECT_EQ(field.at(1), 42);
 
   field.Set(1, 23);
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 2);
   EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
   EXPECT_EQ(field.Get(1), 23);
+  EXPECT_EQ(field.at(1), 23);
+
+  field.at(1) = 25;
+
+  EXPECT_FALSE(field.empty());
+  EXPECT_EQ(field.size(), 2);
+  EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
+  EXPECT_EQ(field.Get(1), 25);
+  EXPECT_EQ(field.at(1), 25);
 
   field.RemoveLast();
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 1);
   EXPECT_EQ(field.Get(0), 5);
+  EXPECT_EQ(field.at(0), 5);
 
   field.Clear();
 
@@ -341,6 +357,9 @@
 
 TEST(RepeatedField, IteratorConstruct) {
   std::vector<int> values;
+  RepeatedField<int> empty(values.begin(), values.end());
+  ASSERT_EQ(values.size(), empty.size());
+
   values.push_back(1);
   values.push_back(2);
 
@@ -516,6 +535,48 @@
   }
 }
 
+TEST(Movable, Works) {
+  class NonMoveConstructible {
+   public:
+    NonMoveConstructible(NonMoveConstructible&&) = delete;
+    NonMoveConstructible& operator=(NonMoveConstructible&&) { return *this; }
+  };
+  class NonMoveAssignable {
+   public:
+    NonMoveAssignable(NonMoveAssignable&&) {}
+    NonMoveAssignable& operator=(NonMoveConstructible&&) = delete;
+  };
+  class NonMovable {
+   public:
+    NonMovable(NonMovable&&) = delete;
+    NonMovable& operator=(NonMovable&&) = delete;
+  };
+
+  EXPECT_TRUE(internal::IsMovable<string>::value);
+
+  EXPECT_FALSE(std::is_move_constructible<NonMoveConstructible>::value);
+  EXPECT_TRUE(std::is_move_assignable<NonMoveConstructible>::value);
+  EXPECT_FALSE(internal::IsMovable<NonMoveConstructible>::value);
+
+  EXPECT_TRUE(std::is_move_constructible<NonMoveAssignable>::value);
+  EXPECT_FALSE(std::is_move_assignable<NonMoveAssignable>::value);
+  EXPECT_FALSE(internal::IsMovable<NonMoveAssignable>::value);
+
+  EXPECT_FALSE(internal::IsMovable<NonMovable>::value);
+}
+
+TEST(RepeatedField, MoveAdd) {
+  RepeatedPtrField<TestAllTypes> field;
+  TestAllTypes test_all_types;
+  auto* optional_nested_message =
+      test_all_types.mutable_optional_nested_message();
+  optional_nested_message->set_bb(42);
+  field.Add(std::move(test_all_types));
+
+  EXPECT_EQ(optional_nested_message,
+            field.Mutable(0)->mutable_optional_nested_message());
+}
+
 TEST(RepeatedField, MutableDataIsMutable) {
   RepeatedField<int> field;
   field.Add(1);
@@ -633,26 +694,32 @@
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 1);
   EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
 
   field.Add()->assign("bar");
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 2);
   EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
   EXPECT_EQ(field.Get(1), "bar");
+  EXPECT_EQ(field.at(1), "bar");
 
   field.Mutable(1)->assign("baz");
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 2);
   EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
   EXPECT_EQ(field.Get(1), "baz");
+  EXPECT_EQ(field.at(1), "baz");
 
   field.RemoveLast();
 
   EXPECT_FALSE(field.empty());
   EXPECT_EQ(field.size(), 1);
   EXPECT_EQ(field.Get(0), "foo");
+  EXPECT_EQ(field.at(0), "foo");
 
   field.Clear();
 
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 89faa46..566eed7 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_SourceContext_google_2fprotobuf_2fsource_5fcontext_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -62,7 +62,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_SourceContext_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fsource_5fcontext_2eproto, "google/protobuf/source_context.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fsource_5fcontext_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
@@ -77,7 +77,7 @@
   "text\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTy"
   "pesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fsource_5fcontext_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
   "google/protobuf/source_context.proto", &assign_descriptors_table_google_2fprotobuf_2fsource_5fcontext_2eproto, 251,
@@ -158,56 +158,33 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* SourceContext::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<SourceContext*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* SourceContext::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string file_name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_file_name(), ptr, ctx, "google.protobuf.SourceContext.file_name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.SourceContext.file_name");
-        object = msg->mutable_file_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool SourceContext::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index 4ed8997..ae50e80 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fsource_5fcontext_2eproto PROTOBUF_EXPORT
@@ -124,8 +131,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -137,10 +143,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(SourceContext* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.SourceContext";
+  }
   private:
   inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
     return nullptr;
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index c0fd3f3..b107e5d 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -78,9 +78,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_ListValue_google_2fprotobuf_2fstruct_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
-const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fstruct_2eproto[4];
+static const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto[1];
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   PROTOBUF_FIELD_OFFSET(::google::protobuf::Struct_FieldsEntry_DoNotUse, _has_bits_),
@@ -131,7 +131,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_ListValue_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fstruct_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fstruct_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fstruct_2eproto, "google/protobuf/struct.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fstruct_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fstruct_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto, file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
@@ -156,7 +156,7 @@
   "\252\002\036Google.Protobuf.WellKnownTypesb\006proto"
   "3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fstruct_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
   "google/protobuf/struct.proto", &assign_descriptors_table_google_2fprotobuf_2fstruct_2eproto, 641,
@@ -204,25 +204,6 @@
   ::google::protobuf::Message::MergeFrom(other);
 }
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-bool Struct_FieldsEntry_DoNotUse::_ParseMap(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx) {
-  using MF = ::google::protobuf::internal::MapField<
-      Struct_FieldsEntry_DoNotUse, EntryKeyType, EntryValueType,
-      kEntryKeyFieldType, kEntryValueFieldType,
-      kEntryDefaultEnumValue>;
-  auto mf = static_cast<MF*>(object);
-  Parser<MF, ::google::protobuf::Map<EntryKeyType, EntryValueType>> parser(mf);
-#define DO_(x) if (!(x)) return false
-  DO_(parser.ParseMap(begin, end));
-  DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
-    parser.key().data(), static_cast<int>(parser.key().length()),
-    ::google::protobuf::internal::WireFormatLite::PARSE,
-    "google.protobuf.Struct.FieldsEntry.key"));
-#undef DO_
-  return true;
-}
-#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-
 
 // ===================================================================
 
@@ -297,55 +278,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Struct::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Struct*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Struct::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // map<string, .google.protobuf.Value> fields = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(&fields_, ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::internal::SlowMapEntryParser;
-          auto parse_map = ::google::protobuf::Struct_FieldsEntry_DoNotUse::_ParseMap;
-          ctx->extra_parse_data().payload.clear();
-          ctx->extra_parse_data().parse_map = parse_map;
-          object = &msg->fields_;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(parse_map(ptr, newend, object, ctx));
-          ptr = newend;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Struct::MergePartialFromCodedStream(
@@ -434,25 +396,17 @@
         items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);
       }
       ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
-      ::std::unique_ptr<Struct_FieldsEntry_DoNotUse> entry;
       for (size_type i = 0; i < n; i++) {
-        entry.reset(fields_.NewEntryWrapper(items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second));
-        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(1, *entry, output);
-        if (entry->GetArena() != nullptr) {
-          entry.release();
-        }
+        Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second);
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(1, entry, output);
         Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
       }
     } else {
-      ::std::unique_ptr<Struct_FieldsEntry_DoNotUse> entry;
       for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
           it = this->fields().begin();
           it != this->fields().end(); ++it) {
-        entry.reset(fields_.NewEntryWrapper(it->first, it->second));
-        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(1, *entry, output);
-        if (entry->GetArena() != nullptr) {
-          entry.release();
-        }
+        Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(1, entry, output);
         Utf8Check::Check(&(*it));
       }
     }
@@ -498,25 +452,17 @@
         items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);
       }
       ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
-      ::std::unique_ptr<Struct_FieldsEntry_DoNotUse> entry;
       for (size_type i = 0; i < n; i++) {
-        entry.reset(fields_.NewEntryWrapper(items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second));
-        target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, *entry, target);
-        if (entry->GetArena() != nullptr) {
-          entry.release();
-        }
+        Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second);
+        target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, entry, target);
         Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
       }
     } else {
-      ::std::unique_ptr<Struct_FieldsEntry_DoNotUse> entry;
       for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
           it = this->fields().begin();
           it != this->fields().end(); ++it) {
-        entry.reset(fields_.NewEntryWrapper(it->first, it->second));
-        target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, *entry, target);
-        if (entry->GetArena() != nullptr) {
-          entry.release();
-        }
+        Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
+        target = ::google::protobuf::internal::WireFormatLite::InternalWriteMessageNoVirtualToArray(1, entry, target);
         Utf8Check::Check(&(*it));
       }
     }
@@ -546,21 +492,12 @@
   // map<string, .google.protobuf.Value> fields = 1;
   total_size += 1 *
       ::google::protobuf::internal::FromIntSize(this->fields_size());
-  {
-    ::std::unique_ptr<Struct_FieldsEntry_DoNotUse> entry;
-    for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = this->fields().begin();
-        it != this->fields().end(); ++it) {
-      if (entry.get() != nullptr && entry->GetArena() != nullptr) {
-        entry.release();
-      }
-      entry.reset(fields_.NewEntryWrapper(it->first, it->second));
-      total_size += ::google::protobuf::internal::WireFormatLite::
-          MessageSizeNoVirtual(*entry);
-    }
-    if (entry.get() != nullptr && entry->GetArena() != nullptr) {
-      entry.release();
-    }
+  for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
+      it = this->fields().begin();
+      it != this->fields().end(); ++it) {
+    Struct_FieldsEntry_DoNotUse::MapEntryWrapper entry(nullptr, it->first, it->second);
+    total_size += ::google::protobuf::internal::WireFormatLite::
+        MessageSizeNoVirtual(entry);
   }
 
   int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
@@ -841,104 +778,69 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Value::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Value*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Value::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // .google.protobuf.NullValue null_value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_null_value(static_cast<::google::protobuf::NullValue>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_null_value(static_cast<::google::protobuf::NullValue>(val));
         break;
       }
       // double number_value = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 17) goto handle_unusual;
-        msg->set_number_value(::google::protobuf::io::UnalignedLoad<double>(ptr));
+        set_number_value(::google::protobuf::internal::UnalignedLoad<double>(ptr));
         ptr += sizeof(double);
         break;
       }
       // string string_value = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_string_value(), ptr, ctx, "google.protobuf.Value.string_value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Value.string_value");
-        object = msg->mutable_string_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // bool bool_value = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 32) goto handle_unusual;
-        msg->set_bool_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_bool_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // .google.protobuf.Struct struct_value = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_struct_value(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::Struct::_InternalParse;
-        object = msg->mutable_struct_value();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // .google.protobuf.ListValue list_value = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_list_value(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::ListValue::_InternalParse;
-        object = msg->mutable_list_value();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Value::MergePartialFromCodedStream(
@@ -1393,52 +1295,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* ListValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<ListValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* ListValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // repeated .google.protobuf.Value values = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_values(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Value::_InternalParse;
-          object = msg->add_values();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool ListValue::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 7d8040d..204edc3 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -35,6 +35,13 @@
 #include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fstruct_2eproto PROTOBUF_EXPORT
@@ -81,9 +88,9 @@
   NullValue_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::google::protobuf::int32>::max()
 };
 PROTOBUF_EXPORT bool NullValue_IsValid(int value);
-const NullValue NullValue_MIN = NULL_VALUE;
-const NullValue NullValue_MAX = NULL_VALUE;
-const int NullValue_ARRAYSIZE = NullValue_MAX + 1;
+constexpr NullValue NullValue_MIN = NULL_VALUE;
+constexpr NullValue NullValue_MAX = NULL_VALUE;
+constexpr int NullValue_ARRAYSIZE = NullValue_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* NullValue_descriptor();
 inline const ::std::string& NullValue_Name(NullValue value) {
@@ -103,9 +110,6 @@
     ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
     0 > {
 public:
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-static bool _ParseMap(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
   typedef ::google::protobuf::internal::MapEntry<Struct_FieldsEntry_DoNotUse, 
     ::std::string, ::google::protobuf::Value,
     ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
@@ -191,8 +195,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -204,10 +207,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Struct* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Struct";
+  }
   protected:
   explicit Struct(::google::protobuf::Arena* arena);
   private:
@@ -337,8 +344,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -350,10 +356,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Value* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Value";
+  }
   protected:
   explicit Value(::google::protobuf::Arena* arena);
   private:
@@ -556,8 +566,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -569,10 +578,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(ListValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.ListValue";
+  }
   protected:
   explicit ListValue(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index d87e993..5b8e85d 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -432,7 +432,8 @@
 }  // namespace google
 
 #ifdef PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#define GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER 1
+#define GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER \
+  PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 #else
 #define GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER 0
 #endif
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 1339449..c660315 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -53,6 +53,7 @@
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.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>
@@ -101,8 +102,7 @@
 
   printer.PrintToString(*this, &debug_string);
   // Single line mode currently might have an extra space at the end.
-  if (debug_string.size() > 0 &&
-      debug_string[debug_string.size() - 1] == ' ') {
+  if (debug_string.size() > 0 && debug_string[debug_string.size() - 1] == ' ') {
     debug_string.resize(debug_string.size() - 1);
   }
 
@@ -121,14 +121,12 @@
   return debug_string;
 }
 
-void Message::PrintDebugString() const {
-  printf("%s", DebugString().c_str());
-}
+void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); }
 
 
 // ===========================================================================
 // Implementation of the parse information tree class.
-TextFormat::ParseInfoTree::ParseInfoTree() { }
+TextFormat::ParseInfoTree::ParseInfoTree() {}
 
 TextFormat::ParseInfoTree::~ParseInfoTree() {
   // Remove any nested information trees, as they are owned by this tree.
@@ -138,8 +136,7 @@
 }
 
 void TextFormat::ParseInfoTree::RecordLocation(
-    const FieldDescriptor* field,
-    TextFormat::ParseLocation location) {
+    const FieldDescriptor* field, TextFormat::ParseLocation location) {
   locations_[field].push_back(location);
 }
 
@@ -154,7 +151,9 @@
 }
 
 void CheckFieldIndex(const FieldDescriptor* field, int index) {
-  if (field == NULL) { return; }
+  if (field == NULL) {
+    return;
+  }
 
   if (field->is_repeated() && index == -1) {
     GOOGLE_LOG(DFATAL) << "Index must be in range of repeated field values. "
@@ -168,7 +167,9 @@
 TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
     const FieldDescriptor* field, int index) const {
   CheckFieldIndex(field, index);
-  if (index == -1) { index = 0; }
+  if (index == -1) {
+    index = 0;
+  }
 
   const std::vector<TextFormat::ParseLocation>* locations =
       FindOrNull(locations_, field);
@@ -182,7 +183,9 @@
 TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
     const FieldDescriptor* field, int index) const {
   CheckFieldIndex(field, index);
-  if (index == -1) { index = 0; }
+  if (index == -1) {
+    index = 0;
+  }
 
   const std::vector<TextFormat::ParseInfoTree*>* trees =
       FindOrNull(nested_, field);
@@ -222,11 +225,14 @@
 // Makes code slightly more readable.  The meaning of "DO(foo)" is
 // "Execute foo and fail if it fails.", where failure is indicated by
 // returning false. Borrowed from parser.cc (Thanks Kenton!).
-#define DO(STATEMENT) if (STATEMENT) {} else return false
+#define DO(STATEMENT) \
+  if (STATEMENT) {    \
+  } else {            \
+    return false;     \
+  }
 
 class TextFormat::Parser::ParserImpl {
  public:
-
   // Determines if repeated values for non-repeated fields and
   // oneofs are permitted, e.g., the string "foo: 1 foo: 2" for a
   // required/optional field named "foo", or "baz: 1 qux: 2"
@@ -239,31 +245,27 @@
   ParserImpl(const Descriptor* root_message_type,
              io::ZeroCopyInputStream* input_stream,
              io::ErrorCollector* error_collector,
-             const TextFormat::Finder* finder,
-             ParseInfoTree* parse_info_tree,
+             const TextFormat::Finder* finder, ParseInfoTree* parse_info_tree,
              SingularOverwritePolicy singular_overwrite_policy,
-             bool allow_case_insensitive_field,
-             bool allow_unknown_field,
-             bool allow_unknown_extension,
-             bool allow_unknown_enum,
-             bool allow_field_number,
-             bool allow_relaxed_whitespace,
-             bool allow_partial)
-    : error_collector_(error_collector),
-      finder_(finder),
-      parse_info_tree_(parse_info_tree),
-      tokenizer_error_collector_(this),
-      tokenizer_(input_stream, &tokenizer_error_collector_),
-      root_message_type_(root_message_type),
-      singular_overwrite_policy_(singular_overwrite_policy),
-      allow_case_insensitive_field_(allow_case_insensitive_field),
-      allow_unknown_field_(allow_unknown_field),
-      allow_unknown_extension_(allow_unknown_extension),
-      allow_unknown_enum_(allow_unknown_enum),
-      allow_field_number_(allow_field_number),
-      allow_partial_(allow_partial),
-      recursion_budget_(io::CodedInputStream::GetDefaultRecursionLimit()),
-      had_errors_(false) {
+             bool allow_case_insensitive_field, bool allow_unknown_field,
+             bool allow_unknown_extension, bool allow_unknown_enum,
+             bool allow_field_number, bool allow_relaxed_whitespace,
+             bool allow_partial, int recursion_limit)
+      : error_collector_(error_collector),
+        finder_(finder),
+        parse_info_tree_(parse_info_tree),
+        tokenizer_error_collector_(this),
+        tokenizer_(input_stream, &tokenizer_error_collector_),
+        root_message_type_(root_message_type),
+        singular_overwrite_policy_(singular_overwrite_policy),
+        allow_case_insensitive_field_(allow_case_insensitive_field),
+        allow_unknown_field_(allow_unknown_field),
+        allow_unknown_extension_(allow_unknown_extension),
+        allow_unknown_enum_(allow_unknown_enum),
+        allow_field_number_(allow_field_number),
+        allow_partial_(allow_partial),
+        recursion_limit_(recursion_limit),
+        had_errors_(false) {
     // For backwards-compatibility with proto1, we need to allow the 'f' suffix
     // for floats.
     tokenizer_.set_allow_f_after_float(true);
@@ -279,7 +281,7 @@
     // Consume the starting token.
     tokenizer_.Next();
   }
-  ~ParserImpl() { }
+  ~ParserImpl() {}
 
   // Parses the ASCII representation specified in input and saves the
   // information into the output pointer (a Message). Returns
@@ -311,13 +313,11 @@
     if (error_collector_ == NULL) {
       if (line >= 0) {
         GOOGLE_LOG(ERROR) << "Error parsing text-format "
-                   << root_message_type_->full_name()
-                   << ": " << (line + 1) << ":"
-                   << (col + 1) << ": " << message;
+                   << root_message_type_->full_name() << ": " << (line + 1)
+                   << ":" << (col + 1) << ": " << message;
       } else {
         GOOGLE_LOG(ERROR) << "Error parsing text-format "
-                   << root_message_type_->full_name()
-                   << ": " << message;
+                   << root_message_type_->full_name() << ": " << message;
       }
     } else {
       error_collector_->AddError(line, col, message);
@@ -328,13 +328,11 @@
     if (error_collector_ == NULL) {
       if (line >= 0) {
         GOOGLE_LOG(WARNING) << "Warning parsing text-format "
-                     << root_message_type_->full_name()
-                     << ": " << (line + 1) << ":"
-                     << (col + 1) << ": " << message;
+                     << root_message_type_->full_name() << ": " << (line + 1)
+                     << ":" << (col + 1) << ": " << message;
       } else {
         GOOGLE_LOG(WARNING) << "Warning parsing text-format "
-                     << root_message_type_->full_name()
-                     << ": " << message;
+                     << root_message_type_->full_name() << ": " << message;
       }
     } else {
       error_collector_->AddWarning(line, col, message);
@@ -362,7 +360,7 @@
   // This method checks to see that the end delimiter at the conclusion of
   // the consumption matches the starting delimiter passed in here.
   bool ConsumeMessage(Message* message, const string delimiter) {
-    while (!LookingAt(">") &&  !LookingAt("}")) {
+    while (!LookingAt(">") && !LookingAt("}")) {
       DO(ConsumeField(message));
     }
 
@@ -424,9 +422,8 @@
           return false;
         }
       }
-      reflection->SetString(
-          message, any_type_url_field,
-          string(prefix + full_type_name));
+      reflection->SetString(message, any_type_url_field,
+                            string(prefix + full_type_name));
       reflection->SetString(message, any_value_field, serialized_value);
       return true;
     }
@@ -440,7 +437,8 @@
 
       if (field == NULL) {
         if (!allow_unknown_field_ && !allow_unknown_extension_) {
-          ReportError("Extension \"" + field_name + "\" is not defined or "
+          ReportError("Extension \"" + field_name +
+                      "\" is not defined or "
                       "is not an extension of \"" +
                       descriptor->full_name() + "\".");
           return false;
@@ -478,8 +476,8 @@
           }
         }
         // Again, special-case group names as described above.
-        if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
-            && field->message_type()->name() != field_name) {
+        if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP &&
+            field->message_type()->name() != field_name) {
           field = NULL;
         }
 
@@ -536,9 +534,13 @@
       if (oneof != NULL && reflection->HasOneof(*message, oneof)) {
         const FieldDescriptor* other_field =
             reflection->GetOneofFieldDescriptor(*message, oneof);
-        ReportError("Field \"" + field_name + "\" is specified along with "
-                    "field \"" + other_field->name() + "\", another member "
-                    "of oneof \"" + oneof->name() + "\".");
+        ReportError("Field \"" + field_name +
+                    "\" is specified along with "
+                    "field \"" +
+                    other_field->name() +
+                    "\", another member "
+                    "of oneof \"" +
+                    oneof->name() + "\".");
         return false;
       }
     }
@@ -547,11 +549,15 @@
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       // ':' is optional here.
       bool consumed_semicolon = TryConsume(":");
-      if (consumed_semicolon && field->options().weak() && LookingAtType(io::Tokenizer::TYPE_STRING)) {
+      if (consumed_semicolon && field->options().weak() &&
+          LookingAtType(io::Tokenizer::TYPE_STRING)) {
         // we are getting a bytes string for a weak field.
         string tmp;
         DO(ConsumeString(&tmp));
-        reflection->MutableMessage(message, field)->ParseFromString(tmp);
+        MessageFactory* factory =
+            finder_ ? finder_->FindExtensionFactory(field) : nullptr;
+        reflection->MutableMessage(message, field, factory)
+            ->ParseFromString(tmp);
         goto label_skip_parsing;
       }
     } else {
@@ -581,14 +587,14 @@
     } else {
       DO(ConsumeFieldValue(message, reflection, field));
     }
-label_skip_parsing:
+  label_skip_parsing:
     // For historical reasons, fields may optionally be separated by commas or
     // semicolons.
     TryConsume(";") || TryConsume(",");
 
     if (field->options().deprecated()) {
-      ReportWarning("text format contains deprecated field \""
-                    + field_name + "\"");
+      ReportWarning("text format contains deprecated field \"" + field_name +
+                    "\"");
     }
 
     // If a parse info tree exists, add the location for the parsed
@@ -629,14 +635,12 @@
     return true;
   }
 
-  bool ConsumeFieldMessage(Message* message,
-                           const Reflection* reflection,
+  bool ConsumeFieldMessage(Message* message, const Reflection* reflection,
                            const FieldDescriptor* field) {
-    if (--recursion_budget_ < 0) {
+    if (--recursion_limit_ < 0) {
       ReportError("Message is too deep");
       return false;
     }
-
     // If the parse information tree is not NULL, create a nested one
     // for the nested message.
     ParseInfoTree* parent = parse_info_tree_;
@@ -646,14 +650,17 @@
 
     string delimiter;
     DO(ConsumeMessageDelimiter(&delimiter));
+    MessageFactory* factory =
+        finder_ ? finder_->FindExtensionFactory(field) : nullptr;
     if (field->is_repeated()) {
-      DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter));
+      DO(ConsumeMessage(reflection->AddMessage(message, field, factory),
+                        delimiter));
     } else {
-      DO(ConsumeMessage(reflection->MutableMessage(message, field),
+      DO(ConsumeMessage(reflection->MutableMessage(message, field, factory),
                         delimiter));
     }
 
-    ++recursion_budget_;
+    ++recursion_limit_;
 
     // Reset the parse information tree.
     parse_info_tree_ = parent;
@@ -665,28 +672,26 @@
   bool SkipFieldMessage() {
     string delimiter;
     DO(ConsumeMessageDelimiter(&delimiter));
-    while (!LookingAt(">") &&  !LookingAt("}")) {
+    while (!LookingAt(">") && !LookingAt("}")) {
       DO(SkipField());
     }
     DO(Consume(delimiter));
     return true;
   }
 
-  bool ConsumeFieldValue(Message* message,
-                         const Reflection* reflection,
+  bool ConsumeFieldValue(Message* message, const Reflection* reflection,
                          const FieldDescriptor* field) {
-
 // Define an easy to use macro for setting fields. This macro checks
 // to see if the field is repeated (in which case we need to use the Add
 // methods or not (in which case we need to use the Set methods).
-#define SET_FIELD(CPPTYPE, VALUE)                                  \
-        if (field->is_repeated()) {                                \
-          reflection->Add##CPPTYPE(message, field, VALUE);         \
-        } else {                                                   \
-          reflection->Set##CPPTYPE(message, field, VALUE);         \
-        }                                                          \
+#define SET_FIELD(CPPTYPE, VALUE)                    \
+  if (field->is_repeated()) {                        \
+    reflection->Add##CPPTYPE(message, field, VALUE); \
+  } else {                                           \
+    reflection->Set##CPPTYPE(message, field, VALUE); \
+  }
 
-    switch(field->cpp_type()) {
+    switch (field->cpp_type()) {
       case FieldDescriptor::CPPTYPE_INT32: {
         int64 value;
         DO(ConsumeSignedInteger(&value, kint32max));
@@ -749,8 +754,8 @@
           } else if (value == "false" || value == "False" || value == "f") {
             SET_FIELD(Bool, false);
           } else {
-            ReportError("Invalid value for boolean field \"" + field->name()
-                        + "\". Value: \"" + value  + "\".");
+            ReportError("Invalid value for boolean field \"" + field->name() +
+                        "\". Value: \"" + value + "\".");
             return false;
           }
         }
@@ -785,12 +790,16 @@
             SET_FIELD(EnumValue, int_value);
             return true;
           } else if (!allow_unknown_enum_) {
-            ReportError("Unknown enumeration value of \"" + value  + "\" for "
-                        "field \"" + field->name() + "\".");
+            ReportError("Unknown enumeration value of \"" + value +
+                        "\" for "
+                        "field \"" +
+                        field->name() + "\".");
             return false;
           } else {
-            ReportWarning("Unknown enumeration value of \"" + value  + "\" for "
-                          "field \"" + field->name() + "\".");
+            ReportWarning("Unknown enumeration value of \"" + value +
+                          "\" for "
+                          "field \"" +
+                          field->name() + "\".");
             return true;
           }
         }
@@ -870,8 +879,7 @@
       string text = tokenizer_.current().text;
       LowerString(&text);
       if (text != "inf" &&
-          text != "infinity" &&
-          text != "nan") {
+          text != "infinity" && text != "nan") {
         ReportError("Invalid float number: " + text);
         return false;
       }
@@ -960,8 +968,8 @@
       return false;
     }
 
-    if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
-                                     max_value, value)) {
+    if (!io::Tokenizer::ParseInteger(tokenizer_.current().text, max_value,
+                                     value)) {
       ReportError("Integer out of range (" + tokenizer_.current().text + ")");
       return false;
     }
@@ -1130,8 +1138,8 @@
     const string& current_value = tokenizer_.current().text;
 
     if (current_value != value) {
-      ReportError("Expected \"" + value + "\", found \"" + current_value
-                  + "\".");
+      ReportError("Expected \"" + value + "\", found \"" + current_value +
+                  "\".");
       return false;
     }
 
@@ -1155,8 +1163,8 @@
   // collect any base-level parse errors and feed them to the ParserImpl.
   class ParserErrorCollector : public io::ErrorCollector {
    public:
-    explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser) :
-        parser_(parser) { }
+    explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser)
+        : parser_(parser) {}
 
     ~ParserErrorCollector() override {}
 
@@ -1186,7 +1194,7 @@
   const bool allow_unknown_enum_;
   const bool allow_field_number_;
   const bool allow_partial_;
-  int recursion_budget_;
+  int recursion_limit_;
   bool had_errors_;
 };
 
@@ -1198,14 +1206,13 @@
  public:
   explicit TextGenerator(io::ZeroCopyOutputStream* output,
                          int initial_indent_level)
-    : output_(output),
-      buffer_(NULL),
-      buffer_size_(0),
-      at_start_of_line_(true),
-      failed_(false),
-      indent_level_(initial_indent_level),
-      initial_indent_level_(initial_indent_level) {
-  }
+      : output_(output),
+        buffer_(NULL),
+        buffer_size_(0),
+        at_start_of_line_(true),
+        failed_(false),
+        indent_level_(initial_indent_level),
+        initial_indent_level_(initial_indent_level) {}
 
   ~TextGenerator() {
     // Only BackUp() if we're sure we've successfully called Next() at least
@@ -1223,8 +1230,7 @@
   // Reduces the current indent level by two spaces, or crashes if the indent
   // level is zero.
   void Outdent() override {
-    if (indent_level_ == 0 ||
-        indent_level_ < initial_indent_level_) {
+    if (indent_level_ == 0 || indent_level_ < initial_indent_level_) {
       GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
       return;
     }
@@ -1298,7 +1304,9 @@
   }
 
   void WriteIndent() {
-    if (indent_level_ == 0) { return; }
+    if (indent_level_ == 0) {
+      return;
+    }
     GOOGLE_DCHECK(!failed_);
     int size = 2 * indent_level_;
 
@@ -1331,8 +1339,7 @@
 
 // ===========================================================================
 // Implementation of the default Finder for extensions.
-TextFormat::Finder::~Finder() {
-}
+TextFormat::Finder::~Finder() {}
 
 const FieldDescriptor* TextFormat::Finder::FindExtension(
     Message* message, const string& name) const {
@@ -1345,21 +1352,26 @@
   return DefaultFinderFindAnyType(message, prefix, name);
 }
 
+MessageFactory* TextFormat::Finder::FindExtensionFactory(
+    const FieldDescriptor* field) const {
+  return nullptr;
+}
+
 // ===========================================================================
 
 TextFormat::Parser::Parser()
-  : error_collector_(NULL),
-    finder_(NULL),
-    parse_info_tree_(NULL),
-    allow_partial_(false),
-    allow_case_insensitive_field_(false),
-    allow_unknown_field_(false),
-    allow_unknown_extension_(false),
-    allow_unknown_enum_(false),
-    allow_field_number_(false),
-    allow_relaxed_whitespace_(false),
-    allow_singular_overwrites_(false) {
-}
+    : error_collector_(NULL),
+      finder_(NULL),
+      parse_info_tree_(NULL),
+      allow_partial_(false),
+      allow_case_insensitive_field_(false),
+      allow_unknown_field_(false),
+      allow_unknown_extension_(false),
+      allow_unknown_enum_(false),
+      allow_field_number_(false),
+      allow_relaxed_whitespace_(false),
+      allow_singular_overwrites_(false),
+      recursion_limit_(std::numeric_limits<int>::max()) {}
 
 TextFormat::Parser::~Parser() {}
 
@@ -1384,20 +1396,19 @@
   output->Clear();
 
   ParserImpl::SingularOverwritePolicy overwrites_policy =
-      allow_singular_overwrites_
-      ? ParserImpl::ALLOW_SINGULAR_OVERWRITES
-      : ParserImpl::FORBID_SINGULAR_OVERWRITES;
+      allow_singular_overwrites_ ? ParserImpl::ALLOW_SINGULAR_OVERWRITES
+                                 : ParserImpl::FORBID_SINGULAR_OVERWRITES;
 
-  ParserImpl parser(
-      output->GetDescriptor(), input, error_collector_, finder_,
-      parse_info_tree_, overwrites_policy, allow_case_insensitive_field_,
-      allow_unknown_field_, allow_unknown_extension_, allow_unknown_enum_,
-      allow_field_number_, allow_relaxed_whitespace_, allow_partial_);
+  ParserImpl parser(output->GetDescriptor(), input, error_collector_, finder_,
+                    parse_info_tree_, overwrites_policy,
+                    allow_case_insensitive_field_, allow_unknown_field_,
+                    allow_unknown_extension_, allow_unknown_enum_,
+                    allow_field_number_, allow_relaxed_whitespace_,
+                    allow_partial_, recursion_limit_);
   return MergeUsingImpl(input, output, &parser);
 }
 
-bool TextFormat::Parser::ParseFromString(const string& input,
-                                         Message* output) {
+bool TextFormat::Parser::ParseFromString(const string& input, Message* output) {
   DO(CheckParseInputSize(input, error_collector_));
   io::ArrayInputStream input_stream(input.data(), input.size());
   return Parse(&input_stream, output);
@@ -1411,12 +1422,11 @@
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_extension_, allow_unknown_enum_,
                     allow_field_number_, allow_relaxed_whitespace_,
-                    allow_partial_);
+                    allow_partial_, recursion_limit_);
   return MergeUsingImpl(input, output, &parser);
 }
 
-bool TextFormat::Parser::MergeFromString(const string& input,
-                                         Message* output) {
+bool TextFormat::Parser::MergeFromString(const string& input, Message* output) {
   DO(CheckParseInputSize(input, error_collector_));
   io::ArrayInputStream input_stream(input.data(), input.size());
   return Merge(&input_stream, output);
@@ -1438,17 +1448,16 @@
   return true;
 }
 
-bool TextFormat::Parser::ParseFieldValueFromString(
-    const string& input,
-    const FieldDescriptor* field,
-    Message* output) {
+bool TextFormat::Parser::ParseFieldValueFromString(const string& input,
+                                                   const FieldDescriptor* field,
+                                                   Message* output) {
   io::ArrayInputStream input_stream(input.data(), input.size());
   ParserImpl parser(
       output->GetDescriptor(), &input_stream, error_collector_, finder_,
       parse_info_tree_, ParserImpl::ALLOW_SINGULAR_OVERWRITES,
       allow_case_insensitive_field_, allow_unknown_field_,
       allow_unknown_extension_, allow_unknown_enum_, allow_field_number_,
-      allow_relaxed_whitespace_, allow_partial_);
+      allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
   return parser.ParseField(field, output);
 }
 
@@ -1490,7 +1499,7 @@
 
 // Some compilers do not support ref-qualifiers even in C++11 mode.
 // Disable the optimization for now and revisit it later.
-#if 0 // LANG_CXX11
+#if 0   // LANG_CXX11
   string Consume() && { return std::move(output_); }
 #else   // !LANG_CXX11
   const string& Get() { return output_; }
@@ -1508,7 +1517,7 @@
 TextFormat::FieldValuePrinter::FieldValuePrinter() {}
 TextFormat::FieldValuePrinter::~FieldValuePrinter() {}
 
-#if 0 // LANG_CXX11
+#if 0  // LANG_CXX11
 #define FORWARD_IMPL(fn, ...)            \
   StringBaseTextGenerator generator;     \
   delegate_.fn(__VA_ARGS__, &generator); \
@@ -1552,23 +1561,18 @@
   FORWARD_IMPL(PrintEnum, val, name);
 }
 string TextFormat::FieldValuePrinter::PrintFieldName(
-    const Message& message,
-    const Reflection* reflection,
+    const Message& message, const Reflection* reflection,
     const FieldDescriptor* field) const {
   FORWARD_IMPL(PrintFieldName, message, reflection, field);
 }
 string TextFormat::FieldValuePrinter::PrintMessageStart(
-    const Message& message,
-    int field_index,
-    int field_count,
+    const Message& message, int field_index, int field_count,
     bool single_line_mode) const {
   FORWARD_IMPL(PrintMessageStart, message, field_index, field_count,
                single_line_mode);
 }
 string TextFormat::FieldValuePrinter::PrintMessageEnd(
-    const Message& message,
-    int field_index,
-    int field_count,
+    const Message& message, int field_index, int field_count,
     bool single_line_mode) const {
   FORWARD_IMPL(PrintMessageEnd, message, field_index, field_count,
                single_line_mode);
@@ -1775,15 +1779,15 @@
 }  // namespace
 
 TextFormat::Printer::Printer()
-  : initial_indent_level_(0),
-    single_line_mode_(false),
-    use_field_number_(false),
-    use_short_repeated_primitives_(false),
-    hide_unknown_fields_(false),
-    print_message_fields_in_index_order_(false),
-    expand_any_(false),
-    truncate_string_field_longer_than_(0LL),
-    finder_(NULL) {
+    : initial_indent_level_(0),
+      single_line_mode_(false),
+      use_field_number_(false),
+      use_short_repeated_primitives_(false),
+      hide_unknown_fields_(false),
+      print_message_fields_in_index_order_(false),
+      expand_any_(false),
+      truncate_string_field_longer_than_(0LL),
+      finder_(NULL) {
   SetUseUtf8StringEscaping(false);
 }
 
@@ -1808,8 +1812,7 @@
 }
 
 bool TextFormat::Printer::RegisterFieldValuePrinter(
-    const FieldDescriptor* field,
-    const FieldValuePrinter* printer) {
+    const FieldDescriptor* field, const FieldValuePrinter* printer) {
   if (field == NULL || printer == NULL) {
     return false;
   }
@@ -1848,8 +1851,7 @@
 }
 
 bool TextFormat::Printer::PrintUnknownFieldsToString(
-    const UnknownFieldSet& unknown_fields,
-    string* output) const {
+    const UnknownFieldSet& unknown_fields, string* output) const {
   GOOGLE_DCHECK(output) << "output specified is NULL";
 
   output->clear();
@@ -1948,13 +1950,25 @@
 
 void TextFormat::Printer::Print(const Message& message,
                                 TextGenerator* generator) const {
+  const Reflection* reflection = message.GetReflection();
+  if (!reflection) {
+    // This message does not provide any way to describe its structure.
+    // Parse it again in an UnknownFieldSet, and display this instead.
+    UnknownFieldSet unknown_fields;
+    {
+      string serialized = message.SerializeAsString();
+      io::ArrayInputStream input(serialized.data(), serialized.size());
+      unknown_fields.ParseFromZeroCopyStream(&input);
+    }
+    PrintUnknownFields(unknown_fields, generator);
+    return;
+  }
   const Descriptor* descriptor = message.GetDescriptor();
   auto itr = custom_message_printers_.find(descriptor);
   if (itr != custom_message_printers_.end()) {
     itr->second->Print(message, single_line_mode_, generator);
     return;
   }
-  const Reflection* reflection = message.GetReflection();
   if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
       PrintAny(message, generator)) {
     return;
@@ -1978,11 +1992,10 @@
   }
 }
 
-void TextFormat::Printer::PrintFieldValueToString(
-    const Message& message,
-    const FieldDescriptor* field,
-    int index,
-    string* output) const {
+void TextFormat::Printer::PrintFieldValueToString(const Message& message,
+                                                  const FieldDescriptor* field,
+                                                  int index,
+                                                  string* output) const {
   GOOGLE_DCHECK(output) << "output specified is NULL";
 
   output->clear();
@@ -2001,34 +2014,34 @@
     const Reflection* reflection = a->GetReflection();
     switch (field_->cpp_type()) {
       case FieldDescriptor::CPPTYPE_BOOL: {
-          bool first = reflection->GetBool(*a, field_);
-          bool second = reflection->GetBool(*b, field_);
-          return first < second;
+        bool first = reflection->GetBool(*a, field_);
+        bool second = reflection->GetBool(*b, field_);
+        return first < second;
       }
       case FieldDescriptor::CPPTYPE_INT32: {
-          int32 first = reflection->GetInt32(*a, field_);
-          int32 second = reflection->GetInt32(*b, field_);
-          return first < second;
+        int32 first = reflection->GetInt32(*a, field_);
+        int32 second = reflection->GetInt32(*b, field_);
+        return first < second;
       }
       case FieldDescriptor::CPPTYPE_INT64: {
-          int64 first = reflection->GetInt64(*a, field_);
-          int64 second = reflection->GetInt64(*b, field_);
-          return first < second;
+        int64 first = reflection->GetInt64(*a, field_);
+        int64 second = reflection->GetInt64(*b, field_);
+        return first < second;
       }
       case FieldDescriptor::CPPTYPE_UINT32: {
-          uint32 first = reflection->GetUInt32(*a, field_);
-          uint32 second = reflection->GetUInt32(*b, field_);
-          return first < second;
+        uint32 first = reflection->GetUInt32(*a, field_);
+        uint32 second = reflection->GetUInt32(*b, field_);
+        return first < second;
       }
       case FieldDescriptor::CPPTYPE_UINT64: {
-          uint64 first = reflection->GetUInt64(*a, field_);
-          uint64 second = reflection->GetUInt64(*b, field_);
-          return first < second;
+        uint64 first = reflection->GetUInt64(*a, field_);
+        uint64 second = reflection->GetUInt64(*b, field_);
+        return first < second;
       }
       case FieldDescriptor::CPPTYPE_STRING: {
-          string first = reflection->GetString(*a, field_);
-          string second = reflection->GetString(*b, field_);
-          return first < second;
+        string first = reflection->GetString(*a, field_);
+        string second = reflection->GetString(*b, field_);
+        return first < second;
       }
       default:
         GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
@@ -2060,8 +2073,7 @@
     const FieldDescriptor* field, MessageFactory* factory,
     std::vector<const Message*>* sorted_map_field) {
   bool need_release = false;
-  const MapFieldBase& base =
-      *reflection->GetMapData(message, field);
+  const MapFieldBase& base = *reflection->GetMapData(message, field);
 
   if (base.IsRepeatedFieldValid()) {
     const RepeatedPtrField<Message>& map_field =
@@ -2171,8 +2183,7 @@
                                      const Reflection* reflection,
                                      const FieldDescriptor* field,
                                      TextGenerator* generator) const {
-  if (use_short_repeated_primitives_ &&
-      field->is_repeated() &&
+  if (use_short_repeated_primitives_ && field->is_repeated() &&
       field->cpp_type() != FieldDescriptor::CPPTYPE_STRING &&
       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
     PrintShortRepeatedField(message, reflection, field, generator);
@@ -2294,21 +2305,22 @@
         generator);                                                  \
     break
 
-    OUTPUT_FIELD( INT32,  Int32);
-    OUTPUT_FIELD( INT64,  Int64);
+    OUTPUT_FIELD(INT32, Int32);
+    OUTPUT_FIELD(INT64, Int64);
     OUTPUT_FIELD(UINT32, UInt32);
     OUTPUT_FIELD(UINT64, UInt64);
-    OUTPUT_FIELD( FLOAT,  Float);
+    OUTPUT_FIELD(FLOAT, Float);
     OUTPUT_FIELD(DOUBLE, Double);
-    OUTPUT_FIELD(  BOOL,   Bool);
+    OUTPUT_FIELD(BOOL, Bool);
 #undef OUTPUT_FIELD
 
     case FieldDescriptor::CPPTYPE_STRING: {
       string scratch;
-      const string& value = field->is_repeated()
-          ? reflection->GetRepeatedStringReference(
-              message, field, index, &scratch)
-          : reflection->GetStringReference(message, field, &scratch);
+      const string& value =
+          field->is_repeated()
+              ? reflection->GetRepeatedStringReference(message, field, index,
+                                                       &scratch)
+              : reflection->GetStringReference(message, field, &scratch);
       const string* value_to_print = &value;
       string truncated_value;
       if (truncate_string_field_longer_than_ > 0 &&
@@ -2327,9 +2339,10 @@
     }
 
     case FieldDescriptor::CPPTYPE_ENUM: {
-      int enum_value = field->is_repeated()
-          ? reflection->GetRepeatedEnumValue(message, field, index)
-          : reflection->GetEnumValue(message, field);
+      int enum_value =
+          field->is_repeated()
+              ? reflection->GetRepeatedEnumValue(message, field, index)
+              : reflection->GetEnumValue(message, field);
       const EnumValueDescriptor* enum_desc =
           field->enum_type()->FindValueByNumber(enum_value);
       if (enum_desc != NULL) {
@@ -2349,8 +2362,8 @@
 
     case FieldDescriptor::CPPTYPE_MESSAGE:
       Print(field->is_repeated()
-            ? reflection->GetRepeatedMessage(message, field, index)
-            : reflection->GetMessage(message, field),
+                ? reflection->GetRepeatedMessage(message, field, index)
+                : reflection->GetMessage(message, field),
             generator);
       break;
   }
@@ -2362,13 +2375,12 @@
 }
 
 /* static */ bool TextFormat::PrintUnknownFields(
-    const UnknownFieldSet& unknown_fields,
-    io::ZeroCopyOutputStream* output) {
+    const UnknownFieldSet& unknown_fields, io::ZeroCopyOutputStream* output) {
   return Printer().PrintUnknownFields(unknown_fields, output);
 }
 
-/* static */ bool TextFormat::PrintToString(
-    const Message& message, string* output) {
+/* static */ bool TextFormat::PrintToString(const Message& message,
+                                            string* output) {
   return Printer().PrintToString(message, output);
 }
 
@@ -2378,28 +2390,24 @@
 }
 
 /* static */ void TextFormat::PrintFieldValueToString(
-    const Message& message,
-    const FieldDescriptor* field,
-    int index,
+    const Message& message, const FieldDescriptor* field, int index,
     string* output) {
   return Printer().PrintFieldValueToString(message, field, index, output);
 }
 
 /* static */ bool TextFormat::ParseFieldValueFromString(
-    const string& input,
-    const FieldDescriptor* field,
-    Message* message) {
+    const string& input, const FieldDescriptor* field, Message* message) {
   return Parser().ParseFieldValueFromString(input, field, message);
 }
 
 // Prints an integer as hex with a fixed number of digits dependent on the
 // integer type.
-template<typename IntType>
+template <typename IntType>
 static string PaddedHex(IntType value) {
   string result;
   result.reserve(sizeof(value) * 2);
   for (int i = sizeof(value) * 2 - 1; i >= 0; i--) {
-    result.push_back(int_to_hex_digit(value >> (i*4) & 0x0F));
+    result.push_back(int_to_hex_digit(value >> (i * 4) & 0x0F));
   }
   return result;
 }
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index d185bfd..3026def 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -59,7 +59,7 @@
 namespace protobuf {
 
 namespace io {
-  class ErrorCollector;      // tokenizer.h
+class ErrorCollector;  // tokenizer.h
 }
 
 // This class implements protocol buffer text format.  Printing and parsing
@@ -94,8 +94,7 @@
   // be supplied. Note that this method will print the default value for a
   // field if it is not set.
   static void PrintFieldValueToString(const Message& message,
-                                      const FieldDescriptor* field,
-                                      int index,
+                                      const FieldDescriptor* field, int index,
                                       std::string* output);
 
   class PROTOBUF_EXPORT BaseTextGenerator {
@@ -174,12 +173,10 @@
     virtual std::string PrintFieldName(const Message& message,
                                   const Reflection* reflection,
                                   const FieldDescriptor* field) const;
-    virtual std::string PrintMessageStart(const Message& message,
-                                     int field_index,
+    virtual std::string PrintMessageStart(const Message& message, int field_index,
                                      int field_count,
                                      bool single_line_mode) const;
-    virtual std::string PrintMessageEnd(const Message& message,
-                                   int field_index,
+    virtual std::string PrintMessageEnd(const Message& message, int field_index,
                                    int field_count,
                                    bool single_line_mode) const;
 
@@ -208,9 +205,8 @@
     // Try to find an extension of *message by fully-qualified field
     // name.  Returns NULL if no extension is known for this name or number.
     // The base implementation uses the extensions already known by the message.
-    virtual const FieldDescriptor* FindExtension(
-        Message* message,
-        const std::string& name) const;
+    virtual const FieldDescriptor* FindExtension(Message* message,
+                                                 const std::string& name) const;
 
     // Find the message type for an Any proto.
     // Returns NULL if no message is known for this name.
@@ -220,6 +216,12 @@
     virtual const Descriptor* FindAnyType(const Message& message,
                                           const std::string& prefix,
                                           const std::string& name) const;
+
+    // Find the message factory for the given extension field. This can be used
+    // to generalize the Parser to add extension fields to a message in the same
+    // way as the "input" message for the Parser.
+    virtual MessageFactory* FindExtensionFactory(
+        const FieldDescriptor* field) const;
   };
 
   // Class for those users which require more fine-grained control over how
@@ -241,8 +243,7 @@
                                     std::string* output) const;
     // Like TextFormat::PrintFieldValueToString
     void PrintFieldValueToString(const Message& message,
-                                 const FieldDescriptor* field,
-                                 int index,
+                                 const FieldDescriptor* field, int index,
                                  std::string* output) const;
 
     // Adjust the initial indent level of all output.  Each indent level is
@@ -257,9 +258,7 @@
       single_line_mode_ = single_line_mode;
     }
 
-    bool IsInSingleLineMode() const {
-      return single_line_mode_;
-    }
+    bool IsInSingleLineMode() const { return single_line_mode_; }
 
     // If use_field_number is true, uses field number instead of field name.
     void SetUseFieldNumber(bool use_field_number) {
@@ -293,9 +292,7 @@
     // is useful to be able to print the message without unknown fields (e.g.
     // for the python protobuf version to maintain consistency between its pure
     // python and c++ implementations).
-    void SetHideUnknownFields(bool hide) {
-      hide_unknown_fields_ = hide;
-    }
+    void SetHideUnknownFields(bool hide) { hide_unknown_fields_ = hide; }
 
     // If print_message_fields_in_index_order is true, fields of a proto message
     // will be printed using the order defined in source code instead of the
@@ -315,9 +312,7 @@
     // If expand==false, print Any using the default printer. The output will
     // look like
     //    type_url: "<type_url>"  value: "serialized_content"
-    void SetExpandAny(bool expand) {
-      expand_any_ = expand;
-    }
+    void SetExpandAny(bool expand) { expand_any_ = expand; }
 
     // Set how parser finds message for Any payloads.
     void SetFinder(const Finder* finder) { finder_ = finder; }
@@ -491,13 +486,13 @@
     ParseInfoTree* CreateNested(const FieldDescriptor* field);
 
     // Defines the map from the index-th field descriptor to its parse location.
-    typedef std::map<const FieldDescriptor*,
-                     std::vector<ParseLocation> > LocationMap;
+    typedef std::map<const FieldDescriptor*, std::vector<ParseLocation> >
+        LocationMap;
 
     // Defines the map from the index-th field descriptor to the nested parse
     // info tree.
-    typedef std::map<const FieldDescriptor*,
-                     std::vector<ParseInfoTree*> > NestedMap;
+    typedef std::map<const FieldDescriptor*, std::vector<ParseInfoTree*> >
+        NestedMap;
 
     LocationMap locations_;
     NestedMap nested_;
@@ -533,15 +528,11 @@
 
     // Sets where location information about the parse will be written. If NULL
     // (the default), then no location will be written.
-    void WriteLocationsTo(ParseInfoTree* tree) {
-      parse_info_tree_ = tree;
-    }
+    void WriteLocationsTo(ParseInfoTree* tree) { parse_info_tree_ = tree; }
 
     // Normally parsing fails if, after parsing, output->IsInitialized()
     // returns false.  Call AllowPartialMessage(true) to skip this check.
-    void AllowPartialMessage(bool allow) {
-      allow_partial_ = allow;
-    }
+    void AllowPartialMessage(bool allow) { allow_partial_ = allow; }
 
     // Allow field names to be matched case-insensitively.
     // This is not advisable if there are fields that only differ in case, or
@@ -559,14 +550,14 @@
     // When an unknown extension is met, parsing will fail if this option is set
     // to false (the default). If true, unknown extensions will be ignored and
     // a warning message will be generated.
-    void AllowUnknownExtension(bool allow) {
-      allow_unknown_extension_ = allow;
-    }
+    void AllowUnknownExtension(bool allow) { allow_unknown_extension_ = allow; }
 
 
-    void AllowFieldNumber(bool allow) {
-      allow_field_number_ = allow;
-    }
+    void AllowFieldNumber(bool allow) { allow_field_number_ = allow; }
+
+    // Sets maximum recursion depth which parser can use. This is effectively
+    // the maximum allowed nesting of proto messages.
+    void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
 
    private:
     // Forward declaration of an internal class used to parse text
@@ -575,8 +566,7 @@
 
     // Like TextFormat::Merge().  The provided implementation is used
     // to do the parsing.
-    bool MergeUsingImpl(io::ZeroCopyInputStream* input,
-                        Message* output,
+    bool MergeUsingImpl(io::ZeroCopyInputStream* input, Message* output,
                         ParserImpl* parser_impl);
 
     io::ErrorCollector* error_collector_;
@@ -590,6 +580,7 @@
     bool allow_field_number_;
     bool allow_relaxed_whitespace_;
     bool allow_singular_overwrites_;
+    int recursion_limit_;
   };
 
 
@@ -613,7 +604,6 @@
   info_tree->RecordLocation(field, location);
 }
 
-
 inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
     ParseInfoTree* info_tree, const FieldDescriptor* field) {
   return info_tree->CreateNested(field);
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 89bb164..023827b 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -1313,24 +1313,24 @@
 
   void ExpectMessage(const string& input, const string& message, int line,
                      int col, Message* proto, bool expected_result) {
-    TextFormat::Parser parser;
     MockErrorCollector error_collector;
-    parser.RecordErrorsTo(&error_collector);
-    EXPECT_EQ(expected_result, parser.ParseFromString(input, proto))
+    parser_.RecordErrorsTo(&error_collector);
+    EXPECT_EQ(expected_result, parser_.ParseFromString(input, proto))
         << input << " -> " << proto->DebugString();
     EXPECT_EQ(
         StrCat(line) + ":" + StrCat(col) + ": " + message + "\n",
         error_collector.text_);
+    parser_.RecordErrorsTo(nullptr);
   }
 
   void ExpectSuccessAndTree(const string& input, Message* proto,
                             TextFormat::ParseInfoTree* info_tree) {
-    TextFormat::Parser parser;
     MockErrorCollector error_collector;
-    parser.RecordErrorsTo(&error_collector);
-    parser.WriteLocationsTo(info_tree);
-
-    EXPECT_TRUE(parser.ParseFromString(input, proto));
+    parser_.RecordErrorsTo(&error_collector);
+    parser_.WriteLocationsTo(info_tree);
+    EXPECT_TRUE(parser_.ParseFromString(input, proto));
+    parser_.WriteLocationsTo(nullptr);
+    parser_.RecordErrorsTo(nullptr);
   }
 
   void ExpectLocation(TextFormat::ParseInfoTree* tree,
@@ -1361,6 +1361,8 @@
       AddError(line, column, "WARNING:" + message);
     }
   };
+
+  TextFormat::Parser parser_;
 };
 
 TEST_F(TextFormatParserTest, ParseInfoTreeBuilding) {
@@ -1810,18 +1812,20 @@
                 "\"deprecated_int32\"", 1, 21, &message, true);
 }
 
-TEST_F(TextFormatParserTest, DeepRecursion) {
+TEST_F(TextFormatParserTest, SetRecursionLimit) {
   const char* format = "child: { $0 }";
   std::string input;
-  for (int i = 0; i < 100; ++i)
-    input = strings::Substitute(format, input);
+  for (int i = 0; i < 100; ++i) input = strings::Substitute(format, input);
 
   unittest::NestedTestAllTypes message;
   ExpectSuccessAndTree(input, &message, nullptr);
 
   input = strings::Substitute(format, input);
-  ExpectMessage(input,
-                "Message is too deep", 1, 908, &message, false);
+  parser_.SetRecursionLimit(100);
+  ExpectMessage(input, "Message is too deep", 1, 908, &message, false);
+
+  parser_.SetRecursionLimit(101);
+  ExpectSuccessAndTree(input, &message, nullptr);
 }
 
 class TextFormatMessageSetTest : public testing::Test {
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 6cc150b..7232af8 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -42,9 +42,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Timestamp_google_2fprotobuf_2ftimestamp_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto[1];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -63,7 +63,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Timestamp_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ftimestamp_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ftimestamp_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2ftimestamp_2eproto, "google/protobuf/timestamp.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2ftimestamp_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
@@ -77,7 +77,7 @@
   "obuf/ptypes/timestamp\370\001\001\242\002\003GPB\252\002\036Google."
   "Protobuf.WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
   false, InitDefaults_google_2fprotobuf_2ftimestamp_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
   "google/protobuf/timestamp.proto", &assign_descriptors_table_google_2fprotobuf_2ftimestamp_2eproto, 231,
@@ -173,43 +173,36 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Timestamp::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Timestamp*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Timestamp::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // int64 seconds = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_seconds(::google::protobuf::internal::ReadVarint(&ptr));
+        set_seconds(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // int32 nanos = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_nanos(::google::protobuf::internal::ReadVarint(&ptr));
+        set_nanos(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index f49ca7a..5cf7d4a 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2ftimestamp_2eproto PROTOBUF_EXPORT
@@ -131,8 +138,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -144,10 +150,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Timestamp* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Timestamp";
+  }
   protected:
   explicit Timestamp(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index bc31823..26deb9d 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -132,9 +132,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_Option_google_2fprotobuf_2ftype_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
-const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2ftype_2eproto[5];
+static const ::google::protobuf::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[3];
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2ftype_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -205,7 +205,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_Option_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ftype_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2ftype_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2ftype_2eproto, "google/protobuf/type.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2ftype_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2ftype_2eproto, 5, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
@@ -253,7 +253,7 @@
   "oto/protobuf/ptype;ptype\370\001\001\242\002\003GPB\252\002\036Goog"
   "le.Protobuf.WellKnownTypesb\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
   false, InitDefaults_google_2fprotobuf_2ftype_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
   "google/protobuf/type.proto", &assign_descriptors_table_google_2fprotobuf_2ftype_2eproto, 1594,
@@ -303,30 +303,30 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const Field_Kind Field::TYPE_UNKNOWN;
-const Field_Kind Field::TYPE_DOUBLE;
-const Field_Kind Field::TYPE_FLOAT;
-const Field_Kind Field::TYPE_INT64;
-const Field_Kind Field::TYPE_UINT64;
-const Field_Kind Field::TYPE_INT32;
-const Field_Kind Field::TYPE_FIXED64;
-const Field_Kind Field::TYPE_FIXED32;
-const Field_Kind Field::TYPE_BOOL;
-const Field_Kind Field::TYPE_STRING;
-const Field_Kind Field::TYPE_GROUP;
-const Field_Kind Field::TYPE_MESSAGE;
-const Field_Kind Field::TYPE_BYTES;
-const Field_Kind Field::TYPE_UINT32;
-const Field_Kind Field::TYPE_ENUM;
-const Field_Kind Field::TYPE_SFIXED32;
-const Field_Kind Field::TYPE_SFIXED64;
-const Field_Kind Field::TYPE_SINT32;
-const Field_Kind Field::TYPE_SINT64;
-const Field_Kind Field::Kind_MIN;
-const Field_Kind Field::Kind_MAX;
-const int Field::Kind_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr Field_Kind Field::TYPE_UNKNOWN;
+constexpr Field_Kind Field::TYPE_DOUBLE;
+constexpr Field_Kind Field::TYPE_FLOAT;
+constexpr Field_Kind Field::TYPE_INT64;
+constexpr Field_Kind Field::TYPE_UINT64;
+constexpr Field_Kind Field::TYPE_INT32;
+constexpr Field_Kind Field::TYPE_FIXED64;
+constexpr Field_Kind Field::TYPE_FIXED32;
+constexpr Field_Kind Field::TYPE_BOOL;
+constexpr Field_Kind Field::TYPE_STRING;
+constexpr Field_Kind Field::TYPE_GROUP;
+constexpr Field_Kind Field::TYPE_MESSAGE;
+constexpr Field_Kind Field::TYPE_BYTES;
+constexpr Field_Kind Field::TYPE_UINT32;
+constexpr Field_Kind Field::TYPE_ENUM;
+constexpr Field_Kind Field::TYPE_SFIXED32;
+constexpr Field_Kind Field::TYPE_SFIXED64;
+constexpr Field_Kind Field::TYPE_SINT32;
+constexpr Field_Kind Field::TYPE_SINT64;
+constexpr Field_Kind Field::Kind_MIN;
+constexpr Field_Kind Field::Kind_MAX;
+constexpr int Field::Kind_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2ftype_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[1];
@@ -343,15 +343,15 @@
   }
 }
 
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-const Field_Cardinality Field::CARDINALITY_UNKNOWN;
-const Field_Cardinality Field::CARDINALITY_OPTIONAL;
-const Field_Cardinality Field::CARDINALITY_REQUIRED;
-const Field_Cardinality Field::CARDINALITY_REPEATED;
-const Field_Cardinality Field::Cardinality_MIN;
-const Field_Cardinality Field::Cardinality_MAX;
-const int Field::Cardinality_ARRAYSIZE;
-#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
+constexpr Field_Cardinality Field::CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field::CARDINALITY_OPTIONAL;
+constexpr Field_Cardinality Field::CARDINALITY_REQUIRED;
+constexpr Field_Cardinality Field::CARDINALITY_REPEATED;
+constexpr Field_Cardinality Field::Cardinality_MIN;
+constexpr Field_Cardinality Field::Cardinality_MAX;
+constexpr int Field::Cardinality_ARRAYSIZE;
+#endif  // (__cplusplus < 201703) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
 const ::google::protobuf::EnumDescriptor* Syntax_descriptor() {
   ::google::protobuf::internal::AssignDescriptors(&assign_descriptors_table_google_2fprotobuf_2ftype_2eproto);
   return file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto[2];
@@ -500,128 +500,78 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Type::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Type*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Type::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Type.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Type.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.Field fields = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_fields(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Field::_InternalParse;
-          object = msg->add_fields();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // repeated string oneofs = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(add_oneofs(), ptr, ctx, "google.protobuf.Type.oneofs");
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          ctx->extra_parse_data().SetFieldName("google.protobuf.Type.oneofs");
-          object = msg->add_oneofs();
-          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-            goto string_till_end;
-          }
-          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-          ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-          ptr += size;
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.Option options = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 34 && (ptr += 1));
         break;
       }
       // .google.protobuf.SourceContext source_context = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 42) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_source_context(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::SourceContext::_InternalParse;
-        object = msg->mutable_source_context();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // .google.protobuf.Syntax syntax = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 48) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_syntax(static_cast<::google::protobuf::Syntax>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_syntax(static_cast<::google::protobuf::Syntax>(val));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Type::MergePartialFromCodedStream(
@@ -1142,84 +1092,60 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Field::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Field*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Field::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // .google.protobuf.Field.Kind kind = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_kind(static_cast<::google::protobuf::Field_Kind>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_kind(static_cast<::google::protobuf::Field_Kind>(val));
         break;
       }
       // .google.protobuf.Field.Cardinality cardinality = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_cardinality(static_cast<::google::protobuf::Field_Cardinality>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_cardinality(static_cast<::google::protobuf::Field_Cardinality>(val));
         break;
       }
       // int32 number = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 24) goto handle_unusual;
-        msg->set_number(::google::protobuf::internal::ReadVarint(&ptr));
+        set_number(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // string name = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Field.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Field.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // string type_url = 6;
       case 6: {
         if (static_cast<::google::protobuf::uint8>(tag) != 50) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_type_url(), ptr, ctx, "google.protobuf.Field.type_url");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Field.type_url");
-        object = msg->mutable_type_url();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // int32 oneof_index = 7;
       case 7: {
         if (static_cast<::google::protobuf::uint8>(tag) != 56) goto handle_unusual;
-        msg->set_oneof_index(::google::protobuf::internal::ReadVarint(&ptr));
+        set_oneof_index(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       // bool packed = 8;
       case 8: {
         if (static_cast<::google::protobuf::uint8>(tag) != 64) goto handle_unusual;
-        msg->set_packed(::google::protobuf::internal::ReadVarint(&ptr));
+        set_packed(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -1227,72 +1153,40 @@
       case 9: {
         if (static_cast<::google::protobuf::uint8>(tag) != 74) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 74 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 74 && (ptr += 1));
         break;
       }
       // string json_name = 10;
       case 10: {
         if (static_cast<::google::protobuf::uint8>(tag) != 82) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_json_name(), ptr, ctx, "google.protobuf.Field.json_name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Field.json_name");
-        object = msg->mutable_json_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // string default_value = 11;
       case 11: {
         if (static_cast<::google::protobuf::uint8>(tag) != 90) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_default_value(), ptr, ctx, "google.protobuf.Field.default_value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Field.default_value");
-        object = msg->mutable_default_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Field::MergePartialFromCodedStream(
@@ -1977,109 +1871,68 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Enum::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Enum*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Enum::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Enum.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Enum.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // repeated .google.protobuf.EnumValue enumvalue = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_enumvalue(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::EnumValue::_InternalParse;
-          object = msg->add_enumvalue();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 18 && (ptr += 1));
         break;
       }
       // repeated .google.protobuf.Option options = 3;
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       // .google.protobuf.SourceContext source_context = 4;
       case 4: {
         if (static_cast<::google::protobuf::uint8>(tag) != 34) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_source_context(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::SourceContext::_InternalParse;
-        object = msg->mutable_source_context();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       // .google.protobuf.Syntax syntax = 5;
       case 5: {
         if (static_cast<::google::protobuf::uint8>(tag) != 40) goto handle_unusual;
         ::google::protobuf::uint64 val = ::google::protobuf::internal::ReadVarint(&ptr);
-        msg->set_syntax(static_cast<::google::protobuf::Syntax>(val));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+        set_syntax(static_cast<::google::protobuf::Syntax>(val));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Enum::MergePartialFromCodedStream(
@@ -2517,38 +2370,23 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* EnumValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<EnumValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* EnumValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.EnumValue.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValue.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // int32 number = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 16) goto handle_unusual;
-        msg->set_number(::google::protobuf::internal::ReadVarint(&ptr));
+        set_number(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
@@ -2556,40 +2394,26 @@
       case 3: {
         if (static_cast<::google::protobuf::uint8>(tag) != 26) goto handle_unusual;
         do {
-          ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+          ptr = ctx->ParseMessage(add_options(), ptr);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-          parser_till_end = ::google::protobuf::Option::_InternalParse;
-          object = msg->add_options();
-          if (size > end - ptr) goto len_delim_till_end;
-          ptr += size;
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-              {parser_till_end, object}, ptr - size, ptr));
-          if (ptr >= end) break;
-        } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
+          if (ctx->Done(&ptr)) return ptr;
+        } while ((::google::protobuf::internal::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool EnumValue::MergePartialFromCodedStream(
@@ -2979,69 +2803,40 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Option::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Option*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Option::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string name = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_name(), ptr, ctx, "google.protobuf.Option.name");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.Option.name");
-        object = msg->mutable_name();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       // .google.protobuf.Any value = 2;
       case 2: {
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ctx->ParseMessage(mutable_value(), ptr);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::Any::_InternalParse;
-        object = msg->mutable_value();
-        if (size > end - ptr) goto len_delim_till_end;
-        ptr += size;
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(
-            {parser_till_end, object}, ptr - size, ptr));
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool Option::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index ce345ba..73828d8 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -32,6 +32,13 @@
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/generated_enum_reflection.h>
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 #include <google/protobuf/any.pb.h>
 #include <google/protobuf/source_context.pb.h>
 // @@protoc_insertion_point(includes)
@@ -102,9 +109,9 @@
   Field_Kind_Field_Kind_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::google::protobuf::int32>::max()
 };
 PROTOBUF_EXPORT bool Field_Kind_IsValid(int value);
-const Field_Kind Field_Kind_Kind_MIN = Field_Kind_TYPE_UNKNOWN;
-const Field_Kind Field_Kind_Kind_MAX = Field_Kind_TYPE_SINT64;
-const int Field_Kind_Kind_ARRAYSIZE = Field_Kind_Kind_MAX + 1;
+constexpr Field_Kind Field_Kind_Kind_MIN = Field_Kind_TYPE_UNKNOWN;
+constexpr Field_Kind Field_Kind_Kind_MAX = Field_Kind_TYPE_SINT64;
+constexpr int Field_Kind_Kind_ARRAYSIZE = Field_Kind_Kind_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Field_Kind_descriptor();
 inline const ::std::string& Field_Kind_Name(Field_Kind value) {
@@ -125,9 +132,9 @@
   Field_Cardinality_Field_Cardinality_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::google::protobuf::int32>::max()
 };
 PROTOBUF_EXPORT bool Field_Cardinality_IsValid(int value);
-const Field_Cardinality Field_Cardinality_Cardinality_MIN = Field_Cardinality_CARDINALITY_UNKNOWN;
-const Field_Cardinality Field_Cardinality_Cardinality_MAX = Field_Cardinality_CARDINALITY_REPEATED;
-const int Field_Cardinality_Cardinality_ARRAYSIZE = Field_Cardinality_Cardinality_MAX + 1;
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MIN = Field_Cardinality_CARDINALITY_UNKNOWN;
+constexpr Field_Cardinality Field_Cardinality_Cardinality_MAX = Field_Cardinality_CARDINALITY_REPEATED;
+constexpr int Field_Cardinality_Cardinality_ARRAYSIZE = Field_Cardinality_Cardinality_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Field_Cardinality_descriptor();
 inline const ::std::string& Field_Cardinality_Name(Field_Cardinality value) {
@@ -146,9 +153,9 @@
   Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<::google::protobuf::int32>::max()
 };
 PROTOBUF_EXPORT bool Syntax_IsValid(int value);
-const Syntax Syntax_MIN = SYNTAX_PROTO2;
-const Syntax Syntax_MAX = SYNTAX_PROTO3;
-const int Syntax_ARRAYSIZE = Syntax_MAX + 1;
+constexpr Syntax Syntax_MIN = SYNTAX_PROTO2;
+constexpr Syntax Syntax_MAX = SYNTAX_PROTO3;
+constexpr int Syntax_ARRAYSIZE = Syntax_MAX + 1;
 
 PROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Syntax_descriptor();
 inline const ::std::string& Syntax_Name(Syntax value) {
@@ -232,8 +239,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -245,10 +251,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Type* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Type";
+  }
   protected:
   explicit Type(::google::protobuf::Arena* arena);
   private:
@@ -445,8 +455,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -458,10 +467,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Field* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Field";
+  }
   protected:
   explicit Field(::google::protobuf::Arena* arena);
   private:
@@ -481,52 +494,52 @@
   // nested types ----------------------------------------------------
 
   typedef Field_Kind Kind;
-  static const Kind TYPE_UNKNOWN =
+  static constexpr Kind TYPE_UNKNOWN =
     Field_Kind_TYPE_UNKNOWN;
-  static const Kind TYPE_DOUBLE =
+  static constexpr Kind TYPE_DOUBLE =
     Field_Kind_TYPE_DOUBLE;
-  static const Kind TYPE_FLOAT =
+  static constexpr Kind TYPE_FLOAT =
     Field_Kind_TYPE_FLOAT;
-  static const Kind TYPE_INT64 =
+  static constexpr Kind TYPE_INT64 =
     Field_Kind_TYPE_INT64;
-  static const Kind TYPE_UINT64 =
+  static constexpr Kind TYPE_UINT64 =
     Field_Kind_TYPE_UINT64;
-  static const Kind TYPE_INT32 =
+  static constexpr Kind TYPE_INT32 =
     Field_Kind_TYPE_INT32;
-  static const Kind TYPE_FIXED64 =
+  static constexpr Kind TYPE_FIXED64 =
     Field_Kind_TYPE_FIXED64;
-  static const Kind TYPE_FIXED32 =
+  static constexpr Kind TYPE_FIXED32 =
     Field_Kind_TYPE_FIXED32;
-  static const Kind TYPE_BOOL =
+  static constexpr Kind TYPE_BOOL =
     Field_Kind_TYPE_BOOL;
-  static const Kind TYPE_STRING =
+  static constexpr Kind TYPE_STRING =
     Field_Kind_TYPE_STRING;
-  static const Kind TYPE_GROUP =
+  static constexpr Kind TYPE_GROUP =
     Field_Kind_TYPE_GROUP;
-  static const Kind TYPE_MESSAGE =
+  static constexpr Kind TYPE_MESSAGE =
     Field_Kind_TYPE_MESSAGE;
-  static const Kind TYPE_BYTES =
+  static constexpr Kind TYPE_BYTES =
     Field_Kind_TYPE_BYTES;
-  static const Kind TYPE_UINT32 =
+  static constexpr Kind TYPE_UINT32 =
     Field_Kind_TYPE_UINT32;
-  static const Kind TYPE_ENUM =
+  static constexpr Kind TYPE_ENUM =
     Field_Kind_TYPE_ENUM;
-  static const Kind TYPE_SFIXED32 =
+  static constexpr Kind TYPE_SFIXED32 =
     Field_Kind_TYPE_SFIXED32;
-  static const Kind TYPE_SFIXED64 =
+  static constexpr Kind TYPE_SFIXED64 =
     Field_Kind_TYPE_SFIXED64;
-  static const Kind TYPE_SINT32 =
+  static constexpr Kind TYPE_SINT32 =
     Field_Kind_TYPE_SINT32;
-  static const Kind TYPE_SINT64 =
+  static constexpr Kind TYPE_SINT64 =
     Field_Kind_TYPE_SINT64;
   static inline bool Kind_IsValid(int value) {
     return Field_Kind_IsValid(value);
   }
-  static const Kind Kind_MIN =
+  static constexpr Kind Kind_MIN =
     Field_Kind_Kind_MIN;
-  static const Kind Kind_MAX =
+  static constexpr Kind Kind_MAX =
     Field_Kind_Kind_MAX;
-  static const int Kind_ARRAYSIZE =
+  static constexpr int Kind_ARRAYSIZE =
     Field_Kind_Kind_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   Kind_descriptor() {
@@ -541,22 +554,22 @@
   }
 
   typedef Field_Cardinality Cardinality;
-  static const Cardinality CARDINALITY_UNKNOWN =
+  static constexpr Cardinality CARDINALITY_UNKNOWN =
     Field_Cardinality_CARDINALITY_UNKNOWN;
-  static const Cardinality CARDINALITY_OPTIONAL =
+  static constexpr Cardinality CARDINALITY_OPTIONAL =
     Field_Cardinality_CARDINALITY_OPTIONAL;
-  static const Cardinality CARDINALITY_REQUIRED =
+  static constexpr Cardinality CARDINALITY_REQUIRED =
     Field_Cardinality_CARDINALITY_REQUIRED;
-  static const Cardinality CARDINALITY_REPEATED =
+  static constexpr Cardinality CARDINALITY_REPEATED =
     Field_Cardinality_CARDINALITY_REPEATED;
   static inline bool Cardinality_IsValid(int value) {
     return Field_Cardinality_IsValid(value);
   }
-  static const Cardinality Cardinality_MIN =
+  static constexpr Cardinality Cardinality_MIN =
     Field_Cardinality_Cardinality_MIN;
-  static const Cardinality Cardinality_MAX =
+  static constexpr Cardinality Cardinality_MAX =
     Field_Cardinality_Cardinality_MAX;
-  static const int Cardinality_ARRAYSIZE =
+  static constexpr int Cardinality_ARRAYSIZE =
     Field_Cardinality_Cardinality_ARRAYSIZE;
   static inline const ::google::protobuf::EnumDescriptor*
   Cardinality_descriptor() {
@@ -799,8 +812,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -812,10 +824,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Enum* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Enum";
+  }
   protected:
   explicit Enum(::google::protobuf::Arena* arena);
   private:
@@ -989,8 +1005,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1002,10 +1017,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(EnumValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.EnumValue";
+  }
   protected:
   explicit EnumValue(::google::protobuf::Arena* arena);
   private:
@@ -1153,8 +1172,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1166,10 +1184,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Option* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Option";
+  }
   protected:
   explicit Option(::google::protobuf::Arena* arena);
   private:
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 4af2b05..4870382 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -1002,3 +1002,106 @@
   optional int32 test_extension_inside_table_extension = 5;
 }
 
+enum VeryLargeEnum {
+  ENUM_LABEL_DEFAULT = 0;
+  ENUM_LABEL_1 = 1;
+  ENUM_LABEL_2 = 2;
+  ENUM_LABEL_3 = 3;
+  ENUM_LABEL_4 = 4;
+  ENUM_LABEL_5 = 5;
+  ENUM_LABEL_6 = 6;
+  ENUM_LABEL_7 = 7;
+  ENUM_LABEL_8 = 8;
+  ENUM_LABEL_9 = 9;
+  ENUM_LABEL_10 = 10;
+  ENUM_LABEL_11 = 11;
+  ENUM_LABEL_12 = 12;
+  ENUM_LABEL_13 = 13;
+  ENUM_LABEL_14 = 14;
+  ENUM_LABEL_15 = 15;
+  ENUM_LABEL_16 = 16;
+  ENUM_LABEL_17 = 17;
+  ENUM_LABEL_18 = 18;
+  ENUM_LABEL_19 = 19;
+  ENUM_LABEL_20 = 20;
+  ENUM_LABEL_21 = 21;
+  ENUM_LABEL_22 = 22;
+  ENUM_LABEL_23 = 23;
+  ENUM_LABEL_24 = 24;
+  ENUM_LABEL_25 = 25;
+  ENUM_LABEL_26 = 26;
+  ENUM_LABEL_27 = 27;
+  ENUM_LABEL_28 = 28;
+  ENUM_LABEL_29 = 29;
+  ENUM_LABEL_30 = 30;
+  ENUM_LABEL_31 = 31;
+  ENUM_LABEL_32 = 32;
+  ENUM_LABEL_33 = 33;
+  ENUM_LABEL_34 = 34;
+  ENUM_LABEL_35 = 35;
+  ENUM_LABEL_36 = 36;
+  ENUM_LABEL_37 = 37;
+  ENUM_LABEL_38 = 38;
+  ENUM_LABEL_39 = 39;
+  ENUM_LABEL_40 = 40;
+  ENUM_LABEL_41 = 41;
+  ENUM_LABEL_42 = 42;
+  ENUM_LABEL_43 = 43;
+  ENUM_LABEL_44 = 44;
+  ENUM_LABEL_45 = 45;
+  ENUM_LABEL_46 = 46;
+  ENUM_LABEL_47 = 47;
+  ENUM_LABEL_48 = 48;
+  ENUM_LABEL_49 = 49;
+  ENUM_LABEL_50 = 50;
+  ENUM_LABEL_51 = 51;
+  ENUM_LABEL_52 = 52;
+  ENUM_LABEL_53 = 53;
+  ENUM_LABEL_54 = 54;
+  ENUM_LABEL_55 = 55;
+  ENUM_LABEL_56 = 56;
+  ENUM_LABEL_57 = 57;
+  ENUM_LABEL_58 = 58;
+  ENUM_LABEL_59 = 59;
+  ENUM_LABEL_60 = 60;
+  ENUM_LABEL_61 = 61;
+  ENUM_LABEL_62 = 62;
+  ENUM_LABEL_63 = 63;
+  ENUM_LABEL_64 = 64;
+  ENUM_LABEL_65 = 65;
+  ENUM_LABEL_66 = 66;
+  ENUM_LABEL_67 = 67;
+  ENUM_LABEL_68 = 68;
+  ENUM_LABEL_69 = 69;
+  ENUM_LABEL_70 = 70;
+  ENUM_LABEL_71 = 71;
+  ENUM_LABEL_72 = 72;
+  ENUM_LABEL_73 = 73;
+  ENUM_LABEL_74 = 74;
+  ENUM_LABEL_75 = 75;
+  ENUM_LABEL_76 = 76;
+  ENUM_LABEL_77 = 77;
+  ENUM_LABEL_78 = 78;
+  ENUM_LABEL_79 = 79;
+  ENUM_LABEL_80 = 80;
+  ENUM_LABEL_81 = 81;
+  ENUM_LABEL_82 = 82;
+  ENUM_LABEL_83 = 83;
+  ENUM_LABEL_84 = 84;
+  ENUM_LABEL_85 = 85;
+  ENUM_LABEL_86 = 86;
+  ENUM_LABEL_87 = 87;
+  ENUM_LABEL_88 = 88;
+  ENUM_LABEL_89 = 89;
+  ENUM_LABEL_90 = 90;
+  ENUM_LABEL_91 = 91;
+  ENUM_LABEL_92 = 92;
+  ENUM_LABEL_93 = 93;
+  ENUM_LABEL_94 = 94;
+  ENUM_LABEL_95 = 95;
+  ENUM_LABEL_96 = 96;
+  ENUM_LABEL_97 = 97;
+  ENUM_LABEL_98 = 98;
+  ENUM_LABEL_99 = 99;
+  ENUM_LABEL_100 = 100;
+};
diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto
index 49d9ada..4e7a8c5 100644
--- a/src/google/protobuf/unittest_mset.proto
+++ b/src/google/protobuf/unittest_mset.proto
@@ -53,6 +53,8 @@
     optional TestMessageSetExtension1 message_set_extension = 1545008;
   }
   optional int32 i = 15;
+  optional proto2_wireformat_unittest.TestMessageSet recursive = 16;
+  optional string test_aliasing = 17 [ctype = STRING_PIECE];
 }
 
 message TestMessageSetExtension2 {
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index f0f9ee2..087b6d6 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -36,6 +36,7 @@
 
 #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>
@@ -112,9 +113,9 @@
     const UnknownField& field = (fields_)[i];
     switch (field.type()) {
       case UnknownField::TYPE_LENGTH_DELIMITED:
-        total_size += sizeof(*field.data_.length_delimited_.string_value_) +
+        total_size += sizeof(*field.data_.length_delimited_.string_value) +
                       internal::StringSpaceUsedExcludingSelfLong(
-                          *field.data_.length_delimited_.string_value_);
+                          *field.data_.length_delimited_.string_value);
         break;
       case UnknownField::TYPE_GROUP:
         total_size += field.data_.group_->SpaceUsedLong();
@@ -158,9 +159,9 @@
   UnknownField field;
   field.number_ = number;
   field.SetType(UnknownField::TYPE_LENGTH_DELIMITED);
-  field.data_.length_delimited_.string_value_ = new string;
+  field.data_.length_delimited_.string_value = new string;
   fields_.push_back(field);
-  return field.data_.length_delimited_.string_value_;
+  return field.data_.length_delimited_.string_value;
 }
 
 
@@ -239,7 +240,7 @@
 void UnknownField::Delete() {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
-      delete data_.length_delimited_.string_value_;
+      delete data_.length_delimited_.string_value;
       break;
     case UnknownField::TYPE_GROUP:
       delete data_.group_;
@@ -252,8 +253,8 @@
 void UnknownField::DeepCopy(const UnknownField& other) {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
-      data_.length_delimited_.string_value_ = new string(
-          *data_.length_delimited_.string_value_);
+      data_.length_delimited_.string_value =
+          new string(*data_.length_delimited_.string_value);
       break;
     case UnknownField::TYPE_GROUP: {
       UnknownFieldSet* group = new UnknownFieldSet();
@@ -270,14 +271,14 @@
 void UnknownField::SerializeLengthDelimitedNoTag(
     io::CodedOutputStream* output) const {
   GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
-  const string& data = *data_.length_delimited_.string_value_;
+  const string& data = *data_.length_delimited_.string_value;
   output->WriteVarint32(data.size());
   output->WriteRawMaybeAliased(data.data(), data.size());
 }
 
 uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
   GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
-  const string& data = *data_.length_delimited_.string_value_;
+  const string& data = *data_.length_delimited_.string_value;
   target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
   target = io::CodedOutputStream::WriteStringToArray(data, target);
   return target;
@@ -285,34 +286,50 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 namespace internal {
-
-const char* PackedValidEnumParser(const char* begin, const char* end,
-                                  void* object, ParseContext* ctx) {
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
+                             bool (*is_valid)(int), UnknownFieldSet* unknown,
+                             int field_num) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(old >= 0);
   auto repeated_field = static_cast<RepeatedField<int>*>(object);
-  auto ptr = begin;
-  while (ptr < end) {
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
     uint64 varint;
-    ptr = io::Parse64(ptr, &varint);
+    ptr = ParseVarint64(ptr, &varint);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     int val = varint;
-    if (ctx->extra_parse_data().ValidateEnum<UnknownFieldSet>(val))
+    if (is_valid(val)) {
       repeated_field->Add(val);
+    } else {
+      unknown->AddVarint(field_num, val);
+    }
   }
+  ctx->PopLimit(old);
   return ptr;
 }
-
-const char* PackedValidEnumParserArg(const char* begin, const char* end,
-                                     void* object, ParseContext* ctx) {
+const char* PackedEnumParserArg(void* object, const char* ptr,
+                                ParseContext* ctx,
+                                bool (*is_valid)(const void*, int),
+                                const void* data, UnknownFieldSet* unknown,
+                                int field_num) {
+  int size = ReadSize(&ptr);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+  auto old = ctx->PushLimit(ptr, size);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(old >= 0);
   auto repeated_field = static_cast<RepeatedField<int>*>(object);
-  auto ptr = begin;
-  while (ptr < end) {
+  while (!ctx->DoneNoSlopCheck(&ptr)) {
     uint64 varint;
-    ptr = io::Parse64(ptr, &varint);
+    ptr = ParseVarint64(ptr, &varint);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     int val = varint;
-    if (ctx->extra_parse_data().ValidateEnumArg<UnknownFieldSet>(val))
+    if (is_valid(data, val)) {
       repeated_field->Add(val);
+    } else {
+      unknown->AddVarint(field_num, val);
+    }
   }
+  ctx->PopLimit(old);
   return ptr;
 }
 
@@ -325,38 +342,39 @@
   void AddFixed64(uint32 num, uint64 value) {
     unknown_->AddFixed64(num, value);
   }
-  ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
+  const char* ParseLengthDelimited(uint32 num, const char* ptr,
+                                   ParseContext* ctx) {
     string* s = unknown_->AddLengthDelimited(num);
-    // TODO(gerbens) SECURITY: add security
-    s->reserve(size);
-    return {GreedyStringParser, s};
+    int size = ReadSize(&ptr);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
+    return ctx->ReadString(ptr, size, s);
   }
-  ParseClosure StartGroup(uint32 num) {
-    return {UnknownGroupParse, unknown_->AddGroup(num)};
+  const char* ParseGroup(uint32 num, const char* ptr, ParseContext* ctx) {
+    UnknownFieldParserHelper child(unknown_->AddGroup(num));
+    return ctx->ParseGroup(&child, ptr, num * 8 + 3);
   }
-  void EndGroup(uint32 num) {}
   void AddFixed32(uint32 num, uint32 value) {
     unknown_->AddFixed32(num, value);
   }
 
+  const char* _InternalParse(const char* ptr, ParseContext* ctx) {
+    return WireFormatParser(*this, ptr, ctx);
+  }
+
  private:
   UnknownFieldSet* unknown_;
 };
 
-const char* UnknownGroupParse(const char* begin, const char* end, void* object,
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
                               ParseContext* ctx) {
-  UnknownFieldParserHelper field_parser(static_cast<UnknownFieldSet*>(object));
-  return WireFormatParser({UnknownGroupParse, object}, field_parser, begin, end,
-                          ctx);
+  UnknownFieldParserHelper field_parser(unknown);
+  return WireFormatParser(field_parser, ptr, ctx);
 }
 
-std::pair<const char*, bool> UnknownFieldParse(uint64 tag, ParseClosure parent,
-                                               const char* begin,
-                                               const char* end,
-                                               UnknownFieldSet* unknown,
-                                               ParseContext* ctx) {
+const char* UnknownFieldParse(uint64 tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx) {
   UnknownFieldParserHelper field_parser(unknown);
-  return FieldParser(tag, parent, field_parser, begin, end, ctx);
+  return FieldParser(tag, field_parser, ptr, ctx);
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index d8335cd..4d1c6df 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -186,6 +186,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 namespace internal {
+
 inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* unknown) {
   unknown->AddVarint(num, val);
 }
@@ -195,20 +196,22 @@
 }
 
 PROTOBUF_EXPORT
-const char* PackedValidEnumParser(const char* begin, const char* end,
-                                  void* object, ParseContext* ctx);
+const char* PackedEnumParser(void* object, const char* ptr, ParseContext* ctx,
+                             bool (*is_valid)(int), UnknownFieldSet* unknown,
+                             int field_num);
 PROTOBUF_EXPORT
-const char* PackedValidEnumParserArg(const char* begin, const char* end,
-                                     void* object, ParseContext* ctx);
+const char* PackedEnumParserArg(void* object, const char* ptr,
+                                ParseContext* ctx,
+                                bool (*is_valid)(const void*, int),
+                                const void* data, UnknownFieldSet* unknown,
+                                int field_num);
+
 PROTOBUF_EXPORT
-const char* UnknownGroupParse(const char* begin, const char* end, void* object,
+const char* UnknownGroupParse(UnknownFieldSet* unknown, const char* ptr,
                               ParseContext* ctx);
 PROTOBUF_EXPORT
-std::pair<const char*, bool> UnknownFieldParse(uint64 tag, ParseClosure parent,
-                                               const char* begin,
-                                               const char* end,
-                                               UnknownFieldSet* unknown,
-                                               ParseContext* ctx);
+const char* UnknownFieldParse(uint64 tag, UnknownFieldSet* unknown,
+                              const char* ptr, ParseContext* ctx);
 
 }  // namespace internal
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -267,7 +270,7 @@
   inline void SetType(Type type);
 
   union LengthDelimited {
-    std::string* string_value_;
+    std::string* string_value;
   };
 
   uint32 number_;
@@ -341,7 +344,7 @@
 }
 inline const std::string& UnknownField::length_delimited() const {
   assert(type() == TYPE_LENGTH_DELIMITED);
-  return *data_.length_delimited_.string_value_;
+  return *data_.length_delimited_.string_value;
 }
 inline const UnknownFieldSet& UnknownField::group() const {
   assert(type() == TYPE_GROUP);
@@ -362,11 +365,11 @@
 }
 inline void UnknownField::set_length_delimited(const std::string& value) {
   assert(type() == TYPE_LENGTH_DELIMITED);
-  data_.length_delimited_.string_value_->assign(value);
+  data_.length_delimited_.string_value->assign(value);
 }
 inline std::string* UnknownField::mutable_length_delimited() {
   assert(type() == TYPE_LENGTH_DELIMITED);
-  return data_.length_delimited_.string_value_;
+  return data_.length_delimited_.string_value;
 }
 inline UnknownFieldSet* UnknownField::mutable_group() {
   assert(type() == TYPE_GROUP);
@@ -375,7 +378,7 @@
 
 inline size_t UnknownField::GetLengthDelimitedSize() const {
   GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
-  return data_.length_delimited_.string_value_->size();
+  return data_.length_delimited_.string_value->size();
 }
 
 inline void UnknownField::SetType(Type type) {
diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h
index 257f6ab..ca78fc5 100644
--- a/src/google/protobuf/util/field_comparator.h
+++ b/src/google/protobuf/util/field_comparator.h
@@ -182,7 +182,8 @@
   // basic types (instead of submessages). They return true on success. One
   // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
   // value.
-  bool CompareBool(const FieldDescriptor& /* unused */, bool value_1, bool value_2) {
+  bool CompareBool(const FieldDescriptor& /* unused */,
+                   bool value_1, bool value_2) {
     return value_1 == value_2;
   }
 
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 0c4af61..2897759 100644
--- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
@@ -72,10 +72,10 @@
   virtual ~DefaultValueObjectWriterTest() {}
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        DefaultValueObjectWriterTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         DefaultValueObjectWriterTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(DefaultValueObjectWriterTest, Empty) {
   // Set expectation
@@ -159,10 +159,10 @@
   ~DefaultValueObjectWriterSuppressListTest() override {}
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        DefaultValueObjectWriterSuppressListTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         DefaultValueObjectWriterSuppressListTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(DefaultValueObjectWriterSuppressListTest, Empty) {
   // Set expectation. Emtpy lists should be suppressed.
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
index b67d76e..e90f6e2 100644
--- a/src/google/protobuf/util/internal/proto_writer.h
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -154,6 +154,8 @@
     ignore_unknown_fields_ = ignore_unknown_fields;
   }
 
+  bool ignore_unknown_fields() { return ignore_unknown_fields_; }
+
   void set_ignore_unknown_enum_values(bool ignore_unknown_enum_values) {
     ignore_unknown_enum_values_ = ignore_unknown_enum_values;
   }
diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
index 8a8b0c4..f242fa1 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc
@@ -290,10 +290,10 @@
   bool render_unknown_enum_values_;
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtostreamObjectSourceTest, EmptyMessage) {
   Book empty;
@@ -606,10 +606,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceMapsTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceMapsTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 // Tests JSON map.
 //
@@ -748,10 +748,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceAnysTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceAnysTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 // Tests JSON any support.
 //
@@ -984,10 +984,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceStructTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceStructTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 // Tests struct
 //
@@ -1030,10 +1030,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceFieldMaskTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceFieldMaskTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
   FieldMaskTest out;
@@ -1093,10 +1093,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtostreamObjectSourceTimestampTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtostreamObjectSourceTimestampTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
   TimestampDuration out;
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index da24dd5..adedc3b 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -190,10 +190,10 @@
   virtual ~ProtoStreamObjectWriterTest() {}
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterTest, EmptyObject) {
   Book empty;
@@ -1198,10 +1198,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterTimestampDurationTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterTimestampDurationTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) {
   TimestampDuration timestamp;
@@ -1594,10 +1594,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterStructTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterStructTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 // TODO(skarvaje): Write tests for failure cases.
 TEST_P(ProtoStreamObjectWriterStructTest, StructRenderSuccess) {
@@ -1746,10 +1746,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterMapTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterMapTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterMapTest, MapShouldNotAcceptList) {
   MapIn mm;
@@ -1843,10 +1843,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterAnyTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterAnyTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterAnyTest, AnyRenderSuccess) {
   AnyOut any;
@@ -2484,10 +2484,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterFieldMaskTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterFieldMaskTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterFieldMaskTest, SimpleFieldMaskTest) {
   FieldMaskTest expected;
@@ -2737,10 +2737,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterWrappersTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterWrappersTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterWrappersTest, WrapperAcceptsNull) {
   Int32Wrapper wrapper;
@@ -2760,10 +2760,10 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
-                        ProtoStreamObjectWriterOneOfsTest,
-                        ::testing::Values(
-                            testing::USE_TYPE_RESOLVER));
+INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
+                         ProtoStreamObjectWriterOneOfsTest,
+                         ::testing::Values(
+                             testing::USE_TYPE_RESOLVER));
 
 TEST_P(ProtoStreamObjectWriterOneOfsTest,
        MultipleOneofsFailForPrimitiveTypesTest) {
diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto
index 767611f..1120bc1 100644
--- a/src/google/protobuf/util/json_format.proto
+++ b/src/google/protobuf/util/json_format.proto
@@ -111,3 +111,9 @@
 message TestStringMap {
   map<string, string> string_map = 1;
 }
+
+message TestStringSerializer {
+  optional string scalar_string = 1;
+  repeated string repeated_string = 2;
+  map<string, string> string_map = 3;
+}
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 0f1a03b..f9d33fa 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -171,7 +171,7 @@
   //
   // This is different from MakeTag(field->number(), field->type()) in the
   // case of packed repeated fields.
-  static uint32 MakeTag(int field_number, WireType type);
+  constexpr static uint32 MakeTag(int field_number, WireType type);
   static WireType GetTagWireType(uint32 tag);
   static int GetTagFieldNumber(uint32 tag);
 
@@ -650,20 +650,6 @@
                                         uint8* target) {
     return InternalWriteMessageToArray(field_number, value, target);
   }
-  template <typename MessageType>
-  INL static uint8* WriteGroupNoVirtualToArray(int field_number,
-                                               const MessageType& value,
-                                               uint8* target) {
-    return InternalWriteGroupNoVirtualToArray(field_number, value, false,
-                                              target);
-  }
-  template <typename MessageType>
-  INL static uint8* WriteMessageNoVirtualToArray(int field_number,
-                                                 const MessageType& value,
-                                                 uint8* target) {
-    return InternalWriteMessageNoVirtualToArray(field_number, value, false,
-                                                target);
-  }
 
 #undef INL
 
@@ -784,7 +770,8 @@
   return kFieldTypeToCppTypeMap[type];
 }
 
-inline uint32 WireFormatLite::MakeTag(int field_number, WireType type) {
+constexpr inline uint32 WireFormatLite::MakeTag(int field_number,
+                                                WireType type) {
   return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
 }
 
@@ -912,29 +899,6 @@
   return unknown_fields.size();
 }
 
-// Some convenience functions to simplify the generated parse loop code.
-// Returning the value and updating the buffer pointer allows for nicer
-// function composition. We rely on the compiler to inline this.
-// Also in debug compiles having local scoped variables tend to generated
-// stack frames that scale as O(num fields).
-inline uint64 ReadVarint(const char** p) {
-  uint64 tmp;
-  *p = io::Parse64(*p, &tmp);
-  return tmp;
-}
-
-inline int64 ReadVarintZigZag64(const char** p) {
-  uint64 tmp;
-  *p = io::Parse64(*p, &tmp);
-  return WireFormatLite::ZigZagDecode64(tmp);
-}
-
-inline int32 ReadVarintZigZag32(const char** p) {
-  uint64 tmp;
-  *p = io::Parse64(*p, &tmp);
-  return WireFormatLite::ZigZagDecode32(tmp);
-}
-
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 266b1e1..15c75a6 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -1021,6 +1021,7 @@
           io::CodedInputStream sub_input(
               reinterpret_cast<const uint8*>(message_data.data()),
               static_cast<int>(message_data.size()));
+          sub_input.SetRecursionLimit(input->RecursionBudget());
           if (!ms.ParseField(last_type_id, &sub_input)) {
             return false;
           }
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 114e883..62b5351 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -599,8 +599,8 @@
   {
     // Test parse the message via Reflection.
     proto2_wireformat_unittest::TestMessageSet message_set;
-    io::CodedInputStream input(
-        reinterpret_cast<const uint8*>(data.data()), data.size());
+    io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()),
+                               data.size());
     EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set));
     EXPECT_TRUE(input.ConsumedEntireMessage());
 
@@ -609,6 +609,65 @@
   }
 }
 
+void SerializeReverseOrder(
+    const proto2_wireformat_unittest::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output);
+
+void SerializeReverseOrder(const unittest::TestMessageSetExtension1& message,
+                           io::CodedOutputStream* coded_output) {
+  WireFormatLite::WriteTag(15,  // i
+                           WireFormatLite::WIRETYPE_VARINT, coded_output);
+  coded_output->WriteVarint32(message.i());
+  WireFormatLite::WriteTag(16,  // recursive
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  coded_output->WriteVarint32(message.recursive().GetCachedSize());
+  SerializeReverseOrder(message.recursive(), coded_output);
+}
+
+void SerializeReverseOrder(
+    const proto2_wireformat_unittest::TestMessageSet& mset,
+    io::CodedOutputStream* coded_output) {
+  if (!mset.HasExtension(
+          unittest::TestMessageSetExtension1::message_set_extension))
+    return;
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
+  // Write the message content first.
+  WireFormatLite::WriteTag(WireFormatLite::kMessageSetMessageNumber,
+                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                           coded_output);
+  auto& message = mset.GetExtension(
+      unittest::TestMessageSetExtension1::message_set_extension);
+  coded_output->WriteVarint32(message.GetCachedSize());
+  SerializeReverseOrder(message, coded_output);
+  // Write the type id.
+  uint32 type_id = message.GetDescriptor()->extension(0)->number();
+  WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, type_id,
+                              coded_output);
+  coded_output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+}
+
+TEST(WireFormatTest, ParseMessageSetWithDeepRecReverseOrder) {
+  string data;
+  {
+    proto2_wireformat_unittest::TestMessageSet message_set;
+    proto2_wireformat_unittest::TestMessageSet* mset = &message_set;
+    for (int i = 0; i < 200; i++) {
+      auto m = mset->MutableExtension(
+          unittest::TestMessageSetExtension1::message_set_extension);
+      m->set_i(i);
+      mset = m->mutable_recursive();
+    }
+    message_set.ByteSizeLong();
+    // Serialize with reverse payload tag order
+    io::StringOutputStream output_stream(&data);
+    io::CodedOutputStream coded_output(&output_stream);
+    SerializeReverseOrder(message_set, &coded_output);
+  }
+  proto2_wireformat_unittest::TestMessageSet message_set;
+  EXPECT_FALSE(message_set.ParseFromString(data));
+}
+
 TEST(WireFormatTest, ParseBrokenMessageSet) {
   proto2_wireformat_unittest::TestMessageSet message_set;
   string input("goodbye");  // Invalid wire format data.
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 12fd317..b65975f 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -194,9 +194,9 @@
   ::google::protobuf::internal::InitSCC(&scc_info_BytesValue_google_2fprotobuf_2fwrappers_2eproto.base);
 }
 
-::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
-constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
-constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static ::google::protobuf::Metadata file_level_metadata_google_2fprotobuf_2fwrappers_2eproto[9];
+static constexpr ::google::protobuf::EnumDescriptor const** file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
+static constexpr ::google::protobuf::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto = nullptr;
 
 const ::google::protobuf::uint32 TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
   ~0u,  // no _has_bits_
@@ -278,7 +278,7 @@
   reinterpret_cast<const ::google::protobuf::Message*>(&::google::protobuf::_BytesValue_default_instance_),
 };
 
-::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fwrappers_2eproto = {
+static ::google::protobuf::internal::AssignDescriptorsTable assign_descriptors_table_google_2fprotobuf_2fwrappers_2eproto = {
   {}, AddDescriptors_google_2fprotobuf_2fwrappers_2eproto, "google/protobuf/wrappers.proto", schemas,
   file_default_instances, TableStruct_google_2fprotobuf_2fwrappers_2eproto::offsets,
   file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, 9, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto, file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
@@ -298,7 +298,7 @@
   "\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb"
   "\006proto3"
   ;
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+static ::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
   false, InitDefaults_google_2fprotobuf_2fwrappers_2eproto, 
   descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
   "google/protobuf/wrappers.proto", &assign_descriptors_table_google_2fprotobuf_2fwrappers_2eproto, 447,
@@ -387,36 +387,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* DoubleValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<DoubleValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* DoubleValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // double value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 9) goto handle_unusual;
-        msg->set_value(::google::protobuf::io::UnalignedLoad<double>(ptr));
+        set_value(::google::protobuf::internal::UnalignedLoad<double>(ptr));
         ptr += sizeof(double);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -674,36 +667,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* FloatValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<FloatValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* FloatValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // float value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 13) goto handle_unusual;
-        msg->set_value(::google::protobuf::io::UnalignedLoad<float>(ptr));
+        set_value(::google::protobuf::internal::UnalignedLoad<float>(ptr));
         ptr += sizeof(float);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -961,36 +947,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Int64Value::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Int64Value*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Int64Value::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // int64 value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -1250,36 +1229,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* UInt64Value::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<UInt64Value*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* UInt64Value::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // uint64 value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -1539,36 +1511,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* Int32Value::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<Int32Value*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* Int32Value::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // int32 value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -1828,36 +1793,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* UInt32Value::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<UInt32Value*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* UInt32Value::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // uint32 value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -2117,36 +2075,29 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* BoolValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<BoolValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* BoolValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // bool value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 8) goto handle_unusual;
-        msg->set_value(::google::protobuf::internal::ReadVarint(&ptr));
+        set_value(::google::protobuf::internal::ReadVarint(&ptr));
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
@@ -2411,56 +2362,33 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* StringValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<StringValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* StringValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // string value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParserUTF8(mutable_value(), ptr, ctx, "google.protobuf.StringValue.value");
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        ctx->extra_parse_data().SetFieldName("google.protobuf.StringValue.value");
-        object = msg->mutable_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool StringValue::MergePartialFromCodedStream(
@@ -2737,55 +2665,33 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-const char* BytesValue::_InternalParse(const char* begin, const char* end, void* object,
-                  ::google::protobuf::internal::ParseContext* ctx) {
-  auto msg = static_cast<BytesValue*>(object);
-  ::google::protobuf::int32 size; (void)size;
-  int depth; (void)depth;
-  ::google::protobuf::uint32 tag;
-  ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = ::google::protobuf::io::Parse32(ptr, &tag);
+const char* BytesValue::_InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) {
+  while (!ctx->Done(&ptr)) {
+    ::google::protobuf::uint32 tag;
+    ptr = ::google::protobuf::internal::ReadTag(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       // bytes value = 1;
       case 1: {
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
-        ptr = ::google::protobuf::io::ReadSize(ptr, &size);
+        ptr = ::google::protobuf::internal::InlineGreedyStringParser(mutable_value(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        object = msg->mutable_value();
-        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
-          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
-          goto string_till_end;
-        }
-        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
-        ::google::protobuf::internal::InlineGreedyStringParser(object, ptr, size, ctx);
-        ptr += size;
         break;
       }
       default: {
       handle_unusual:
         if ((tag & 7) == 4 || tag == 0) {
-          ctx->EndGroup(tag);
+          ctx->SetLastTag(tag);
           return ptr;
         }
-        auto res = UnknownFieldParse(tag, {_InternalParse, msg},
-          ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
-        ptr = res.first;
+        ptr = UnknownFieldParse(tag,
+          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
-        if (res.second) return ptr;
+        break;
       }
     }  // switch
   }  // while
   return ptr;
-string_till_end:
-  static_cast<::std::string*>(object)->clear();
-  static_cast<::std::string*>(object)->reserve(size);
-  goto len_delim_till_end;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},
-                               {parser_till_end, object}, size);
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool BytesValue::MergePartialFromCodedStream(
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 11a7662..420a5b7 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -31,6 +31,13 @@
 #include <google/protobuf/repeated_field.h>  // IWYU pragma: export
 #include <google/protobuf/extension_set.h>  // IWYU pragma: export
 #include <google/protobuf/unknown_field_set.h>
+namespace google {
+namespace protobuf {
+namespace internal {
+class AnyMetadata;
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
 // @@protoc_insertion_point(includes)
 #include <google/protobuf/port_def.inc>
 #define PROTOBUF_INTERNAL_EXPORT_google_2fprotobuf_2fwrappers_2eproto PROTOBUF_EXPORT
@@ -163,8 +170,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -176,10 +182,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(DoubleValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.DoubleValue";
+  }
   protected:
   explicit DoubleValue(::google::protobuf::Arena* arena);
   private:
@@ -290,8 +300,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -303,10 +312,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(FloatValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.FloatValue";
+  }
   protected:
   explicit FloatValue(::google::protobuf::Arena* arena);
   private:
@@ -417,8 +430,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -430,10 +442,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Int64Value* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Int64Value";
+  }
   protected:
   explicit Int64Value(::google::protobuf::Arena* arena);
   private:
@@ -544,8 +560,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -557,10 +572,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(UInt64Value* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.UInt64Value";
+  }
   protected:
   explicit UInt64Value(::google::protobuf::Arena* arena);
   private:
@@ -671,8 +690,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -684,10 +702,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(Int32Value* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.Int32Value";
+  }
   protected:
   explicit Int32Value(::google::protobuf::Arena* arena);
   private:
@@ -798,8 +820,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -811,10 +832,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(UInt32Value* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.UInt32Value";
+  }
   protected:
   explicit UInt32Value(::google::protobuf::Arena* arena);
   private:
@@ -925,8 +950,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -938,10 +962,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(BoolValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.BoolValue";
+  }
   protected:
   explicit BoolValue(::google::protobuf::Arena* arena);
   private:
@@ -1052,8 +1080,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1065,10 +1092,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(StringValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.StringValue";
+  }
   protected:
   explicit StringValue(::google::protobuf::Arena* arena);
   private:
@@ -1196,8 +1227,7 @@
 
   size_t ByteSizeLong() const final;
   #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  static const char* _InternalParse(const char* begin, const char* end, void* object, ::google::protobuf::internal::ParseContext* ctx);
-  ::google::protobuf::internal::ParseFunc _ParseFunc() const final { return _InternalParse; }
+  const char* _InternalParse(const char* ptr, ::google::protobuf::internal::ParseContext* ctx) final;
   #else
   bool MergePartialFromCodedStream(
       ::google::protobuf::io::CodedInputStream* input) final;
@@ -1209,10 +1239,14 @@
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
-  void SharedCtor();
-  void SharedDtor();
+  inline void SharedCtor();
+  inline void SharedDtor();
   void SetCachedSize(int size) const final;
   void InternalSwap(BytesValue* other);
+  friend class ::google::protobuf::internal::AnyMetadata;
+  static ::google::protobuf::StringPiece FullMessageName() {
+    return "google.protobuf.BytesValue";
+  }
   protected:
   explicit BytesValue(::google::protobuf::Arena* arena);
   private: