Merge pull request #5921 from haon4/contributing

Down integrate to Github
diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in
index 9b429f7..8456d01 100644
--- a/cmake/extract_includes.bat.in
+++ b/cmake/extract_includes.bat.in
@@ -115,7 +115,6 @@
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver_util.h" include\google\protobuf\util\type_resolver_util.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format.h" include\google\protobuf\wire_format.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite.h" include\google\protobuf\wire_format_lite.h
-copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format_lite_inl.h" include\google\protobuf\wire_format_lite_inl.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wrappers.pb.h" include\google\protobuf\wrappers.pb.h
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\any.proto" include\google\protobuf\any.proto
 copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\api.proto" include\google\protobuf\api.proto
diff --git a/conformance/Makefile.am b/conformance/Makefile.am
index f2337df..495b462 100644
--- a/conformance/Makefile.am
+++ b/conformance/Makefile.am
@@ -336,28 +336,28 @@
 	./conformance-test-runner --enforce_recommended --failure_list failure_list_cpp.txt ./conformance-cpp
 
 test_java: protoc_middleman conformance-test-runner conformance-java
-	./conformance-test-runner --enforce_recommended --failure_list failure_list_java.txt ./conformance-java
+	./conformance-test-runner --enforce_recommended --failure_list failure_list_java.txt --text_format_failure_list text_format_failure_list_java.txt ./conformance-java
 
 test_java_lite: protoc_middleman conformance-test-runner conformance-java-lite
 	./conformance-test-runner --enforce_recommended ./conformance-java-lite
 
 test_csharp: protoc_middleman conformance-test-runner conformance-csharp
-	./conformance-test-runner --enforce_recommended --failure_list failure_list_csharp.txt ./conformance-csharp
+	./conformance-test-runner --enforce_recommended --failure_list failure_list_csharp.txt --text_format_failure_list text_format_failure_list_csharp.txt ./conformance-csharp
 
 test_ruby: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
-	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby.txt ./conformance_ruby.rb
+	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby.txt --text_format_failure_list text_format_failure_list_ruby.txt ./conformance_ruby.rb
 
 test_ruby_mac: protoc_middleman conformance-test-runner $(other_language_protoc_outputs)
-	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby_mac.txt ./conformance_ruby.rb
+	RUBYLIB=../ruby/lib:. ./conformance-test-runner --enforce_recommended --failure_list failure_list_ruby_mac.txt --text_format_failure_list text_format_failure_list_ruby.txt ./conformance_ruby.rb
 
 test_php: protoc_middleman conformance-test-runner conformance-php $(other_language_protoc_outputs)
-	./conformance-test-runner --enforce_recommended --failure_list failure_list_php.txt ./conformance-php
+	./conformance-test-runner --enforce_recommended --failure_list failure_list_php.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php
 
 test_php_c: protoc_middleman conformance-test-runner conformance-php-c $(other_language_protoc_outputs)
-	./conformance-test-runner --enforce_recommended --failure_list failure_list_php_c.txt ./conformance-php-c
+	./conformance-test-runner --enforce_recommended --failure_list failure_list_php_c.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php-c
 
 test_php_zts_c: protoc_middleman conformance-test-runner conformance-php-c $(other_language_protoc_outputs)
-	./conformance-test-runner --enforce_recommended --failure_list failure_list_php_zts_c.txt ./conformance-php-c
+	./conformance-test-runner --enforce_recommended --failure_list failure_list_php_zts_c.txt --text_format_failure_list text_format_failure_list_php.txt ./conformance-php-c
 
 # These depend on library paths being properly set up.  The easiest way to
 # run them is to just use "tox" from the python dir.
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
index 271476d..54da406 100644
--- a/conformance/conformance.proto
+++ b/conformance/conformance.proto
@@ -119,6 +119,10 @@
 
   // Specify details for how to encode jspb.
   JspbEncodingConfig jspb_encoding_options = 6;
+
+  // This can be used in json and text format. If true, testee should print
+  // unknown fields instead of ignore. This feature is optional.
+  bool print_unknown_fields = 9;
 }
 
 // Represents a single test case's output.
diff --git a/conformance/conformance_cpp.cc b/conformance/conformance_cpp.cc
index ff70d5d..5a1f214 100644
--- a/conformance/conformance_cpp.cc
+++ b/conformance/conformance_cpp.cc
@@ -214,8 +214,10 @@
     }
 
     case conformance::TEXT_FORMAT: {
-      GOOGLE_CHECK(TextFormat::PrintToString(*test_message,
-                                             response->mutable_text_payload()));
+      TextFormat::Printer printer;
+      printer.SetHideUnknownFields(!request.print_unknown_fields());
+      GOOGLE_CHECK(printer.PrintToString(*test_message,
+                                         response->mutable_text_payload()));
       break;
     }
 
diff --git a/conformance/conformance_python.py b/conformance/conformance_python.py
index 5c4f900..88d9749 100755
--- a/conformance/conformance_python.py
+++ b/conformance/conformance_python.py
@@ -166,7 +166,8 @@
         return response
 
     elif request.requested_output_format == conformance_pb2.TEXT_FORMAT:
-      response.text_payload = text_format.MessageToString(test_message)
+      response.text_payload = text_format.MessageToString(
+          test_message, print_unknown_fields=request.print_unknown_fields)
 
   except Exception as e:
     response.runtime_error = str(e)
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 221464c..6325b35 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -68,6 +68,7 @@
       input_format_(input_format),
       output_format_(output_format),
       prototype_message_(prototype_message),
+      prototype_message_for_compare_(prototype_message.New()),
       test_name_(test_name) {
   switch (input_format) {
     case conformance::PROTOBUF: {
@@ -102,7 +103,7 @@
 
 Message* ConformanceTestSuite::ConformanceRequestSetting::
     GetTestMessage() const {
-  return prototype_message_.New();
+  return prototype_message_for_compare_->New();
 }
 
 string ConformanceTestSuite::ConformanceRequestSetting::
diff --git a/conformance/conformance_test.h b/conformance/conformance_test.h
index b64943d..4d741e7 100644
--- a/conformance/conformance_test.h
+++ b/conformance/conformance_test.h
@@ -224,6 +224,14 @@
 
     string ConformanceLevelToString(ConformanceLevel level) const;
 
+    void SetPrintUnknownFields(bool print_unknown_fields) {
+      request_.set_print_unknown_fields(true);
+    }
+
+    void SetPrototypeMessageForCompare(const Message& message) {
+      prototype_message_for_compare_.reset(message.New());
+    }
+
    protected:
     virtual string InputFormatString(conformance::WireFormat format) const;
     virtual string OutputFormatString(conformance::WireFormat format) const;
@@ -234,6 +242,7 @@
     ::conformance::WireFormat input_format_;
     ::conformance::WireFormat output_format_;
     const Message& prototype_message_;
+    std::unique_ptr<Message> prototype_message_for_compare_;
     string test_name_;
   };
 
diff --git a/conformance/text_format_conformance_suite.cc b/conformance/text_format_conformance_suite.cc
index 17af09e..76f398c 100644
--- a/conformance/text_format_conformance_suite.cc
+++ b/conformance/text_format_conformance_suite.cc
@@ -43,6 +43,7 @@
 using google::protobuf::Message;
 using google::protobuf::TextFormat;
 using protobuf_test_messages::proto2::TestAllTypesProto2;
+using protobuf_test_messages::proto2::UnknownToTestAllTypes;
 using protobuf_test_messages::proto3::TestAllTypesProto3;
 using std::string;
 
@@ -54,8 +55,14 @@
 }
 
 bool TextFormatConformanceTestSuite::ParseTextFormatResponse(
-    const ConformanceResponse& response, Message* test_message) {
-  if (!TextFormat::ParseFromString(response.text_payload(), test_message)) {
+    const ConformanceResponse& response,
+    const ConformanceRequestSetting& setting, Message* test_message) {
+  TextFormat::Parser parser;
+  const ConformanceRequest& request = setting.GetRequest();
+  if (request.print_unknown_fields()) {
+    parser.AllowFieldNumber(true);
+  }
+  if (!parser.ParseFromString(response.text_payload(), test_message)) {
     GOOGLE_LOG(ERROR) << "INTERNAL ERROR: internal text->protobuf transcode "
                       << "yielded unparseable proto. Text payload: "
                       << response.text_payload();
@@ -103,7 +110,7 @@
         return false;
       }
 
-      if (!ParseTextFormatResponse(response, test_message)) {
+      if (!ParseTextFormatResponse(response, setting, test_message)) {
         ReportFailure(
             test_name, level, request, response,
             "TEXT_FORMAT output we received from test was unparseable.");
@@ -171,6 +178,27 @@
   RunValidInputTest(setting2, input_text);
 }
 
+void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
+    const string& test_name, const Message& message) {
+  string serialized_input;
+  message.SerializeToString(&serialized_input);
+  TestAllTypesProto3 prototype;
+  ConformanceRequestSetting setting1(
+      RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
+      conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Drop",
+      serialized_input);
+  setting1.SetPrototypeMessageForCompare(message);
+  RunValidBinaryInputTest(setting1, "");
+
+  ConformanceRequestSetting setting2(
+      RECOMMENDED, conformance::PROTOBUF, conformance::TEXT_FORMAT,
+      conformance::TEXT_FORMAT_TEST, prototype, test_name + "_Print",
+      serialized_input);
+  setting2.SetPrototypeMessageForCompare(message);
+  setting2.SetPrintUnknownFields(true);
+  RunValidBinaryInputTest(setting2, serialized_input);
+}
+
 void TextFormatConformanceTestSuite::RunSuiteImpl() {
   RunValidTextFormatTest("HelloWorld", REQUIRED,
                          "optional_string: 'Hello, World!'");
@@ -235,6 +263,29 @@
                                "Data: { group_int32: 1 }");
   RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
                                "Data {}");
+
+
+  // Unknown Fields
+  UnknownToTestAllTypes message;
+  // Unable to print unknown Fixed32/Fixed64 fields as if they are known.
+  // Fixed32/Fixed64 fields are not added in the tests.
+  message.set_optional_int32(123);
+  message.set_optional_string("hello");
+  message.set_optional_bool(true);
+  RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
+
+  message.Clear();
+  message.mutable_nested_message()->set_c(111);
+  RunValidUnknownTextFormatTest("MessageUnknownFields", message);
+
+  message.Clear();
+  message.mutable_optionalgroup()->set_a(321);
+  RunValidUnknownTextFormatTest("GroupUnknownFields", message);
+
+  message.add_repeated_int32(1);
+  message.add_repeated_int32(2);
+  message.add_repeated_int32(3);
+  RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
 }
 
 }  // namespace protobuf
diff --git a/conformance/text_format_conformance_suite.h b/conformance/text_format_conformance_suite.h
index 661d45e..dd258f5 100644
--- a/conformance/text_format_conformance_suite.h
+++ b/conformance/text_format_conformance_suite.h
@@ -51,9 +51,12 @@
                                          ConformanceLevel level,
                                          const string& input_text,
                                          const Message& prototype);
+  void RunValidUnknownTextFormatTest(const string& test_name,
+                                     const Message& message);
   void ExpectParseFailure(const string& test_name, ConformanceLevel level,
                           const string& input);
   bool ParseTextFormatResponse(const conformance::ConformanceResponse& response,
+                               const ConformanceRequestSetting& setting,
                                Message* test_message);
   bool ParseResponse(const conformance::ConformanceResponse& response,
                      const ConformanceRequestSetting& setting,
diff --git a/conformance/text_format_failure_list_csharp.txt b/conformance/text_format_failure_list_csharp.txt
new file mode 100644
index 0000000..404b64a
--- /dev/null
+++ b/conformance/text_format_failure_list_csharp.txt
@@ -0,0 +1,8 @@
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Print.TextFormatOutput
diff --git a/conformance/text_format_failure_list_java.txt b/conformance/text_format_failure_list_java.txt
new file mode 100755
index 0000000..4902d46
--- /dev/null
+++ b/conformance/text_format_failure_list_java.txt
@@ -0,0 +1,4 @@
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
diff --git a/conformance/text_format_failure_list_php.txt b/conformance/text_format_failure_list_php.txt
new file mode 100644
index 0000000..404b64a
--- /dev/null
+++ b/conformance/text_format_failure_list_php.txt
@@ -0,0 +1,8 @@
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Print.TextFormatOutput
diff --git a/conformance/text_format_failure_list_ruby.txt b/conformance/text_format_failure_list_ruby.txt
new file mode 100644
index 0000000..404b64a
--- /dev/null
+++ b/conformance/text_format_failure_list_ruby.txt
@@ -0,0 +1,8 @@
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.GroupUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.MessageUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Print.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
+Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Print.TextFormatOutput
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
index 0a51062..589ea76 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs
@@ -25,32 +25,32 @@
       byte[] descriptorData = global::System.Convert.FromBase64String(
           string.Concat(
             "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiHQoKRmFpbHVyZVNl",
-            "dBIPCgdmYWlsdXJlGAEgAygJIsUCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
+            "dBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
             "cHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgCIAEo",
             "CUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9hZBgI",
             "IAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0GAMgASgOMhcuY29u",
             "Zm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5cGUYBCABKAkSMAoN",
             "dGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNlLlRlc3RDYXRlZ29y",
             "eRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsyHy5jb25mb3JtYW5j",
-            "ZS5Kc3BiRW5jb2RpbmdDb25maWdCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFu",
-            "Y2VSZXNwb25zZRIVCgtwYXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6",
-            "ZV9lcnJvchgGIAEoCUgAEhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBw",
-            "cm90b2J1Zl9wYXlsb2FkGAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJ",
-            "SAASEQoHc2tpcHBlZBgFIAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgA",
-            "EhYKDHRleHRfcGF5bG9hZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5j",
-            "b2RpbmdDb25maWcSIQoZdXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEo",
-            "CCpQCgpXaXJlRm9ybWF0Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQ",
-            "ARIICgRKU09OEAISCAoESlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRl",
-            "c3RDYXRlZ29yeRIUChBVTlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RF",
-            "U1QQARINCglKU09OX1RFU1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BB",
-            "UlNJTkdfVEVTVBADEg0KCUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RF",
-            "U1QQBUIhCh9jb20uZ29vZ2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90",
-            "bzM="));
+            "ZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5rbm93bl9maWVsZHMY",
+            "CSABKAhCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtw",
+            "YXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgA",
+            "EhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2Fk",
+            "GAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgF",
+            "IAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9h",
+            "ZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5jb2RpbmdDb25maWcSIQoZ",
+            "dXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEoCCpQCgpXaXJlRm9ybWF0",
+            "Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQARIICgRKU09OEAISCAoE",
+            "SlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRlc3RDYXRlZ29yeRIUChBV",
+            "TlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RFU1QQARINCglKU09OX1RF",
+            "U1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BBUlNJTkdfVEVTVBADEg0K",
+            "CUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RFU1QQBUIhCh9jb20uZ29v",
+            "Z2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90bzM="));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.TestCategory), }, new pbr::GeneratedClrTypeInfo[] {
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.FailureSet), global::Conformance.FailureSet.Parser, new[]{ "Failure" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions" }, new[]{ "Payload" }, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions", "PrintUnknownFields" }, new[]{ "Payload" }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.JspbEncodingConfig), global::Conformance.JspbEncodingConfig.Parser, new[]{ "UseJspbArrayAnyFormat" }, null, null, null)
           }));
@@ -264,6 +264,7 @@
       messageType_ = other.messageType_;
       testCategory_ = other.testCategory_;
       jspbEncodingOptions_ = other.jspbEncodingOptions_ != null ? other.jspbEncodingOptions_.Clone() : null;
+      printUnknownFields_ = other.printUnknownFields_;
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
@@ -394,6 +395,21 @@
       }
     }
 
+    /// <summary>Field number for the "print_unknown_fields" field.</summary>
+    public const int PrintUnknownFieldsFieldNumber = 9;
+    private bool printUnknownFields_;
+    /// <summary>
+    /// This can be used in json and text format. If true, testee should print
+    /// unknown fields instead of ignore. This feature is optional.
+    /// </summary>
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool PrintUnknownFields {
+      get { return printUnknownFields_; }
+      set {
+        printUnknownFields_ = value;
+      }
+    }
+
     private object payload_;
     /// <summary>Enum of possible cases for the "payload" oneof.</summary>
     public enum PayloadOneofCase {
@@ -436,6 +452,7 @@
       if (MessageType != other.MessageType) return false;
       if (TestCategory != other.TestCategory) return false;
       if (!object.Equals(JspbEncodingOptions, other.JspbEncodingOptions)) return false;
+      if (PrintUnknownFields != other.PrintUnknownFields) return false;
       if (PayloadCase != other.PayloadCase) return false;
       return Equals(_unknownFields, other._unknownFields);
     }
@@ -451,6 +468,7 @@
       if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
       if (TestCategory != 0) hash ^= TestCategory.GetHashCode();
       if (jspbEncodingOptions_ != null) hash ^= JspbEncodingOptions.GetHashCode();
+      if (PrintUnknownFields != false) hash ^= PrintUnknownFields.GetHashCode();
       hash ^= (int) payloadCase_;
       if (_unknownFields != null) {
         hash ^= _unknownFields.GetHashCode();
@@ -497,6 +515,10 @@
         output.WriteRawTag(66);
         output.WriteString(TextPayload);
       }
+      if (PrintUnknownFields != false) {
+        output.WriteRawTag(72);
+        output.WriteBool(PrintUnknownFields);
+      }
       if (_unknownFields != null) {
         _unknownFields.WriteTo(output);
       }
@@ -529,6 +551,9 @@
       if (jspbEncodingOptions_ != null) {
         size += 1 + pb::CodedOutputStream.ComputeMessageSize(JspbEncodingOptions);
       }
+      if (PrintUnknownFields != false) {
+        size += 1 + 1;
+      }
       if (_unknownFields != null) {
         size += _unknownFields.CalculateSize();
       }
@@ -555,6 +580,9 @@
         }
         JspbEncodingOptions.MergeFrom(other.JspbEncodingOptions);
       }
+      if (other.PrintUnknownFields != false) {
+        PrintUnknownFields = other.PrintUnknownFields;
+      }
       switch (other.PayloadCase) {
         case PayloadOneofCase.ProtobufPayload:
           ProtobufPayload = other.ProtobufPayload;
@@ -616,6 +644,10 @@
             TextPayload = input.ReadString();
             break;
           }
+          case 72: {
+            PrintUnknownFields = input.ReadBool();
+            break;
+          }
         }
       }
     }
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 09a4c8b..9d9b6a5 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java
index 54d158d..648991d 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -1438,16 +1438,14 @@
         LiteralByteString lbsOther = (LiteralByteString) other;
         byte[] thisBytes = bytes;
         byte[] otherBytes = lbsOther.bytes;
-        int thisLimit = getOffsetIntoBytes() + length;
-        for (int thisIndex = getOffsetIntoBytes(),
-                otherIndex = lbsOther.getOffsetIntoBytes() + offset;
-            (thisIndex < thisLimit);
-            ++thisIndex, ++otherIndex) {
-          if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
-            return false;
-          }
-        }
-        return true;
+
+        return UnsafeUtil.mismatch(
+                thisBytes,
+                getOffsetIntoBytes(),
+                otherBytes,
+                lbsOther.getOffsetIntoBytes() + offset,
+                length)
+            == -1;
       }
 
       return other.substring(offset, offset + length).equals(substring(0, length));
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index 53771de..3823f81 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -1264,16 +1264,34 @@
 
     @Override
     public final void writeUInt32NoTag(int value) throws IOException {
-      if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT32_SIZE) {
-        while (true) {
-          if ((value & ~0x7F) == 0) {
-            UnsafeUtil.putByte(buffer, position++, (byte) value);
-            return;
-          } else {
-            UnsafeUtil.putByte(buffer, position++, (byte) ((value & 0x7F) | 0x80));
-            value >>>= 7;
-          }
+      if (HAS_UNSAFE_ARRAY_OPERATIONS
+          && !Android.isOnAndroidDevice()
+          && spaceLeft() >= MAX_VARINT32_SIZE) {
+        if ((value & ~0x7F) == 0) {
+          UnsafeUtil.putByte(buffer, position++, (byte) value);
+          return;
         }
+        UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80));
+        value >>>= 7;
+        if ((value & ~0x7F) == 0) {
+          UnsafeUtil.putByte(buffer, position++, (byte) value);
+          return;
+        }
+        UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80));
+        value >>>= 7;
+        if ((value & ~0x7F) == 0) {
+          UnsafeUtil.putByte(buffer, position++, (byte) value);
+          return;
+        }
+        UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80));
+        value >>>= 7;
+        if ((value & ~0x7F) == 0) {
+          UnsafeUtil.putByte(buffer, position++, (byte) value);
+          return;
+        }
+        UnsafeUtil.putByte(buffer, position++, (byte) (value | 0x80));
+        value >>>= 7;
+        UnsafeUtil.putByte(buffer, position++, (byte) value);
       } else {
         try {
           while (true) {
diff --git a/java/core/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java
index e5da634..30c828e 100644
--- a/java/core/src/main/java/com/google/protobuf/Extension.java
+++ b/java/core/src/main/java/com/google/protobuf/Extension.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+// TODO(chrisn): Change ContainingType to extend Message
 /**
  * Interface that generated extensions implement.
  *
@@ -37,6 +38,11 @@
  */
 public abstract class Extension<ContainingType extends MessageLite, Type>
     extends ExtensionLite<ContainingType, Type> {
+  // TODO(chrisn): Add package-private constructor.
+
+  /** {@inheritDoc} Overridden to return {@link Message} instead of {@link MessageLite}. */
+  @Override
+  public abstract Message getMessageDefaultInstance();
 
   /** Returns the descriptor of the extension. */
   public abstract Descriptors.FieldDescriptor getDescriptor();
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 77c837e..e16633b 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -448,22 +448,26 @@
     }
 
     /**
-     * Find a type by its full name. Returns null if it cannot be found in
-     * this {@link TypeRegistry}.
+     * Find a type by its full name. Returns null if it cannot be found in this {@link
+     * TypeRegistry}.
      */
     public Descriptor find(String name) {
       return types.get(name);
     }
 
+    /* @Nullable */
+    Descriptor getDescriptorForTypeUrl(String typeUrl) throws InvalidProtocolBufferException {
+      return find(getTypeName(typeUrl));
+    }
+
     private final Map<String, Descriptor> types;
 
     private TypeRegistry(Map<String, Descriptor> types) {
       this.types = types;
     }
 
-    /**
-     * A Builder is used to build {@link TypeRegistry}.
-     */
+
+    /** A Builder is used to build {@link TypeRegistry}. */
     public static class Builder {
       private Builder() {}
 
@@ -801,15 +805,14 @@
         throw new InvalidProtocolBufferException("Invalid Any type.");
       }
       String typeUrl = (String) message.getField(typeUrlField);
-      String typeName = getTypeName(typeUrl);
-      Descriptor type = registry.find(typeName);
+      Descriptor type = registry.getDescriptorForTypeUrl(typeUrl);
       if (type == null) {
         throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
       }
       ByteString content = (ByteString) message.getField(valueField);
       Message contentMessage =
           DynamicMessage.getDefaultInstance(type).getParserForType().parseFrom(content);
-      WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
+      WellKnownTypePrinter printer = wellKnownTypePrinters.get(getTypeName(typeUrl));
       if (printer != null) {
         // If the type is one of the well-known types, we use a special
         // formatting.
@@ -1443,7 +1446,7 @@
         throw new InvalidProtocolBufferException("Missing type url when parsing: " + json);
       }
       String typeUrl = typeUrlElement.getAsString();
-      Descriptor contentType = registry.find(getTypeName(typeUrl));
+      Descriptor contentType = registry.getDescriptorForTypeUrl(typeUrl);
       if (contentType == null) {
         throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
       }
diff --git a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
index 922532a..0c19ad5 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -112,8 +112,9 @@
       };
 
   /**
-   * Returns a {@link Comparator} for {@link Timestamp}s which sorts in increasing chronological
-   * order. Nulls and invalid {@link Timestamp}s are not allowed (see {@link #isValid}).
+   * Returns a {@link Comparator} for {@link Timestamp Timestamps} which sorts in increasing
+   * chronological order. Nulls and invalid {@link Timestamp Timestamps} are not allowed (see
+   * {@link #isValid}).
    */
   public static Comparator<Timestamp> comparator() {
     return COMPARATOR;
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index 9805737..b7b437c 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -34,6 +34,7 @@
 import com.google.protobuf.BoolValue;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.BytesValue;
+import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.DoubleValue;
 import com.google.protobuf.FloatValue;
@@ -834,6 +835,7 @@
     assertRoundTripEquals(message);
   }
 
+
   public void testAnyFields() throws Exception {
     TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build();
     TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build();
diff --git a/js/data.proto b/js/data.proto
index 74a8a99..ca815ca 100644
--- a/js/data.proto
+++ b/js/data.proto
@@ -32,11 +32,11 @@
 
 syntax = "proto2";
 
+package jspb.test;
+
 option java_package = "com.google.apps.jspb.proto";
 option java_multiple_files = true;
 
-package jspb.test;
-
 // legacy data, must be nested
 message data {
   message NestedData {
@@ -48,4 +48,3 @@
 message UnnestedData {
   required string str = 1;
 }
-
diff --git a/js/proto3_test.proto b/js/proto3_test.proto
index 0d073ea..f23e19c 100644
--- a/js/proto3_test.proto
+++ b/js/proto3_test.proto
@@ -35,43 +35,43 @@
 package jspb.test;
 
 message TestProto3 {
-     int32 optional_int32    =  1;
-     int64 optional_int64    =  2;
-    uint32 optional_uint32   =  3;
-    uint64 optional_uint64   =  4;
-    sint32 optional_sint32   =  5;
-    sint64 optional_sint64   =  6;
-   fixed32 optional_fixed32  =  7;
-   fixed64 optional_fixed64  =  8;
-  sfixed32 optional_sfixed32 =  9;
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  sint32 optional_sint32 = 5;
+  sint64 optional_sint64 = 6;
+  fixed32 optional_fixed32 = 7;
+  fixed64 optional_fixed64 = 8;
+  sfixed32 optional_sfixed32 = 9;
   sfixed64 optional_sfixed64 = 10;
-     float optional_float    = 11;
-    double optional_double   = 12;
-      bool optional_bool     = 13;
-    string optional_string   = 14;
-     bytes optional_bytes    = 15;
+  float optional_float = 11;
+  double optional_double = 12;
+  bool optional_bool = 13;
+  string optional_string = 14;
+  bytes optional_bytes = 15;
 
   ForeignMessage optional_foreign_message = 19;
-  Proto3Enum     optional_foreign_enum    = 22;
+  Proto3Enum optional_foreign_enum = 22;
 
-  repeated    int32 repeated_int32    = 31;
-  repeated    int64 repeated_int64    = 32;
-  repeated   uint32 repeated_uint32   = 33;
-  repeated   uint64 repeated_uint64   = 34;
-  repeated   sint32 repeated_sint32   = 35;
-  repeated   sint64 repeated_sint64   = 36;
-  repeated  fixed32 repeated_fixed32  = 37;
-  repeated  fixed64 repeated_fixed64  = 38;
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
   repeated sfixed32 repeated_sfixed32 = 39;
   repeated sfixed64 repeated_sfixed64 = 40;
-  repeated    float repeated_float    = 41;
-  repeated   double repeated_double   = 42;
-  repeated     bool repeated_bool     = 43;
-  repeated   string repeated_string   = 44;
-  repeated    bytes repeated_bytes    = 45;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
 
   repeated ForeignMessage repeated_foreign_message = 49;
-  repeated Proto3Enum     repeated_foreign_enum    = 52;
+  repeated Proto3Enum repeated_foreign_enum = 52;
 
 
   oneof oneof_field {
diff --git a/js/test13.proto b/js/test13.proto
index 4f9d272..b9895d8 100644
--- a/js/test13.proto
+++ b/js/test13.proto
@@ -47,24 +47,24 @@
 
 message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1 {
   optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2
-    a = 1;
+      a = 1;
   optional int32 b = 2;
 }
 
 message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2 {
   optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3
-    a = 1;
+      a = 1;
   optional int32 b = 2;
 }
 
 message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3 {
   optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4
-    a = 1;
+      a = 1;
   optional int32 b = 2;
 }
 
 message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4 {
   optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1
-    a = 1;
+      a = 1;
   optional int32 b = 2;
 }
diff --git a/js/test15.proto b/js/test15.proto
index 602cc2d..b481116 100644
--- a/js/test15.proto
+++ b/js/test15.proto
@@ -30,10 +30,10 @@
 
 syntax = "proto2";
 
-import "test13.proto";
-
 package jspb.filenametest.package1;
 
+import "test13.proto";
+
 extend TestMessage {
   optional int32 b = 2;
 }
diff --git a/js/test2.proto b/js/test2.proto
index b67f93f..e9457e7 100644
--- a/js/test2.proto
+++ b/js/test2.proto
@@ -30,13 +30,13 @@
 
 syntax = "proto2";
 
-option java_package = "com.google.apps.jspb.proto";
-option java_multiple_files = true;
-
 package jspb.test;
 
 import "test.proto";
 
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
 message TestExtensionsMessage {
   optional int32 intfield = 1;
   extensions 100 to max;
diff --git a/js/test3.proto b/js/test3.proto
index 940a552..3fa037d 100644
--- a/js/test3.proto
+++ b/js/test3.proto
@@ -30,11 +30,11 @@
 
 syntax = "proto2";
 
+package jspb.exttest;
+
 option java_package = "com.google.apps.jspb.proto";
 option java_multiple_files = true;
 
-package jspb.exttest;
-
 message TestExtensionsMessage {
   optional int32 intfield = 1;
   extensions 100 to max;
diff --git a/js/test4.proto b/js/test4.proto
index cf2451e..c3c8342 100644
--- a/js/test4.proto
+++ b/js/test4.proto
@@ -30,13 +30,13 @@
 
 syntax = "proto2";
 
-option java_package = "com.google.apps.jspb.proto";
-option java_multiple_files = true;
-
 package jspb.exttest;
 
 import "test3.proto";
 
+option java_package = "com.google.apps.jspb.proto";
+option java_multiple_files = true;
+
 extend TestExtensionsMessage {
   optional ExtensionMessage floating_msg_field_two = 103;
 }
diff --git a/js/test5.proto b/js/test5.proto
index 3497951..db29721 100644
--- a/js/test5.proto
+++ b/js/test5.proto
@@ -30,11 +30,11 @@
 
 syntax = "proto2";
 
+package jspb.exttest.beta;
+
 option java_package = "com.google.apps.jspb.proto";
 option java_multiple_files = true;
 
-package jspb.exttest.beta;
-
 message TestBetaExtensionsMessage {
   extensions 100 to max;
 }
diff --git a/js/test8.proto b/js/test8.proto
index 2ae80da..7dbb6ef 100644
--- a/js/test8.proto
+++ b/js/test8.proto
@@ -30,11 +30,11 @@
 
 syntax = "proto2";
 
+package jspb.exttest.nested;
+
 option java_package = "com.google.apps.jspb.proto";
 option java_multiple_files = true;
 
-package jspb.exttest.nested;
-
 message TestNestedExtensionsMessage {
   optional int32 intfield = 1;
   extensions 100 to max;
diff --git a/js/testbinary.proto b/js/testbinary.proto
index ee4d2df..2e54845 100644
--- a/js/testbinary.proto
+++ b/js/testbinary.proto
@@ -39,66 +39,66 @@
 // to ensure that the binary-format support will handle all field types
 // properly.
 message TestAllTypes {
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
+  optional int32 optional_int32 = 1;
+  optional int64 optional_int64 = 2;
+  optional uint32 optional_uint32 = 3;
+  optional uint64 optional_uint64 = 4;
+  optional sint32 optional_sint32 = 5;
+  optional sint64 optional_sint64 = 6;
+  optional fixed32 optional_fixed32 = 7;
+  optional fixed64 optional_fixed64 = 8;
+  optional sfixed32 optional_sfixed32 = 9;
   optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
+  optional float optional_float = 11;
+  optional double optional_double = 12;
+  optional bool optional_bool = 13;
+  optional string optional_string = 14;
+  optional bytes optional_bytes = 15;
   optional group OptionalGroup = 16 {
     optional int32 a = 17;
   }
 
-  optional ForeignMessage                       optional_foreign_message = 19;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  optional ForeignMessage optional_foreign_message = 19;
+  optional ForeignEnum optional_foreign_enum = 22;
 
   // Repeated
-  repeated    int32 repeated_int32    = 31;
-  repeated    int64 repeated_int64    = 32;
-  repeated   uint32 repeated_uint32   = 33;
-  repeated   uint64 repeated_uint64   = 34;
-  repeated   sint32 repeated_sint32   = 35;
-  repeated   sint64 repeated_sint64   = 36;
-  repeated  fixed32 repeated_fixed32  = 37;
-  repeated  fixed64 repeated_fixed64  = 38;
+  repeated int32 repeated_int32 = 31;
+  repeated int64 repeated_int64 = 32;
+  repeated uint32 repeated_uint32 = 33;
+  repeated uint64 repeated_uint64 = 34;
+  repeated sint32 repeated_sint32 = 35;
+  repeated sint64 repeated_sint64 = 36;
+  repeated fixed32 repeated_fixed32 = 37;
+  repeated fixed64 repeated_fixed64 = 38;
   repeated sfixed32 repeated_sfixed32 = 39;
   repeated sfixed64 repeated_sfixed64 = 40;
-  repeated    float repeated_float    = 41;
-  repeated   double repeated_double   = 42;
-  repeated     bool repeated_bool     = 43;
-  repeated   string repeated_string   = 44;
-  repeated    bytes repeated_bytes    = 45;
+  repeated float repeated_float = 41;
+  repeated double repeated_double = 42;
+  repeated bool repeated_bool = 43;
+  repeated string repeated_string = 44;
+  repeated bytes repeated_bytes = 45;
 
   repeated group RepeatedGroup = 46 {
     optional int32 a = 47;
   }
 
-  repeated ForeignMessage                       repeated_foreign_message = 49;
-  repeated ForeignEnum                          repeated_foreign_enum    = 52;
+  repeated ForeignMessage repeated_foreign_message = 49;
+  repeated ForeignEnum repeated_foreign_enum = 52;
 
   // Packed repeated
-  repeated    int32 packed_repeated_int32    = 61 [packed=true];
-  repeated    int64 packed_repeated_int64    = 62 [packed=true];
-  repeated   uint32 packed_repeated_uint32   = 63 [packed=true];
-  repeated   uint64 packed_repeated_uint64   = 64 [packed=true];
-  repeated   sint32 packed_repeated_sint32   = 65 [packed=true];
-  repeated   sint64 packed_repeated_sint64   = 66 [packed=true];
-  repeated  fixed32 packed_repeated_fixed32  = 67 [packed=true];
-  repeated  fixed64 packed_repeated_fixed64  = 68 [packed=true];
-  repeated sfixed32 packed_repeated_sfixed32 = 69 [packed=true];
-  repeated sfixed64 packed_repeated_sfixed64 = 70 [packed=true];
-  repeated    float packed_repeated_float    = 71 [packed=true];
-  repeated   double packed_repeated_double   = 72 [packed=true];
-  repeated     bool packed_repeated_bool     = 73 [packed=true];
+  repeated int32 packed_repeated_int32 = 61 [packed = true];
+  repeated int64 packed_repeated_int64 = 62 [packed = true];
+  repeated uint32 packed_repeated_uint32 = 63 [packed = true];
+  repeated uint64 packed_repeated_uint64 = 64 [packed = true];
+  repeated sint32 packed_repeated_sint32 = 65 [packed = true];
+  repeated sint64 packed_repeated_sint64 = 66 [packed = true];
+  repeated fixed32 packed_repeated_fixed32 = 67 [packed = true];
+  repeated fixed64 packed_repeated_fixed64 = 68 [packed = true];
+  repeated sfixed32 packed_repeated_sfixed32 = 69 [packed = true];
+  repeated sfixed64 packed_repeated_sfixed64 = 70 [packed = true];
+  repeated float packed_repeated_float = 71 [packed = true];
+  repeated double packed_repeated_double = 72 [packed = true];
+  repeated bool packed_repeated_bool = 73 [packed = true];
 
   oneof oneof_field {
     uint32 oneof_uint32 = 111;
@@ -132,55 +132,54 @@
 }
 
 extend TestExtendable {
-  optional    int32 extend_optional_int32    =  1;
-  optional    int64 extend_optional_int64    =  2;
-  optional   uint32 extend_optional_uint32   =  3;
-  optional   uint64 extend_optional_uint64   =  4;
-  optional   sint32 extend_optional_sint32   =  5;
-  optional   sint64 extend_optional_sint64   =  6;
-  optional  fixed32 extend_optional_fixed32  =  7;
-  optional  fixed64 extend_optional_fixed64  =  8;
-  optional sfixed32 extend_optional_sfixed32 =  9;
+  optional int32 extend_optional_int32 = 1;
+  optional int64 extend_optional_int64 = 2;
+  optional uint32 extend_optional_uint32 = 3;
+  optional uint64 extend_optional_uint64 = 4;
+  optional sint32 extend_optional_sint32 = 5;
+  optional sint64 extend_optional_sint64 = 6;
+  optional fixed32 extend_optional_fixed32 = 7;
+  optional fixed64 extend_optional_fixed64 = 8;
+  optional sfixed32 extend_optional_sfixed32 = 9;
   optional sfixed64 extend_optional_sfixed64 = 10;
-  optional    float extend_optional_float    = 11;
-  optional   double extend_optional_double   = 12;
-  optional     bool extend_optional_bool     = 13;
-  optional   string extend_optional_string   = 14;
-  optional    bytes extend_optional_bytes    = 15;
-  optional ForeignEnum extend_optional_foreign_enum    = 22;
+  optional float extend_optional_float = 11;
+  optional double extend_optional_double = 12;
+  optional bool extend_optional_bool = 13;
+  optional string extend_optional_string = 14;
+  optional bytes extend_optional_bytes = 15;
+  optional ForeignEnum extend_optional_foreign_enum = 22;
 
-  repeated    int32 extend_repeated_int32    = 31;
-  repeated    int64 extend_repeated_int64    = 32;
-  repeated   uint32 extend_repeated_uint32   = 33;
-  repeated   uint64 extend_repeated_uint64   = 34;
-  repeated   sint32 extend_repeated_sint32   = 35;
-  repeated   sint64 extend_repeated_sint64   = 36;
-  repeated  fixed32 extend_repeated_fixed32  = 37;
-  repeated  fixed64 extend_repeated_fixed64  = 38;
+  repeated int32 extend_repeated_int32 = 31;
+  repeated int64 extend_repeated_int64 = 32;
+  repeated uint32 extend_repeated_uint32 = 33;
+  repeated uint64 extend_repeated_uint64 = 34;
+  repeated sint32 extend_repeated_sint32 = 35;
+  repeated sint64 extend_repeated_sint64 = 36;
+  repeated fixed32 extend_repeated_fixed32 = 37;
+  repeated fixed64 extend_repeated_fixed64 = 38;
   repeated sfixed32 extend_repeated_sfixed32 = 39;
   repeated sfixed64 extend_repeated_sfixed64 = 40;
-  repeated    float extend_repeated_float    = 41;
-  repeated   double extend_repeated_double   = 42;
-  repeated     bool extend_repeated_bool     = 43;
-  repeated   string extend_repeated_string   = 44;
-  repeated    bytes extend_repeated_bytes    = 45;
-  repeated ForeignEnum extend_repeated_foreign_enum    = 52;
+  repeated float extend_repeated_float = 41;
+  repeated double extend_repeated_double = 42;
+  repeated bool extend_repeated_bool = 43;
+  repeated string extend_repeated_string = 44;
+  repeated bytes extend_repeated_bytes = 45;
+  repeated ForeignEnum extend_repeated_foreign_enum = 52;
 
-  repeated    int32 extend_packed_repeated_int32    = 61 [packed=true];
-  repeated    int64 extend_packed_repeated_int64    = 62 [packed=true];
-  repeated   uint32 extend_packed_repeated_uint32   = 63 [packed=true];
-  repeated   uint64 extend_packed_repeated_uint64   = 64 [packed=true];
-  repeated   sint32 extend_packed_repeated_sint32   = 65 [packed=true];
-  repeated   sint64 extend_packed_repeated_sint64   = 66 [packed=true];
-  repeated  fixed32 extend_packed_repeated_fixed32  = 67 [packed=true];
-  repeated  fixed64 extend_packed_repeated_fixed64  = 68 [packed=true];
-  repeated sfixed32 extend_packed_repeated_sfixed32 = 69 [packed=true];
-  repeated sfixed64 extend_packed_repeated_sfixed64 = 70 [packed=true];
-  repeated    float extend_packed_repeated_float    = 71 [packed=true];
-  repeated   double extend_packed_repeated_double   = 72 [packed=true];
-  repeated     bool extend_packed_repeated_bool     = 73 [packed=true];
-  repeated ForeignEnum extend_packed_repeated_foreign_enum    = 82
-      [packed=true];
+  repeated int32 extend_packed_repeated_int32 = 61 [packed = true];
+  repeated int64 extend_packed_repeated_int64 = 62 [packed = true];
+  repeated uint32 extend_packed_repeated_uint32 = 63 [packed = true];
+  repeated uint64 extend_packed_repeated_uint64 = 64 [packed = true];
+  repeated sint32 extend_packed_repeated_sint32 = 65 [packed = true];
+  repeated sint64 extend_packed_repeated_sint64 = 66 [packed = true];
+  repeated fixed32 extend_packed_repeated_fixed32 = 67 [packed = true];
+  repeated fixed64 extend_packed_repeated_fixed64 = 68 [packed = true];
+  repeated sfixed32 extend_packed_repeated_sfixed32 = 69 [packed = true];
+  repeated sfixed64 extend_packed_repeated_sfixed64 = 70 [packed = true];
+  repeated float extend_packed_repeated_float = 71 [packed = true];
+  repeated double extend_packed_repeated_double = 72 [packed = true];
+  repeated bool extend_packed_repeated_bool = 73 [packed = true];
+  repeated ForeignEnum extend_packed_repeated_foreign_enum = 82 [packed = true];
 
 }
 
@@ -226,7 +225,7 @@
 
 message TestMapFieldsOptionalKeys {
   optional MapEntryOptionalKeysStringKey map_string_string = 1;
-  optional MapEntryOptionalKeysInt32Key map_int32_string= 8;
+  optional MapEntryOptionalKeysInt32Key map_int32_string = 8;
   optional MapEntryOptionalKeysInt64Key map_int64_string = 9;
   optional MapEntryOptionalKeysBoolKey map_bool_string = 10;
 }
diff --git a/js/testempty.proto b/js/testempty.proto
index 960bce4..6161753 100644
--- a/js/testempty.proto
+++ b/js/testempty.proto
@@ -31,4 +31,3 @@
 syntax = "proto2";
 
 package javatests.com.google.apps.jspb;
-
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 8a9ba3d..5d8f8a1 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -855,7 +855,7 @@
   dependencies: List of other FileDescriptors this FileDescriptor depends on.
   public_dependencies: A list of FileDescriptors, subset of the dependencies
     above, which were declared as "public".
-  message_types_by_name: Dict of message names of their descriptors.
+  message_types_by_name: Dict of message names and their descriptors.
   enum_types_by_name: Dict of enum names and their descriptors.
   extensions_by_name: Dict of extension names and their descriptors.
   services_by_name: Dict of services names and their descriptors.
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py
index ca0bfec..38f76c5 100755
--- a/python/google/protobuf/internal/_parameterized.py
+++ b/python/google/protobuf/internal/_parameterized.py
@@ -145,7 +145,6 @@
 
 __author__ = 'tmarek@google.com (Torsten Marek)'
 
-import collections
 import functools
 import re
 import types
@@ -157,6 +156,13 @@
 
 import six
 
+try:
+  # Since python 3
+  import collections.abc as collections_abc
+except ImportError:
+  # Won't work after python 3.8
+  import collections as collections_abc
+
 ADDR_RE = re.compile(r'\<([a-zA-Z0-9_\-\.]+) object at 0x[a-fA-F0-9]+\>')
 _SEPARATOR = uuid.uuid1().hex
 _FIRST_ARG = object()
@@ -174,12 +180,12 @@
 
 
 def _NonStringIterable(obj):
-  return (isinstance(obj, collections.Iterable) and not
+  return (isinstance(obj, collections_abc.Iterable) and not
           isinstance(obj, six.string_types))
 
 
 def _FormatParameterList(testcase_params):
-  if isinstance(testcase_params, collections.Mapping):
+  if isinstance(testcase_params, collections_abc.Mapping):
     return ', '.join('%s=%s' % (argname, _CleanRepr(value))
                      for argname, value in testcase_params.items())
   elif _NonStringIterable(testcase_params):
@@ -222,7 +228,7 @@
     def MakeBoundParamTest(testcase_params):
       @functools.wraps(test_method)
       def BoundParamTest(self):
-        if isinstance(testcase_params, collections.Mapping):
+        if isinstance(testcase_params, collections_abc.Mapping):
           test_method(self, **testcase_params)
         elif _NonStringIterable(testcase_params):
           test_method(self, *testcase_params)
@@ -291,7 +297,7 @@
     if isinstance(obj, type):
       _ModifyClass(
           obj,
-          list(testcases) if not isinstance(testcases, collections.Sequence)
+          list(testcases) if not isinstance(testcases, collections_abc.Sequence)
           else testcases,
           naming_type)
       return obj
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index 5a54018..845d774 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -914,11 +914,11 @@
     pos = new_pos
 
 
-def _DecodeGroup(buffer, pos):
-  """Decode group.  Returns the UnknownFieldSet and new position."""
+def _DecodeUnknownFieldSet(buffer, pos, end_pos=None):
+  """Decode UnknownFieldSet.  Returns the UnknownFieldSet and new position."""
 
   unknown_field_set = containers.UnknownFieldSet()
-  while 1:
+  while end_pos is None or pos < end_pos:
     (tag_bytes, pos) = ReadTag(buffer, pos)
     (tag, _) = _DecodeVarint(tag_bytes, 0)
     field_number, wire_type = wire_format.UnpackTag(tag)
@@ -945,7 +945,7 @@
     data = buffer[pos:pos+size]
     pos += size
   elif wire_type == wire_format.WIRETYPE_START_GROUP:
-    (data, pos) = _DecodeGroup(buffer, pos)
+    (data, pos) = _DecodeUnknownFieldSet(buffer, pos)
   elif wire_type == wire_format.WIRETYPE_END_GROUP:
     return (0, -1)
   else:
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
index da5dbd9..800d54f 100644
--- a/python/google/protobuf/internal/descriptor_database_test.py
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -44,10 +44,11 @@
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf.internal import no_package_pb2
+from google.protobuf.internal import testing_refleaks
 from google.protobuf import descriptor_database
 
 
-class DescriptorDatabaseTest(unittest.TestCase):
+class DescriptorDatabaseTest(testing_refleaks.BaseTestCase):
 
   def testAdd(self):
     db = descriptor_database.DescriptorDatabase()
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 3244251..4dc2094 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -55,6 +55,7 @@
 from google.protobuf.internal import file_options_test_pb2
 from google.protobuf.internal import more_messages_pb2
 from google.protobuf.internal import no_package_pb2
+from google.protobuf.internal import testing_refleaks
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
@@ -560,7 +561,8 @@
                       str(w[0].message))
 
 
-class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
+class DefaultDescriptorPoolTest(DescriptorPoolTestBase,
+                                testing_refleaks.BaseTestCase):
 
   def setUp(self):
     self.pool = descriptor_pool.Default()
@@ -595,7 +597,8 @@
         unittest_pb2.DESCRIPTOR.services_by_name['TestService'])
 
 
-class CreateDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
+class CreateDescriptorPoolTest(DescriptorPoolTestBase,
+                               testing_refleaks.BaseTestCase):
 
   def setUp(self):
     self.pool = descriptor_pool.DescriptorPool()
@@ -617,7 +620,7 @@
 
 
 class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase,
-                                          unittest.TestCase):
+                                          testing_refleaks.BaseTestCase):
 
   def setUp(self):
     self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
@@ -809,7 +812,7 @@
     test.assertEqual(file_desc, field_desc.file)
 
 
-class AddDescriptorTest(unittest.TestCase):
+class AddDescriptorTest(testing_refleaks.BaseTestCase):
 
   def _TestMessage(self, prefix):
     pool = descriptor_pool.DescriptorPool()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index 5be65c7..7a5a090 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -43,12 +43,13 @@
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import testing_refleaks
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_pool
 from google.protobuf import message_factory
 
 
-class MessageFactoryTest(unittest.TestCase):
+class MessageFactoryTest(testing_refleaks.BaseTestCase):
 
   def setUp(self):
     self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index c3bb066..b66c1e0 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -45,7 +45,6 @@
 __author__ = 'gps@google.com (Gregory P. Smith)'
 
 
-import collections
 import copy
 import math
 import operator
@@ -56,6 +55,13 @@
 import warnings
 
 try:
+  # Since python 3
+  import collections.abc as collections_abc
+except ImportError:
+  # Won't work after python 3.8
+  import collections as collections_abc
+
+try:
   import unittest2 as unittest  # PY26
 except ImportError:
   import unittest
@@ -753,9 +759,9 @@
 
   def testRepeatedFieldsAreSequences(self, message_module):
     m = message_module.TestAllTypes()
-    self.assertIsInstance(m.repeated_int32, collections.MutableSequence)
+    self.assertIsInstance(m.repeated_int32, collections_abc.MutableSequence)
     self.assertIsInstance(m.repeated_nested_message,
-                          collections.MutableSequence)
+                          collections_abc.MutableSequence)
 
   def testRepeatedFieldsNotHashable(self, message_module):
     m = message_module.TestAllTypes()
@@ -2339,11 +2345,11 @@
 
   def testMapsAreMapping(self):
     msg = map_unittest_pb2.TestMap()
-    self.assertIsInstance(msg.map_int32_int32, collections.Mapping)
-    self.assertIsInstance(msg.map_int32_int32, collections.MutableMapping)
-    self.assertIsInstance(msg.map_int32_foreign_message, collections.Mapping)
+    self.assertIsInstance(msg.map_int32_int32, collections_abc.Mapping)
+    self.assertIsInstance(msg.map_int32_int32, collections_abc.MutableMapping)
+    self.assertIsInstance(msg.map_int32_foreign_message, collections_abc.Mapping)
     self.assertIsInstance(msg.map_int32_foreign_message,
-                          collections.MutableMapping)
+                          collections_abc.MutableMapping)
 
   def testMapsCompare(self):
     msg = map_unittest_pb2.TestMap()
diff --git a/python/google/protobuf/internal/test_bad_identifiers.proto b/python/google/protobuf/internal/test_bad_identifiers.proto
index c4860ea..caf86b5 100644
--- a/python/google/protobuf/internal/test_bad_identifiers.proto
+++ b/python/google/protobuf/internal/test_bad_identifiers.proto
@@ -43,10 +43,10 @@
 // Make sure these reasonable extension names don't conflict with internal
 // variables.
 extend TestBadIdentifiers {
-  optional string message = 100 [default="foo"];
-  optional string descriptor = 101 [default="bar"];
-  optional string reflection = 102 [default="baz"];
-  optional string service = 103 [default="qux"];
+  optional string message = 100 [default = "foo"];
+  optional string descriptor = 101 [default = "bar"];
+  optional string reflection = 102 [default = "baz"];
+  optional string service = 103 [default = "qux"];
 }
 
 message AnotherMessage {}
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index 15f3a19..cdab1c6 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -798,6 +798,39 @@
         self.RemoveRedundantZeros(text_format.MessageToString(message)),
         'text_format_unittest_data_oneof_implemented.txt')
 
+  def testPrintUnknownFields(self):
+    message = unittest_pb2.TestAllTypes()
+    message.optional_int32 = 101
+    message.optional_double = 102.0
+    message.optional_string = u'hello'
+    message.optional_bytes = b'103'
+    message.optionalgroup.a = 104
+    message.optional_nested_message.bb = 105
+    all_data = message.SerializeToString()
+    empty_message = unittest_pb2.TestEmptyMessage()
+    empty_message.ParseFromString(all_data)
+    self.assertEqual('1: 101\n'
+                     '12: 4636878028842991616\n'
+                     '14: "hello"\n'
+                     '15: "103"\n'
+                     '16 {\n'
+                     '  17: 104\n'
+                     '}\n'
+                     '18 {\n'
+                     '  1: 105\n'
+                     '}\n',
+                     text_format.MessageToString(empty_message,
+                                                 print_unknown_fields=True))
+    self.assertEqual('1: 101 '
+                     '12: 4636878028842991616 '
+                     '14: "hello" '
+                     '15: "103" '
+                     '16 { 17: 104 } '
+                     '18 { 1: 105 }',
+                     text_format.MessageToString(empty_message,
+                                                 print_unknown_fields=True,
+                                                 as_one_line=True))
+
   def testPrintInIndexOrder(self):
     message = unittest_pb2.TestFieldOrderings()
     # Fields are listed in index order instead of field number.
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
index 6b4df51..4d11662 100644
--- a/python/google/protobuf/internal/well_known_types.py
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -41,11 +41,17 @@
 __author__ = 'jieluo@google.com (Jie Luo)'
 
 import calendar
-import collections
 from datetime import datetime
 from datetime import timedelta
 import six
 
+try:
+  # Since python 3
+  import collections.abc as collections_abc
+except ImportError:
+  # Won't work after python 3.8
+  import collections as collections_abc
+
 from google.protobuf.descriptor import FieldDescriptor
 
 _TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
@@ -88,6 +94,9 @@
     return '/' in self.type_url and self.TypeName() == descriptor.full_name
 
 
+_EPOCH_DATETIME = datetime.utcfromtimestamp(0)
+
+
 class Timestamp(object):
   """Class for Timestamp message type."""
 
@@ -221,8 +230,9 @@
 
   def ToDatetime(self):
     """Converts Timestamp to datetime."""
-    return datetime.utcfromtimestamp(
-        self.seconds + self.nanos / float(_NANOS_PER_SECOND))
+    return _EPOCH_DATETIME + timedelta(
+        seconds=self.seconds, microseconds=_RoundTowardZero(
+            self.nanos, _NANOS_PER_MICROSECOND))
 
   def FromDatetime(self, dt):
     """Converts datetime to Timestamp."""
@@ -780,7 +790,7 @@
     for key, value in dictionary.items():
       _SetStructValue(self.fields[key], value)
 
-collections.MutableMapping.register(Struct)
+collections_abc.MutableMapping.register(Struct)
 
 
 class ListValue(object):
@@ -824,7 +834,7 @@
     list_value.Clear()
     return list_value
 
-collections.MutableSequence.register(ListValue)
+collections_abc.MutableSequence.register(ListValue)
 
 
 WKTBASES = {
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
index 95a7023..61b41ec 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -34,10 +34,16 @@
 
 __author__ = 'jieluo@google.com (Jie Luo)'
 
-import collections
 import datetime
 
 try:
+  # Since python 3
+  import collections.abc as collections_abc
+except ImportError:
+  # Won't work after python 3.8
+  import collections as collections_abc
+
+try:
   import unittest2 as unittest  #PY26
 except ImportError:
   import unittest
@@ -249,6 +255,14 @@
     self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0, 1, 999000),
                      message.ToDatetime())
 
+    dt = datetime.datetime(2555, 2, 22, 1, 2, 3, 456789)
+    message.FromDatetime(dt)
+    self.assertEqual(dt, message.ToDatetime())
+
+    dt = datetime.datetime.max
+    message.FromDatetime(dt)
+    self.assertEqual(dt, message.ToDatetime())
+
   def testDatetimeConversionWithTimezone(self):
     class TZ(datetime.tzinfo):
 
@@ -740,7 +754,7 @@
 
   def testStruct(self):
     struct = struct_pb2.Struct()
-    self.assertIsInstance(struct, collections.Mapping)
+    self.assertIsInstance(struct, collections_abc.Mapping)
     self.assertEqual(0, len(struct))
     struct_class = struct.__class__
 
@@ -749,7 +763,7 @@
     struct['key3'] = True
     struct.get_or_create_struct('key4')['subkey'] = 11.0
     struct_list = struct.get_or_create_list('key5')
-    self.assertIsInstance(struct_list, collections.Sequence)
+    self.assertIsInstance(struct_list, collections_abc.Sequence)
     struct_list.extend([6, 'seven', True, False, None])
     struct_list.add_struct()['subkey2'] = 9
     struct['key6'] = {'subkey': {}}
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index d5813d8..fb55511 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -249,6 +249,7 @@
   }
   ScopedPyObjectPtr value(
       PyEval_CallObject(message_class->AsPyObject(), NULL));
+  Py_DECREF(message_class);
   if (value == NULL) {
     return NULL;
   }
@@ -363,7 +364,7 @@
     return it->second;
   }
   // Create a new descriptor object
-  PyBaseDescriptor* py_descriptor = PyObject_New(
+  PyBaseDescriptor* py_descriptor = PyObject_GC_New(
       PyBaseDescriptor, type);
   if (py_descriptor == NULL) {
     return NULL;
@@ -385,6 +386,8 @@
   Py_INCREF(pool);
   py_descriptor->pool = pool;
 
+  PyObject_GC_Track(py_descriptor);
+
   if (was_created) {
     *was_created = true;
   }
@@ -398,41 +401,53 @@
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyBaseDescriptor* self = reinterpret_cast<PyBaseDescriptor*>(pself);
+  Py_VISIT(self->pool);
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyBaseDescriptor* self = reinterpret_cast<PyBaseDescriptor*>(pself);
+  Py_CLEAR(self->pool);
+  return 0;
+}
+
 static PyGetSetDef Getters[] = {
   {NULL}
 };
 
 PyTypeObject PyBaseDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".DescriptorBase",   // tp_name
-  sizeof(PyBaseDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  (destructor)Dealloc,                  // tp_dealloc
-  0,                                    // tp_print
-  0,                                    // tp_getattr
-  0,                                    // tp_setattr
-  0,                                    // tp_compare
-  0,                                    // tp_repr
-  0,                                    // tp_as_number
-  0,                                    // tp_as_sequence
-  0,                                    // tp_as_mapping
-  0,                                    // tp_hash
-  0,                                    // tp_call
-  0,                                    // tp_str
-  0,                                    // tp_getattro
-  0,                                    // tp_setattro
-  0,                                    // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                   // tp_flags
-  "Descriptors base class",             // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  0,                                    // tp_methods
-  0,                                    // tp_members
-  Getters,                              // tp_getset
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".DescriptorBase",                        // tp_name
+    sizeof(PyBaseDescriptor),                 // tp_basicsize
+    0,                                        // tp_itemsize
+    (destructor)Dealloc,                      // tp_dealloc
+    0,                                        // tp_print
+    0,                                        // tp_getattr
+    0,                                        // tp_setattr
+    0,                                        // tp_compare
+    0,                                        // tp_repr
+    0,                                        // tp_as_number
+    0,                                        // tp_as_sequence
+    0,                                        // tp_as_mapping
+    0,                                        // tp_hash
+    0,                                        // tp_call
+    0,                                        // tp_str
+    0,                                        // tp_getattro
+    0,                                        // tp_setattro
+    0,                                        // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "Descriptors base class",                 // tp_doc
+    GcTraverse,                               // tp_traverse
+    GcClear,                                  // tp_clear
+    0,                                        // tp_richcompare
+    0,                                        // tp_weaklistoffset
+    0,                                        // tp_iter
+    0,                                        // tp_iternext
+    0,                                        // tp_methods
+    0,                                        // tp_members
+    Getters,                                  // tp_getset
 };
 
 }  // namespace descriptor
@@ -1436,45 +1451,45 @@
 }  // namespace file_descriptor
 
 PyTypeObject PyFileDescriptor_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".FileDescriptor",   // tp_name
-  sizeof(PyFileDescriptor),             // tp_basicsize
-  0,                                    // tp_itemsize
-  (destructor)file_descriptor::Dealloc,  // tp_dealloc
-  0,                                    // tp_print
-  0,                                    // tp_getattr
-  0,                                    // tp_setattr
-  0,                                    // tp_compare
-  0,                                    // tp_repr
-  0,                                    // tp_as_number
-  0,                                    // tp_as_sequence
-  0,                                    // tp_as_mapping
-  0,                                    // tp_hash
-  0,                                    // tp_call
-  0,                                    // tp_str
-  0,                                    // tp_getattro
-  0,                                    // tp_setattro
-  0,                                    // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                   // tp_flags
-  "A File Descriptor",                  // tp_doc
-  0,                                    // tp_traverse
-  0,                                    // tp_clear
-  0,                                    // tp_richcompare
-  0,                                    // tp_weaklistoffset
-  0,                                    // tp_iter
-  0,                                    // tp_iternext
-  file_descriptor::Methods,             // tp_methods
-  0,                                    // tp_members
-  file_descriptor::Getters,             // tp_getset
-  &descriptor::PyBaseDescriptor_Type,   // tp_base
-  0,                                    // tp_dict
-  0,                                    // tp_descr_get
-  0,                                    // tp_descr_set
-  0,                                    // tp_dictoffset
-  0,                                    // tp_init
-  0,                                    // tp_alloc
-  0,                                    // tp_new
-  PyObject_Del,                         // tp_free
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".FileDescriptor",                     // tp_name
+    sizeof(PyFileDescriptor),              // tp_basicsize
+    0,                                     // tp_itemsize
+    (destructor)file_descriptor::Dealloc,  // tp_dealloc
+    0,                                     // tp_print
+    0,                                     // tp_getattr
+    0,                                     // tp_setattr
+    0,                                     // tp_compare
+    0,                                     // tp_repr
+    0,                                     // tp_as_number
+    0,                                     // tp_as_sequence
+    0,                                     // tp_as_mapping
+    0,                                     // tp_hash
+    0,                                     // tp_call
+    0,                                     // tp_str
+    0,                                     // tp_getattro
+    0,                                     // tp_setattro
+    0,                                     // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                    // tp_flags
+    "A File Descriptor",                   // tp_doc
+    0,                                     // tp_traverse
+    0,                                     // tp_clear
+    0,                                     // tp_richcompare
+    0,                                     // tp_weaklistoffset
+    0,                                     // tp_iter
+    0,                                     // tp_iternext
+    file_descriptor::Methods,              // tp_methods
+    0,                                     // tp_members
+    file_descriptor::Getters,              // tp_getset
+    &descriptor::PyBaseDescriptor_Type,    // tp_base
+    0,                                     // tp_dict
+    0,                                     // tp_descr_get
+    0,                                     // tp_descr_set
+    0,                                     // tp_dictoffset
+    0,                                     // tp_init
+    0,                                     // tp_alloc
+    0,                                     // tp_new
+    PyObject_GC_Del,                       // tp_free
 };
 
 PyObject* PyFileDescriptor_FromDescriptor(
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index d0038b1..50b290d 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -70,7 +70,7 @@
 // Create a Python DescriptorPool object, but does not fill the "pool"
 // attribute.
 static PyDescriptorPool* _CreateDescriptorPool() {
-  PyDescriptorPool* cpool = PyObject_New(
+  PyDescriptorPool* cpool = PyObject_GC_New(
       PyDescriptorPool, &PyDescriptorPool_Type);
   if (cpool == NULL) {
     return NULL;
@@ -88,6 +88,8 @@
     return NULL;
   }
 
+  PyObject_GC_Track(cpool);
+
   return cpool;
 }
 
@@ -165,7 +167,19 @@
   delete self->descriptor_options;
   delete self->database;
   delete self->pool;
-  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+  Py_TYPE(self)->tp_free(pself);
+}
+
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  Py_VISIT(self->py_message_factory);
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyDescriptorPool* self = reinterpret_cast<PyDescriptorPool*>(pself);
+  Py_CLEAR(self->py_message_factory);
+  return 0;
 }
 
 static PyObject* FindMessageByName(PyObject* self, PyObject* arg) {
@@ -629,45 +643,45 @@
 }  // namespace cdescriptor_pool
 
 PyTypeObject PyDescriptorPool_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".DescriptorPool",  // tp_name
-  sizeof(PyDescriptorPool),            // tp_basicsize
-  0,                                   // tp_itemsize
-  cdescriptor_pool::Dealloc,           // tp_dealloc
-  0,                                   // tp_print
-  0,                                   // tp_getattr
-  0,                                   // tp_setattr
-  0,                                   // tp_compare
-  0,                                   // tp_repr
-  0,                                   // tp_as_number
-  0,                                   // tp_as_sequence
-  0,                                   // tp_as_mapping
-  0,                                   // tp_hash
-  0,                                   // tp_call
-  0,                                   // tp_str
-  0,                                   // tp_getattro
-  0,                                   // tp_setattro
-  0,                                   // tp_as_buffer
-  Py_TPFLAGS_DEFAULT,                  // tp_flags
-  "A Descriptor Pool",                 // tp_doc
-  0,                                   // tp_traverse
-  0,                                   // tp_clear
-  0,                                   // tp_richcompare
-  0,                                   // tp_weaklistoffset
-  0,                                   // tp_iter
-  0,                                   // tp_iternext
-  cdescriptor_pool::Methods,           // tp_methods
-  0,                                   // tp_members
-  0,                                   // tp_getset
-  0,                                   // tp_base
-  0,                                   // tp_dict
-  0,                                   // tp_descr_get
-  0,                                   // tp_descr_set
-  0,                                   // tp_dictoffset
-  0,                                   // tp_init
-  0,                                   // tp_alloc
-  cdescriptor_pool::New,               // tp_new
-  PyObject_Del,                        // tp_free
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".DescriptorPool",                        // tp_name
+    sizeof(PyDescriptorPool),                 // tp_basicsize
+    0,                                        // tp_itemsize
+    cdescriptor_pool::Dealloc,                // tp_dealloc
+    0,                                        // tp_print
+    0,                                        // tp_getattr
+    0,                                        // tp_setattr
+    0,                                        // tp_compare
+    0,                                        // tp_repr
+    0,                                        // tp_as_number
+    0,                                        // tp_as_sequence
+    0,                                        // tp_as_mapping
+    0,                                        // tp_hash
+    0,                                        // tp_call
+    0,                                        // tp_str
+    0,                                        // tp_getattro
+    0,                                        // tp_setattro
+    0,                                        // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "A Descriptor Pool",                      // tp_doc
+    cdescriptor_pool::GcTraverse,             // tp_traverse
+    cdescriptor_pool::GcClear,                // tp_clear
+    0,                                        // tp_richcompare
+    0,                                        // tp_weaklistoffset
+    0,                                        // tp_iter
+    0,                                        // tp_iternext
+    cdescriptor_pool::Methods,                // tp_methods
+    0,                                        // tp_members
+    0,                                        // tp_getset
+    0,                                        // tp_base
+    0,                                        // tp_dict
+    0,                                        // tp_descr_get
+    0,                                        // tp_descr_set
+    0,                                        // tp_dictoffset
+    0,                                        // tp_init
+    0,                                        // tp_alloc
+    cdescriptor_pool::New,                    // tp_new
+    PyObject_GC_Del,                          // tp_free
 };
 
 // This is the DescriptorPool which contains all the definitions from the
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 8289dae..7ce7513 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -50,8 +50,6 @@
 //
 // There is normally one pool per process. We make it a Python object only
 // because it contains many Python references.
-// TODO(amauryfa): See whether such objects can appear in reference cycles, and
-// consider adding support for the cyclic GC.
 //
 // "Methods" that interacts with this DescriptorPool are in the cdescriptor_pool
 // namespace.
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index b4dba6e..9a3caa4 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -310,12 +310,25 @@
   return result.release();
 }
 
-static void Dealloc(CMessageClass *self) {
+static void Dealloc(PyObject* pself) {
+  CMessageClass* self = reinterpret_cast<CMessageClass*>(pself);
   Py_XDECREF(self->py_message_descriptor);
   Py_XDECREF(self->py_message_factory);
-  Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
+  return PyType_Type.tp_dealloc(pself);
 }
 
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  CMessageClass* self = reinterpret_cast<CMessageClass*>(pself);
+  Py_VISIT(self->py_message_descriptor);
+  Py_VISIT(self->py_message_factory);
+  return PyType_Type.tp_traverse(pself, visit, arg);
+}
+
+static int GcClear(PyObject* pself) {
+  // It's important to keep the descriptor and factory alive, until the
+  // C++ message is fully destructed.
+  return PyType_Type.tp_clear(pself);
+}
 
 // This function inserts and empty weakref at the end of the list of
 // subclasses for the main protocol buffer Message class.
@@ -329,10 +342,16 @@
   // https://bugs.python.org/issue17936.
   return 0;
 #else
+#ifdef Py_DEBUG
+  // The code below causes all new subclasses to append an entry, which is never
+  // cleared. This is a small memory leak, which we disable in Py_DEBUG mode
+  // to have stable refcounting checks.
+#else
   PyObject *subclasses = base_type->tp_subclasses;
   if (subclasses && PyList_CheckExact(subclasses)) {
     return PyList_Append(subclasses, kEmptyWeakref);
   }
+#endif  // !Py_DEBUG
   return 0;
 #endif  // PY_MAJOR_VERSION >= 3
 }
@@ -451,44 +470,44 @@
 }  // namespace message_meta
 
 static PyTypeObject _CMessageClass_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  FULL_MODULE_NAME ".MessageMeta",     // tp_name
-  sizeof(CMessageClass),               // tp_basicsize
-  0,                                   // tp_itemsize
-  (destructor)message_meta::Dealloc,   // tp_dealloc
-  0,                                   // tp_print
-  0,                                   // tp_getattr
-  0,                                   // tp_setattr
-  0,                                   // tp_compare
-  0,                                   // tp_repr
-  0,                                   // tp_as_number
-  0,                                   // tp_as_sequence
-  0,                                   // tp_as_mapping
-  0,                                   // tp_hash
-  0,                                   // tp_call
-  0,                                   // tp_str
-  (getattrofunc)message_meta::GetAttr,  // tp_getattro
-  0,                                   // tp_setattro
-  0,                                   // tp_as_buffer
-  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
-  "The metaclass of ProtocolMessages",  // tp_doc
-  0,                                   // tp_traverse
-  0,                                   // tp_clear
-  0,                                   // tp_richcompare
-  0,                                   // tp_weaklistoffset
-  0,                                   // tp_iter
-  0,                                   // tp_iternext
-  0,                                   // tp_methods
-  0,                                   // tp_members
-  message_meta::Getters,               // tp_getset
-  0,                                   // tp_base
-  0,                                   // tp_dict
-  0,                                   // tp_descr_get
-  0,                                   // tp_descr_set
-  0,                                   // tp_dictoffset
-  0,                                   // tp_init
-  0,                                   // tp_alloc
-  message_meta::New,                   // tp_new
+    PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
+    ".MessageMeta",                       // tp_name
+    sizeof(CMessageClass),                // tp_basicsize
+    0,                                    // tp_itemsize
+    message_meta::Dealloc,                // tp_dealloc
+    0,                                    // tp_print
+    0,                                    // tp_getattr
+    0,                                    // tp_setattr
+    0,                                    // tp_compare
+    0,                                    // tp_repr
+    0,                                    // tp_as_number
+    0,                                    // tp_as_sequence
+    0,                                    // tp_as_mapping
+    0,                                    // tp_hash
+    0,                                    // tp_call
+    0,                                    // tp_str
+    (getattrofunc)message_meta::GetAttr,  // tp_getattro
+    0,                                    // tp_setattro
+    0,                                    // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "The metaclass of ProtocolMessages",                            // tp_doc
+    message_meta::GcTraverse,  // tp_traverse
+    message_meta::GcClear,     // tp_clear
+    0,                         // tp_richcompare
+    0,                         // tp_weaklistoffset
+    0,                         // tp_iter
+    0,                         // tp_iternext
+    0,                         // tp_methods
+    0,                         // tp_members
+    message_meta::Getters,     // tp_getset
+    0,                         // tp_base
+    0,                         // tp_dict
+    0,                         // tp_descr_get
+    0,                         // tp_descr_set
+    0,                         // tp_dictoffset
+    0,                         // tp_init
+    0,                         // tp_alloc
+    message_meta::New,         // tp_new
 };
 PyTypeObject* CMessageClass_Type = &_CMessageClass_Type;
 
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 1b0effa..64aafaf 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -129,12 +129,13 @@
   const Descriptor* message_descriptor;
 
   // Owned reference, used to keep the pointer above alive.
+  // This reference must stay alive until all message pointers are destructed.
   PyObject* py_message_descriptor;
 
   // The Python MessageFactory used to create the class. It is needed to resolve
   // fields descriptors, including extensions fields; its C++ MessageFactory is
   // used to instantiate submessages.
-  // We own the reference, because it's important to keep the factory alive.
+  // This reference must stay alive until all message pointers are destructed.
   PyMessageFactory* py_message_factory;
 
   PyObject* AsPyObject() {
diff --git a/python/google/protobuf/pyext/message_factory.cc b/python/google/protobuf/pyext/message_factory.cc
index a5ff318..5fed13b 100644
--- a/python/google/protobuf/pyext/message_factory.cc
+++ b/python/google/protobuf/pyext/message_factory.cc
@@ -69,9 +69,7 @@
   factory->message_factory = message_factory;
 
   factory->pool = pool;
-  // TODO(amauryfa): When the MessageFactory is not created from the
-  // DescriptorPool this reference should be owned, not borrowed.
-  // Py_INCREF(pool);
+  Py_INCREF(pool);
 
   factory->classes_by_descriptor = new PyMessageFactory::ClassesByMessageMap();
 
@@ -107,19 +105,37 @@
 static void Dealloc(PyObject* pself) {
   PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
 
-  // TODO(amauryfa): When the MessageFactory is not created from the
-  // DescriptorPool this reference should be owned, not borrowed.
-  // Py_CLEAR(self->pool);
   typedef PyMessageFactory::ClassesByMessageMap::iterator iterator;
   for (iterator it = self->classes_by_descriptor->begin();
        it != self->classes_by_descriptor->end(); ++it) {
-    Py_DECREF(it->second);
+    Py_CLEAR(it->second);
   }
   delete self->classes_by_descriptor;
   delete self->message_factory;
+  Py_CLEAR(self->pool);
   Py_TYPE(self)->tp_free(pself);
 }
 
+static int GcTraverse(PyObject* pself, visitproc visit, void* arg) {
+  PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
+  Py_VISIT(self->pool);
+  for (const auto& desc_and_class : *self->classes_by_descriptor) {
+    Py_VISIT(desc_and_class.second);
+  }
+  return 0;
+}
+
+static int GcClear(PyObject* pself) {
+  PyMessageFactory* self = reinterpret_cast<PyMessageFactory*>(pself);
+  // Here it's important to not clear self->pool, so that the C++ DescriptorPool
+  // is still alive when self->message_factory is destructed.
+  for (auto& desc_and_class : *self->classes_by_descriptor) {
+    Py_CLEAR(desc_and_class.second);
+  }
+
+  return 0;
+}
+
 // Add a message class to our database.
 int RegisterMessageClass(PyMessageFactory* self,
                          const Descriptor* message_descriptor,
@@ -234,44 +250,44 @@
 
 PyTypeObject PyMessageFactory_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME
-    ".MessageFactory",                        // tp_name
-    sizeof(PyMessageFactory),                 // tp_basicsize
-    0,                                        // tp_itemsize
-    message_factory::Dealloc,                 // tp_dealloc
-    0,                                        // tp_print
-    0,                                        // tp_getattr
-    0,                                        // tp_setattr
-    0,                                        // tp_compare
-    0,                                        // tp_repr
-    0,                                        // tp_as_number
-    0,                                        // tp_as_sequence
-    0,                                        // tp_as_mapping
-    0,                                        // tp_hash
-    0,                                        // tp_call
-    0,                                        // tp_str
-    0,                                        // tp_getattro
-    0,                                        // tp_setattro
-    0,                                        // tp_as_buffer
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
-    "A static Message Factory",               // tp_doc
-    0,                                        // tp_traverse
-    0,                                        // tp_clear
-    0,                                        // tp_richcompare
-    0,                                        // tp_weaklistoffset
-    0,                                        // tp_iter
-    0,                                        // tp_iternext
-    message_factory::Methods,                 // tp_methods
-    0,                                        // tp_members
-    message_factory::Getters,                 // tp_getset
-    0,                                        // tp_base
-    0,                                        // tp_dict
-    0,                                        // tp_descr_get
-    0,                                        // tp_descr_set
-    0,                                        // tp_dictoffset
-    0,                                        // tp_init
-    0,                                        // tp_alloc
-    message_factory::New,                     // tp_new
-    PyObject_Del,                             // tp_free
+    ".MessageFactory",         // tp_name
+    sizeof(PyMessageFactory),  // tp_basicsize
+    0,                         // tp_itemsize
+    message_factory::Dealloc,  // tp_dealloc
+    0,                         // tp_print
+    0,                         // tp_getattr
+    0,                         // tp_setattr
+    0,                         // tp_compare
+    0,                         // tp_repr
+    0,                         // tp_as_number
+    0,                         // tp_as_sequence
+    0,                         // tp_as_mapping
+    0,                         // tp_hash
+    0,                         // tp_call
+    0,                         // tp_str
+    0,                         // tp_getattro
+    0,                         // tp_setattro
+    0,                         // tp_as_buffer
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,  // tp_flags
+    "A static Message Factory",                                     // tp_doc
+    message_factory::GcTraverse,  // tp_traverse
+    message_factory::GcClear,     // tp_clear
+    0,                            // tp_richcompare
+    0,                            // tp_weaklistoffset
+    0,                            // tp_iter
+    0,                            // tp_iternext
+    message_factory::Methods,     // tp_methods
+    0,                            // tp_members
+    message_factory::Getters,     // tp_getset
+    0,                            // tp_base
+    0,                            // tp_dict
+    0,                            // tp_descr_get
+    0,                            // tp_descr_set
+    0,                            // tp_dictoffset
+    0,                            // tp_init
+    0,                            // tp_alloc
+    message_factory::New,         // tp_new
+    PyObject_GC_Del,              // tp_free
 };
 
 bool InitMessageFactory() {
diff --git a/python/google/protobuf/pyext/message_factory.h b/python/google/protobuf/pyext/message_factory.h
index 06444b0..515c29c 100644
--- a/python/google/protobuf/pyext/message_factory.h
+++ b/python/google/protobuf/pyext/message_factory.h
@@ -57,9 +57,8 @@
   // The C++ one creates messages, when the Python one creates classes.
   MessageFactory* message_factory;
 
-  // borrowed reference to a Python DescriptorPool.
-  // TODO(amauryfa): invert the dependency: the MessageFactory owns the
-  // DescriptorPool, not the opposite.
+  // Owned reference to a Python DescriptorPool.
+  // This reference must stay until the message_factory is destructed.
   PyDescriptorPool* pool;
 
   // Make our own mapping to retrieve Python classes from C++ descriptors.
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index f0b6e5d..d8088a1 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -233,13 +233,12 @@
 static PyObject* AppendMethod(PyObject* pself, PyObject* value) {
   RepeatedCompositeContainer* self =
       reinterpret_cast<RepeatedCompositeContainer*>(pself);
-  PyObject* py_cmsg = AddMessage(self, value);
+  ScopedPyObjectPtr py_cmsg(AddMessage(self, value));
   if (py_cmsg == nullptr) {
     return nullptr;
   }
 
-  if (PyList_Append(self->child_messages, py_cmsg) < 0) {
-    Py_DECREF(py_cmsg);
+  if (PyList_Append(self->child_messages, py_cmsg.get()) < 0) {
     return nullptr;
   }
 
@@ -258,7 +257,7 @@
     return nullptr;
   }
 
-  PyObject* py_cmsg = AddMessage(self, value);
+  ScopedPyObjectPtr py_cmsg(AddMessage(self, value));
   if (py_cmsg == nullptr) {
     return nullptr;
   }
@@ -277,7 +276,7 @@
     }
   }
 
-  if (PyList_Insert(self->child_messages, index, py_cmsg) < 0) {
+  if (PyList_Insert(self->child_messages, index, py_cmsg.get()) < 0) {
     return nullptr;
   }
   Py_RETURN_NONE;
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 1d965fa..557c7e2 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -51,6 +51,7 @@
   long = int  # pylint: disable=redefined-builtin,invalid-name
 
 # pylint: disable=g-import-not-at-top
+from google.protobuf.internal import decoder
 from google.protobuf.internal import type_checkers
 from google.protobuf import descriptor
 from google.protobuf import text_encoding
@@ -128,7 +129,8 @@
                     use_field_number=False,
                     descriptor_pool=None,
                     indent=0,
-                    message_formatter=None):
+                    message_formatter=None,
+                    print_unknown_fields=False):
   # type: (...) -> str
   """Convert protobuf message to text format.
 
@@ -159,6 +161,7 @@
     message_formatter: A function(message, indent, as_one_line): unicode|None
       to custom format selected sub-messages (usually based on message type).
       Use to pretty print parts of the protobuf for easier diffing.
+    print_unknown_fields: If True, unknown fields will be printed.
 
   Returns:
     A string of the text formatted protocol buffer message.
@@ -167,7 +170,8 @@
   printer = _Printer(out, indent, as_utf8, as_one_line,
                      use_short_repeated_primitives, pointy_brackets,
                      use_index_order, float_format, use_field_number,
-                     descriptor_pool, message_formatter)
+                     descriptor_pool, message_formatter,
+                     print_unknown_fields=print_unknown_fields)
   printer.PrintMessage(message)
   result = out.getvalue()
   out.close()
@@ -203,11 +207,19 @@
                  float_format=None,
                  use_field_number=False,
                  descriptor_pool=None,
-                 message_formatter=None):
-  printer = _Printer(out, indent, as_utf8, as_one_line,
-                     use_short_repeated_primitives, pointy_brackets,
-                     use_index_order, float_format, use_field_number,
-                     descriptor_pool, message_formatter)
+                 message_formatter=None,
+                 print_unknown_fields=False):
+  printer = _Printer(
+      out=out, indent=indent, as_utf8=as_utf8,
+      as_one_line=as_one_line,
+      use_short_repeated_primitives=use_short_repeated_primitives,
+      pointy_brackets=pointy_brackets,
+      use_index_order=use_index_order,
+      float_format=float_format,
+      use_field_number=use_field_number,
+      descriptor_pool=descriptor_pool,
+      message_formatter=message_formatter,
+      print_unknown_fields=print_unknown_fields)
   printer.PrintMessage(message)
 
 
@@ -221,12 +233,14 @@
                pointy_brackets=False,
                use_index_order=False,
                float_format=None,
-               message_formatter=None):
+               message_formatter=None,
+               print_unknown_fields=False):
   """Print a single field name/value pair."""
   printer = _Printer(out, indent, as_utf8, as_one_line,
                      use_short_repeated_primitives, pointy_brackets,
                      use_index_order, float_format,
-                     message_formatter=message_formatter)
+                     message_formatter=message_formatter,
+                     print_unknown_fields=print_unknown_fields)
   printer.PrintField(field, value)
 
 
@@ -240,12 +254,14 @@
                     pointy_brackets=False,
                     use_index_order=False,
                     float_format=None,
-                    message_formatter=None):
+                    message_formatter=None,
+                    print_unknown_fields=False):
   """Print a single field value (not including name)."""
   printer = _Printer(out, indent, as_utf8, as_one_line,
                      use_short_repeated_primitives, pointy_brackets,
                      use_index_order, float_format,
-                     message_formatter=message_formatter)
+                     message_formatter=message_formatter,
+                     print_unknown_fields=print_unknown_fields)
   printer.PrintFieldValue(field, value)
 
 
@@ -274,6 +290,11 @@
   return message_type()
 
 
+# These values must match WireType enum in google/protobuf/wire_format.h.
+WIRETYPE_LENGTH_DELIMITED = 2
+WIRETYPE_START_GROUP = 3
+
+
 class _Printer(object):
   """Text format printer for protocol message."""
 
@@ -288,7 +309,8 @@
                float_format=None,
                use_field_number=False,
                descriptor_pool=None,
-               message_formatter=None):
+               message_formatter=None,
+               print_unknown_fields=False):
     """Initialize the Printer.
 
     Floating point values can be formatted compactly with 15 digits of
@@ -317,6 +339,7 @@
       message_formatter: A function(message, indent, as_one_line): unicode|None
         to custom format selected sub-messages (usually based on message type).
         Use to pretty print parts of the protobuf for easier diffing.
+      print_unknown_fields: If True, unknown fields will be printed.
     """
     self.out = out
     self.indent = indent
@@ -329,6 +352,7 @@
     self.use_field_number = use_field_number
     self.descriptor_pool = descriptor_pool
     self.message_formatter = message_formatter
+    self.print_unknown_fields = print_unknown_fields
 
   def _TryPrintAsAnyMessage(self, message):
     """Serializes if message is a google.protobuf.Any field."""
@@ -392,6 +416,64 @@
       else:
         self.PrintField(field, value)
 
+    if self.print_unknown_fields:
+      self._PrintUnknownFields(message.UnknownFields())
+
+  def _PrintUnknownFields(self, unknown_fields):
+    """Print unknown fields."""
+    out = self.out
+    for field in unknown_fields:
+      out.write(' ' * self.indent)
+      out.write(str(field.field_number))
+      if field.wire_type == WIRETYPE_START_GROUP:
+        if self.as_one_line:
+          out.write(' { ')
+        else:
+          out.write(' {\n')
+          self.indent += 2
+
+        self._PrintUnknownFields(field.data)
+
+        if self.as_one_line:
+          out.write('} ')
+        else:
+          out.write('}\n')
+          self.indent -= 2
+      elif field.wire_type == WIRETYPE_LENGTH_DELIMITED:
+        try:
+          # If this field is parseable as a Message, it is probably
+          # an embedded message.
+          # pylint: disable=protected-access
+          (embedded_unknown_message, pos) = decoder._DecodeUnknownFieldSet(
+              memoryview(field.data), 0, len(field.data))
+        except Exception:    # pylint: disable=broad-except
+          pos = 0
+
+        if pos == len(field.data):
+          if self.as_one_line:
+            out.write(' { ')
+          else:
+            out.write(' {\n')
+            self.indent += 2
+
+          self._PrintUnknownFields(embedded_unknown_message)
+
+          if self.as_one_line:
+            out.write('} ')
+          else:
+            out.write('}\n')
+            self.indent -= 2
+        else:
+          # A string or bytes field. self.as_utf8 may not work.
+          out.write(': \"')
+          out.write(text_encoding.CEscape(field.data, False))
+          out.write('\" ' if self.as_one_line else '\"\n')
+      else:
+        # varint, fixed32, fixed64
+        out.write(': ')
+        out.write(str(field.data))
+        out.write(' ' if self.as_one_line else '\n')
+
   def _PrintFieldName(self, field):
     """Print field name."""
     out = self.out
diff --git a/src/Makefile.am b/src/Makefile.am
index 169d923..6f64b96 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -131,7 +131,6 @@
   google/protobuf/unknown_field_set.h                            \
   google/protobuf/wire_format.h                                  \
   google/protobuf/wire_format_lite.h                             \
-  google/protobuf/wire_format_lite_inl.h                         \
   google/protobuf/wrappers.pb.h                                  \
   google/protobuf/io/coded_stream.h                              \
   $(GZHEADERS)                                                   \
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index fac9eba..3515411 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -190,7 +190,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Any::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -216,8 +215,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 5a8bb22..1b56305 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -296,7 +296,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Api::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -367,8 +366,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -900,7 +898,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Method::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -965,8 +962,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1468,7 +1464,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Mixin::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1494,8 +1489,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index b728470..9220ddb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -72,6 +72,7 @@
   variables_["short_name"] = descriptor_->name();
   variables_["enumbase"] = options_.proto_h ? " : int" : "";
   variables_["nested_name"] = descriptor_->name();
+  variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
   variables_["prefix"] =
       (descriptor_->containing_type() == NULL) ? "" : classname_ + "_";
 }
@@ -192,13 +193,13 @@
 
 void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("typedef $classname$ $nested_name$;\n");
+  format("typedef $classname$ $resolved_name$;\n");
 
   for (int j = 0; j < descriptor_->value_count(); j++) {
     std::string deprecated_attr = DeprecatedAttribute(
         options_, descriptor_->value(j)->options().deprecated());
     format(
-        "$1$static constexpr $nested_name$ ${2$$3$$}$ =\n"
+        "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n"
         "  $classname$_$3$;\n",
         deprecated_attr, descriptor_->value(j),
         EnumValueName(descriptor_->value(j)));
@@ -208,9 +209,9 @@
       "static inline bool $nested_name$_IsValid(int value) {\n"
       "  return $classname$_IsValid(value);\n"
       "}\n"
-      "static constexpr $nested_name$ ${1$$nested_name$_MIN$}$ =\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n"
       "  $classname$_$nested_name$_MIN;\n"
-      "static constexpr $nested_name$ ${1$$nested_name$_MAX$}$ =\n"
+      "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n"
       "  $classname$_$nested_name$_MAX;\n",
       descriptor_);
   if (generate_array_size_) {
@@ -231,7 +232,7 @@
       // version below.  Would this break our compatibility guarantees?
       format(
           "static inline const std::string& "
-          "$nested_name$_Name($nested_name$ value) {"
+          "$nested_name$_Name($resolved_name$ value) {"
           "\n"
           "  return $classname$_Name(value);\n"
           "}\n");
@@ -243,7 +244,7 @@
           "template<typename T>\n"
           "static inline const std::string& $nested_name$_Name(T enum_t_value) "
           "{\n"
-          "  static_assert(::std::is_same<T, $nested_name$>::value ||\n"
+          "  static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
           "    ::std::is_integral<T>::value,\n"
           "    \"Incorrect type passed to function $nested_name$_Name.\");\n"
           "  return $classname$_Name(enum_t_value);\n"
@@ -251,7 +252,7 @@
     }
     format(
         "static inline bool $nested_name$_Parse(const std::string& name,\n"
-        "    $nested_name$* value) {\n"
+        "    $resolved_name$* value) {\n"
         "  return $classname$_Parse(name, value);\n"
         "}\n");
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 6bcbb3a..b03ca83 100644
--- a/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -93,7 +93,7 @@
   variables_["extendee"] = ExtendeeClassName(descriptor_);
   variables_["type_traits"] = type_traits_;
   std::string name = descriptor_->name();
-  variables_["name"] = name;
+  variables_["name"] = ResolveKeyword(name);
   variables_["constant_name"] = FieldConstantName(descriptor_);
   variables_["field_type"] =
       StrCat(static_cast<int>(descriptor_->type()));
@@ -102,7 +102,7 @@
   std::string scope =
       IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
   variables_["scope"] = scope;
-  std::string scoped_name = scope + name;
+  std::string scoped_name = scope + ResolveKeyword(name);
   variables_["scoped_name"] = scoped_name;
   variables_["number"] = StrCat(descriptor_->number());
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 4e19fdc..21af61f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -319,12 +319,12 @@
   if (parent) res += ClassName(parent) + "_";
   res += descriptor->name();
   if (IsMapEntryMessage(descriptor)) res += "_DoNotUse";
-  return res;
+  return ResolveKeyword(res);
 }
 
 std::string ClassName(const EnumDescriptor* enum_descriptor) {
   if (enum_descriptor->containing_type() == nullptr) {
-    return enum_descriptor->name();
+    return ResolveKeyword(enum_descriptor->name());
   } else {
     return ClassName(enum_descriptor->containing_type()) + "_" +
            enum_descriptor->name();
@@ -395,6 +395,13 @@
                                                             : "::MessageLite");
 }
 
+std::string ResolveKeyword(const string& name) {
+  if (kKeywords.count(name) > 0) {
+    return name + "_";
+  }
+  return name;
+}
+
 std::string FieldName(const FieldDescriptor* field) {
   std::string result = field->name();
   LowerString(&result);
@@ -1345,8 +1352,6 @@
     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<std::string, std::string> vars;
     SetCommonVars(options_, &vars);
     format_.AddMap(vars);
@@ -1365,93 +1370,14 @@
 
     format_(
         "const char* $classname$::_InternalParse(const char* ptr, "
-        "$pi_ns$::ParseContext* ctx) {\n"
-        "  $p_ns$::Arena* arena = GetArena(); (void)arena;\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");
-
+        "$pi_ns$::ParseContext* ctx) {\n");
     format_.Indent();
-    format_.Indent();
-    format_.Indent();
-
-    for (const auto* field : ordered_fields) {
-      // 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.
-      std::string def;
-      {
-        DebugStringOptions options;
-        options.elide_group_body = true;
-        options.elide_oneof_body = true;
-        def = field->DebugStringWithOptions(options);
-        def = def.substr(0, def.find_first_of('\n'));
-      }
-      format_(
-          "// $1$\n"
-          "case $2$: {\n",
-          def, field->number());
-      format_.Indent();
-      GenerateCaseBody(field);
-      format_.Outdent();
-      format_("}\n");  // case
-    }                  // for fields
-
-    // Default case
-    format_("default: {\n");
-    if (!ordered_fields.empty()) format_("handle_unusual:\n");
-    format_(
-        "  if ((tag & 7) == 4 || tag == 0) {\n"
-        "    ctx->SetLastTag(tag);\n"
-        "    return ptr;\n"
-        "  }\n");
-    if (IsMapEntryMessage(descriptor)) {
-      format_("  break;\n");
-    } else {
-      if (descriptor->extension_range_count() > 0) {
-        format_("if (");
-        for (int i = 0; i < descriptor->extension_range_count(); i++) {
-          const Descriptor::ExtensionRange* range =
-              descriptor->extension_range(i);
-          if (i > 0) format_(" ||\n    ");
-
-          uint32 start_tag = WireFormatLite::MakeTag(
-              range->start, static_cast<WireFormatLite::WireType>(0));
-          uint32 end_tag = WireFormatLite::MakeTag(
-              range->end, static_cast<WireFormatLite::WireType>(0));
-
-          if (range->end > FieldDescriptor::kMaxNumber) {
-            format_("($1$u <= tag)", start_tag);
-          } else {
-            format_("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
-          }
-        }
-        format_(") {\n");
-        format_(
-            "  ptr = _extensions_.ParseField(tag, ptr, \n"
-            "      internal_default_instance(), &_internal_metadata_, "
-            "ctx);\n"
-            "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
-            "  break;\n"
-            "}\n");
-      }
-      format_(
-          "  ptr = UnknownFieldParse(tag,\n"
-          "    _internal_metadata_.mutable_unknown_fields(), ptr, ctx);\n"
-          "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
-          "  break;\n");
+    if (descriptor->file()->options().cc_enable_arenas()) {
+      format_("$p_ns$::Arena* arena = GetArenaNoVirtual(); (void)arena;\n");
     }
-    format_("}\n");  // default case
+    GenerateParseLoop(descriptor, ordered_fields);
     format_.Outdent();
-    format_.Outdent();
-    format_.Outdent();
-    format_(
-        "    }  // switch\n"
-        "  }  // while\n"
-        "  return ptr;\n"
-        "}\n");
+    format_("}\n");
   }
 
  private:
@@ -1469,18 +1395,25 @@
               field_name.substr(2));  // remove ", "
       field_name = ", kFieldName";
     }
-    format_("if (arena != nullptr) {\n");
     if (HasFieldPresence(field->file())) {
-      format_("  HasBitSetters::set_has_$1$(this);\n", FieldName(field));
+      format_("HasBitSetters::set_has_$1$(this);\n", FieldName(field));
     }
+    string default_string =
+        field->default_value_string().empty()
+            ? "::" + ProtobufNamespace(options_) +
+                  "::internal::GetEmptyStringAlreadyInited()"
+            : QualifiedClassName(field->containing_type(), options_) +
+                  "::" + MakeDefaultName(field) + ".get()";
     format_(
+        "if (arena != nullptr) {\n"
         "  ptr = $pi_ns$::InlineCopyIntoArenaString$1$(&$2$_, ptr, ctx, "
         "  arena$3$);\n"
         "} else {\n"
-        "  ptr = $pi_ns$::InlineGreedyStringParser$1$($4$_$2$(), ptr, ctx$3$);"
+        "  ptr = "
+        "$pi_ns$::InlineGreedyStringParser$1$($2$_.MutableNoArenaNoDefault(&$4$"
+        "), ptr, ctx$3$);"
         "\n}\n",
-        utf8, FieldName(field), field_name,
-        field->is_repeated() ? "add" : "mutable");
+        utf8, FieldName(field), field_name, default_string);
   }
 
   void GenerateStrings(const FieldDescriptor* field, bool check_utf8) {
@@ -1766,6 +1699,93 @@
       GenerateCaseBody(wiretype, field);
     }
   }
+
+  void GenerateParseLoop(
+      const Descriptor* descriptor,
+      const std::vector<const FieldDescriptor*>& ordered_fields) {
+    format_(
+        "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");
+
+    format_.Indent();
+    format_.Indent();
+
+    for (const auto* field : ordered_fields) {
+      // 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.
+      std::string def;
+      {
+        DebugStringOptions options;
+        options.elide_group_body = true;
+        options.elide_oneof_body = true;
+        def = field->DebugStringWithOptions(options);
+        def = def.substr(0, def.find_first_of('\n'));
+      }
+      format_(
+          "// $1$\n"
+          "case $2$: {\n",
+          def, field->number());
+      format_.Indent();
+      GenerateCaseBody(field);
+      format_.Outdent();
+      format_("}\n");  // case
+    }                  // for fields
+
+    // Default case
+    format_("default: {\n");
+    if (!ordered_fields.empty()) format_("handle_unusual:\n");
+    format_(
+        "  if ((tag & 7) == 4 || tag == 0) {\n"
+        "    ctx->SetLastTag(tag);\n"
+        "    return ptr;\n"
+        "  }\n");
+    if (IsMapEntryMessage(descriptor)) {
+      format_("  break;\n");
+    } else {
+      if (descriptor->extension_range_count() > 0) {
+        format_("if (");
+        for (int i = 0; i < descriptor->extension_range_count(); i++) {
+          const Descriptor::ExtensionRange* range =
+              descriptor->extension_range(i);
+          if (i > 0) format_(" ||\n    ");
+
+          uint32 start_tag = WireFormatLite::MakeTag(
+              range->start, static_cast<WireFormatLite::WireType>(0));
+          uint32 end_tag = WireFormatLite::MakeTag(
+              range->end, static_cast<WireFormatLite::WireType>(0));
+
+          if (range->end > FieldDescriptor::kMaxNumber) {
+            format_("($1$u <= tag)", start_tag);
+          } else {
+            format_("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
+          }
+        }
+        format_(") {\n");
+        format_(
+            "  ptr = _extensions_.ParseField(tag, ptr, \n"
+            "      internal_default_instance(), &_internal_metadata_, "
+            "ctx);\n"
+            "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
+            "  break;\n"
+            "}\n");
+      }
+      format_(
+          "  ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);\n"
+          "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
+          "  break;\n");
+    }
+    format_("}\n");  // default case
+    format_.Outdent();
+    format_.Outdent();
+    format_(
+        "  }  // switch\n"
+        "}  // while\n"
+        "return ptr;\n");
+  }
 };
 
 void GenerateParserLoop(const Descriptor* descriptor, const Options& options,
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 2e4ba4f..895749d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -143,6 +143,9 @@
 std::string SuperClassName(const Descriptor* descriptor,
                            const Options& options);
 
+// Adds an underscore if necessary to prevent conflicting with a keyword.
+std::string ResolveKeyword(const string& name);
+
 // Get the (unqualified) name that should be used for this field in C++ code.
 // The name is coerced to lower-case to emulate proto1 behavior.  People
 // should be using lowercase-with-underscores style for proto field names
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 2854398..bd17215 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -975,9 +975,11 @@
         GOOGLE_CHECK(suffix == "UTF8Verify");
         format(
             "  bool ValidateKey() const {\n"
+            "#ifndef NDEBUG\n"
             "    ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n"
             "       key().data(), key().size(), ::$proto_ns$::internal::"
             "WireFormatLite::PARSE, \"$1$\");\n"
+            "#endif\n"
             "    return true;\n"
             " }\n",
             descriptor_->field(0)->full_name());
@@ -999,9 +1001,11 @@
         GOOGLE_CHECK(suffix == "UTF8Verify");
         format(
             "  bool ValidateValue() const {\n"
+            "#ifndef NDEBUG\n"
             "    ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n"
             "       value().data(), value().size(), ::$proto_ns$::internal::"
             "WireFormatLite::PARSE, \"$1$\");\n"
+            "#endif\n"
             "    return true;\n"
             " }\n",
             descriptor_->field(1)->full_name());
@@ -1324,7 +1328,7 @@
     const Descriptor* nested_type = descriptor_->nested_type(i);
     if (!IsMapEntryMessage(nested_type)) {
       format.Set("nested_full_name", ClassName(nested_type, false));
-      format.Set("nested_name", nested_type->name());
+      format.Set("nested_name", ResolveKeyword(nested_type->name()));
       format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n",
              nested_type);
     }
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 0f15f39..4797108 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -35,11 +35,13 @@
 // This file tests that various identifiers work as field and type names even
 // though the same identifiers are used internally by the C++ code generator.
 
+// LINT: LEGACY_NAMES
+
 syntax = "proto2";
 
 // Some generic_services option(s) added automatically.
 // See:  http://go/proto2-generic-services-default
-option cc_generic_services = true;     // auto-added
+option cc_generic_services = true; // auto-added
 
 // We don't put this in a package within proto2 because we need to make sure
 // that the generated code doesn't depend on being in the proto2 namespace.
@@ -55,17 +57,29 @@
   optional int32 output = 2;
   optional string length = 3;
   repeated int32 i = 4;
-  repeated string new_element = 5 [ctype=STRING_PIECE];
+  repeated string new_element = 5 [ctype = STRING_PIECE];
   optional int32 total_size = 6;
   optional int32 tag = 7;
 
   enum TestEnum { FOO = 0; }
-  message Data1 { repeated int32 data = 1; }
-  message Data2 { repeated TestEnum data = 1; }
-  message Data3 { repeated string data = 1; }
-  message Data4 { repeated Data4 data = 1; }
-  message Data5 { repeated string data = 1 [ctype=STRING_PIECE]; }
-  message Data6 { repeated string data = 1 [ctype=CORD]; }
+  message Data1 {
+    repeated int32 data = 1;
+  }
+  message Data2 {
+    repeated TestEnum data = 1;
+  }
+  message Data3 {
+    repeated string data = 1;
+  }
+  message Data4 {
+    repeated Data4 data = 1;
+  }
+  message Data5 {
+    repeated string data = 1 [ctype = STRING_PIECE];
+  }
+  message Data6 {
+    repeated string data = 1 [ctype = CORD];
+  }
 
   optional int32 source = 8;
   optional int32 value = 9;
@@ -91,10 +105,10 @@
   optional uint32 reflection = 27;
 
   message Cord {}
-  optional string some_cord = 28 [ctype=CORD];
+  optional string some_cord = 28 [ctype = CORD];
 
   message StringPiece {}
-  optional string some_string_piece = 29 [ctype=STRING_PIECE];
+  optional string some_string_piece = 29 [ctype = STRING_PIECE];
 
   // Some keywords.
   optional uint32 int = 30;
@@ -125,14 +139,15 @@
   extensions 1000 to max;  // NO_PROTO3
 }
 
-message TestConflictingSymbolNamesExtension {                    // NO_PROTO3
-  extend TestConflictingSymbolNames {                            // NO_PROTO3
-    repeated int32 repeated_int32_ext = 20423638 [packed=true];  // NO_PROTO3
-  }                                                              // NO_PROTO3
-}                                                                // NO_PROTO3
+message TestConflictingSymbolNamesExtension {                      // NO_PROTO3
+  extend TestConflictingSymbolNames {                              // NO_PROTO3
+    repeated int32 repeated_int32_ext = 20423638 [packed = true];  // NO_PROTO3
+  }                                                                // NO_PROTO3
+}  // NO_PROTO3
 
 message TestConflictingEnumNames {  // NO_PROTO3
-  enum NestedConflictingEnum {      // NO_PROTO3
+  enum while {                      // NO_PROTO3
+    default = 0;                    // NO_PROTO3
     and = 1;                        // NO_PROTO3
     class = 2;                      // NO_PROTO3
     int = 3;                        // NO_PROTO3
@@ -140,18 +155,26 @@
     XOR = 5;                        // NO_PROTO3
   }                                 // NO_PROTO3
 
-  optional NestedConflictingEnum conflicting_enum = 1;  // NO_PROTO3
+  optional while conflicting_enum = 1;  // NO_PROTO3
 }  // NO_PROTO3
 
-enum ConflictingEnum {  // NO_PROTO3
+enum bool {             // NO_PROTO3
+  default = 0;          // NO_PROTO3
   NOT_EQ = 1;           // NO_PROTO3
   volatile = 2;         // NO_PROTO3
   return = 3;           // NO_PROTO3
-  NULL = 4;             // NO_PROTO3
 }  // NO_PROTO3
 
 message DummyMessage {}
 
+message NULL {
+  optional int32 int = 1;
+}
+
+extend TestConflictingSymbolNames {  // NO_PROTO3
+  optional int32 void = 314253;      // NO_PROTO3
+}                                    // NO_PROTO3
+
 // Message names that could conflict.
 message Shutdown {}
 message TableStruct {}
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index a17ed8b..4a52460 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -102,20 +102,33 @@
 
 TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingEnumNames) {
   protobuf_unittest::TestConflictingEnumNames message;
-  message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_and_);
+  message.set_conflicting_enum(
+      protobuf_unittest::TestConflictingEnumNames_while_and_);
   EXPECT_EQ(1, message.conflicting_enum());
-  message.set_conflicting_enum(protobuf_unittest::TestConflictingEnumNames_NestedConflictingEnum_XOR);
+  message.set_conflicting_enum(
+      protobuf_unittest::TestConflictingEnumNames_while_XOR);
   EXPECT_EQ(5, message.conflicting_enum());
 
-  protobuf_unittest::ConflictingEnum conflicting_enum;
+  protobuf_unittest::bool_ conflicting_enum;
   conflicting_enum = protobuf_unittest::NOT_EQ;
   EXPECT_EQ(1, conflicting_enum);
   conflicting_enum = protobuf_unittest::return_;
   EXPECT_EQ(3, conflicting_enum);
-  conflicting_enum = protobuf_unittest::NULL_;
-  EXPECT_EQ(4, conflicting_enum);
 }
 
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingMessageNames) {
+  protobuf_unittest::NULL_ message;
+  message.set_int_(123);
+  EXPECT_EQ(message.int_(), 123);
+}
+
+TEST(GENERATED_MESSAGE_TEST_NAME, TestConflictingExtension) {
+  protobuf_unittest::TestConflictingSymbolNames message;
+  message.SetExtension(protobuf_unittest::void_, 123);
+  EXPECT_EQ(123, message.GetExtension(protobuf_unittest::void_));
+}
+
+
 }  // namespace cpp_unittest
 }  // namespace cpp
 }  // namespace compiler
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 1f4317d..7259975 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -53,6 +53,13 @@
 namespace java {
 
 namespace {
+bool EnableExperimentalRuntimeForLite() {
+#ifdef PROTOBUF_EXPERIMENT
+  return PROTOBUF_EXPERIMENT;
+#else   // PROTOBUF_EXPERIMENT
+  return false;
+#endif  // !PROTOBUF_EXPERIMENT
+}
 
 void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
                       int builderBitIndex, const FieldGeneratorInfo* info,
@@ -656,7 +663,7 @@
     printer->Annotate("{", "}", descriptor_);
   }
 
-  if (descriptor_->is_packed() &&
+  if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() &&
       context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
@@ -929,6 +936,8 @@
 
 void RepeatedImmutableEnumFieldLiteGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!EnableExperimentalRuntimeForLite());
+
   if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
@@ -948,6 +957,8 @@
 
 void RepeatedImmutableEnumFieldLiteGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!EnableExperimentalRuntimeForLite());
+
   printer->Print(variables_,
     "{\n"
     "  int dataSize = 0;\n");
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 6527f0b..93b9294 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -115,6 +115,7 @@
   return field_name;
 }
 
+
 }  // namespace
 
 void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
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 0fda38d..be5f0f1 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -56,6 +56,13 @@
 using internal::WireFormatLite;
 
 namespace {
+bool EnableExperimentalRuntimeForLite() {
+#ifdef PROTOBUF_EXPERIMENT
+  return PROTOBUF_EXPERIMENT;
+#else   // PROTOBUF_EXPERIMENT
+  return false;
+#endif  // !PROTOBUF_EXPERIMENT
+}
 
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
                            int messageBitIndex, int builderBitIndex,
@@ -663,7 +670,7 @@
     "}\n");
   printer->Annotate("{", "}", descriptor_);
 
-  if (descriptor_->is_packed() &&
+  if (!EnableExperimentalRuntimeForLite() && descriptor_->is_packed() &&
       context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
@@ -854,6 +861,8 @@
 
 void RepeatedImmutablePrimitiveFieldLiteGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!EnableExperimentalRuntimeForLite());
+
   if (descriptor_->is_packed()) {
     // We invoke getSerializedSize in writeTo for messages that have packed
     // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
@@ -876,6 +885,8 @@
 
 void RepeatedImmutablePrimitiveFieldLiteGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
+  GOOGLE_CHECK(!EnableExperimentalRuntimeForLite());
+
   printer->Print(variables_,
     "{\n"
     "  int dataSize = 0;\n");
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index f3d8533..e00637e 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -2426,9 +2426,13 @@
     // 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 = ");
+    if (!use_default) {
+      printer->Print("(f = ");
+    }
     GenerateFieldValueExpression(printer, "msg", field, use_default);
-    printer->Print(") == null ? undefined : f");
+    if (!use_default) {
+      printer->Print(") == null ? undefined : f");
+    }
   }
 }
 
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 58e5694..98280f8 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -62,8 +62,8 @@
 
 class MockErrorCollector : public io::ErrorCollector {
  public:
-  MockErrorCollector() {}
-  ~MockErrorCollector() {}
+  MockErrorCollector() = default;
+  ~MockErrorCollector() override = default;
 
   std::string text_;
 
@@ -1114,17 +1114,17 @@
 
 TEST_F(ParseMiscTest, ParseFileOptions) {
   ExpectParsesTo(
-    "option java_package = \"com.google.foo\";\n"
-    "option optimize_for = CODE_SIZE;",
+      "option java_package = \"com.google.foo\";\n"
+      "option optimize_for = CODE_SIZE;",
 
-    "options {"
-    "uninterpreted_option { name { name_part: \"java_package\" "
-    "                              is_extension: false }"
-    "                       string_value: \"com.google.foo\"} "
-    "uninterpreted_option { name { name_part: \"optimize_for\" "
-    "                              is_extension: false }"
-    "                       identifier_value: \"CODE_SIZE\" } "
-    "}");
+      "options {"
+      "uninterpreted_option { name { name_part: \"java_package\" "
+      "                              is_extension: false }"
+      "                       string_value: \"com.google.foo\"} "
+      "uninterpreted_option { name { name_part: \"optimize_for\" "
+      "                              is_extension: false }"
+      "                       identifier_value: \"CODE_SIZE\" } "
+      "}");
 }
 
 // ===================================================================
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 4b7dd94..4759473 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -309,7 +309,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Version::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -349,8 +348,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -758,7 +756,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -804,8 +801,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1228,7 +1224,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1261,8 +1256,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1635,7 +1629,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1664,8 +1657,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
index 5b55745..665e5a7 100644
--- a/src/google/protobuf/compiler/plugin.proto
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -45,6 +45,7 @@
 // flag "--${NAME}_out" is passed to protoc.
 
 syntax = "proto2";
+
 package google.protobuf.compiler;
 option java_package = "com.google.protobuf.compiler";
 option java_outer_classname = "PluginProtos";
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index ac57cd5..06d6ea0 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1463,7 +1463,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FileDescriptorSet::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1485,8 +1485,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1902,7 +1901,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FileDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2027,8 +2026,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2825,7 +2823,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* DescriptorProto_ExtensionRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2858,8 +2856,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -3222,7 +3219,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* DescriptorProto_ReservedRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -3248,8 +3245,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -3640,7 +3636,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* DescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -3746,8 +3742,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -4417,7 +4412,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* ExtensionRangeOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -4445,8 +4440,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -4879,7 +4873,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FieldDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -4971,8 +4965,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -5696,7 +5689,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* OneofDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -5722,8 +5715,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -6065,7 +6057,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumDescriptorProto_EnumReservedRange::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -6091,8 +6083,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -6463,7 +6454,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -6519,8 +6510,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -7033,7 +7023,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumValueDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -7066,8 +7056,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -7482,7 +7471,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* ServiceDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -7518,8 +7507,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -7981,7 +7969,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* MethodDescriptorProto::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -8035,8 +8023,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -8731,7 +8718,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FileOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -8904,8 +8891,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -10057,7 +10043,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* MessageOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -10113,8 +10099,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -10587,7 +10572,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FieldOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -10667,8 +10652,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -11187,7 +11171,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* OneofOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -11215,8 +11199,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -11533,7 +11516,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -11575,8 +11558,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -11956,7 +11938,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumValueOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -11991,8 +11973,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -12334,7 +12315,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* ServiceOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -12369,8 +12350,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -12725,7 +12705,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* MethodOptions::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -12772,8 +12752,7 @@
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -13170,7 +13149,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* UninterpretedOption_NamePart::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -13196,8 +13175,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -13604,7 +13582,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* UninterpretedOption::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -13668,8 +13646,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -14225,7 +14202,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* SourceCodeInfo_Location::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -14289,8 +14266,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -14788,7 +14764,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* SourceCodeInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -14810,8 +14786,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -15120,7 +15095,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -15167,8 +15142,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -15584,7 +15558,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* GeneratedCodeInfo::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -15606,8 +15580,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index ef83b78..7c51bad 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -171,7 +171,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Duration::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -197,8 +197,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 1831645..57b8fe8 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -157,7 +157,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Empty::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -168,8 +168,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 795df3d..d0a63b9 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -279,14 +279,14 @@
 namespace {
 
 enum {
-  REPEATED,
-  OPTIONAL
+  REPEATED_FIELD,
+  OPTIONAL_FIELD
 };
 
 }  // namespace
 
-#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                             \
-  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED : OPTIONAL, LABEL);         \
+#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE)                                 \
+  GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? REPEATED_FIELD : OPTIONAL_FIELD, LABEL); \
   GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), WireFormatLite::CPPTYPE_##CPPTYPE)
 
 // -------------------------------------------------------------------
@@ -300,7 +300,7 @@
   if (extension == NULL || extension->is_cleared) {                            \
     return default_value;                                                      \
   } else {                                                                     \
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, UPPERCASE);                              \
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                        \
     return extension->LOWERCASE##_value;                                       \
   }                                                                            \
 }                                                                              \
@@ -314,7 +314,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \
     extension->is_repeated = false;                                            \
   } else {                                                                     \
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, UPPERCASE);                              \
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE);                        \
   }                                                                            \
   extension->is_cleared = false;                                               \
   extension->LOWERCASE##_value = value;                                        \
@@ -323,7 +323,7 @@
 LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const {  \
   const Extension* extension = FindOrNull(number);                             \
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";         \
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                                \
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                          \
   return extension->repeated_##LOWERCASE##_value->Get(index);                  \
 }                                                                              \
                                                                                \
@@ -331,7 +331,7 @@
     int number, int index, LOWERCASE value) {                                  \
   Extension* extension = FindOrNull(number);                                   \
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";         \
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                                \
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                          \
   extension->repeated_##LOWERCASE##_value->Set(index, value);                  \
 }                                                                              \
                                                                                \
@@ -347,7 +347,7 @@
     extension->repeated_##LOWERCASE##_value =                                  \
       Arena::CreateMessage<RepeatedField<LOWERCASE> >(arena_);                 \
   } else {                                                                     \
-    GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                              \
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, UPPERCASE);                        \
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                   \
   }                                                                            \
   extension->repeated_##LOWERCASE##_value->Add(value);                         \
@@ -456,7 +456,7 @@
     // Not present.  Return the default value.
     return default_value;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, ENUM);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
     return extension->enum_value;
   }
 }
@@ -469,7 +469,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
     extension->is_repeated = false;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, ENUM);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
   }
   extension->is_cleared = false;
   extension->enum_value = value;
@@ -478,14 +478,14 @@
 int ExtensionSet::GetRepeatedEnum(int number, int index) const {
   const Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
   return extension->repeated_enum_value->Get(index);
 }
 
 void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
   Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
   extension->repeated_enum_value->Set(index, value);
 }
 
@@ -501,7 +501,7 @@
     extension->repeated_enum_value =
         Arena::CreateMessage<RepeatedField<int> >(arena_);
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, ENUM);
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);
   }
   extension->repeated_enum_value->Add(value);
@@ -517,7 +517,7 @@
     // Not present.  Return the default value.
     return default_value;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
     return *extension->string_value;
   }
 }
@@ -531,7 +531,7 @@
     extension->is_repeated = false;
     extension->string_value = Arena::Create<std::string>(arena_);
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
   }
   extension->is_cleared = false;
   return extension->string_value;
@@ -541,14 +541,14 @@
                                                    int index) const {
   const Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
   return extension->repeated_string_value->Get(index);
 }
 
 std::string* ExtensionSet::MutableRepeatedString(int number, int index) {
   Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
   return extension->repeated_string_value->Mutable(index);
 }
 
@@ -563,7 +563,7 @@
     extension->repeated_string_value =
         Arena::CreateMessage<RepeatedPtrField<std::string>>(arena_);
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, STRING);
   }
   return extension->repeated_string_value->Add();
 }
@@ -578,7 +578,7 @@
     // Not present.  Return the default value.
     return default_value;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     if (extension->is_lazy) {
       return extension->lazymessage_value->GetMessage(default_value);
     } else {
@@ -605,7 +605,7 @@
     extension->is_cleared = false;
     return extension->message_value;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     extension->is_cleared = false;
     if (extension->is_lazy) {
       return extension->lazymessage_value->MutableMessage(prototype);
@@ -644,7 +644,7 @@
       extension->message_value->CheckTypeAndMergeFrom(*message);
     }
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     if (extension->is_lazy) {
       extension->lazymessage_value->SetAllocatedMessage(message);
     } else {
@@ -680,7 +680,7 @@
     extension->is_lazy = false;
     extension->message_value = message;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     if (extension->is_lazy) {
       extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message);
     } else {
@@ -700,7 +700,7 @@
     // Not present.  Return NULL.
     return NULL;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     MessageLite* ret = NULL;
     if (extension->is_lazy) {
       ret = extension->lazymessage_value->ReleaseMessage(prototype);
@@ -729,7 +729,7 @@
     // Not present.  Return NULL.
     return NULL;
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE);
     MessageLite* ret = NULL;
     if (extension->is_lazy) {
       ret = extension->lazymessage_value->UnsafeArenaReleaseMessage(prototype);
@@ -752,14 +752,14 @@
     int number, int index) const {
   const Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
   return extension->repeated_message_value->Get(index);
 }
 
 MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) {
   Extension* extension = FindOrNull(number);
   GOOGLE_CHECK(extension != NULL) << "Index out-of-bounds (field is empty).";
-  GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
+  GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
   return extension->repeated_message_value->Mutable(index);
 }
 
@@ -774,7 +774,7 @@
     extension->repeated_message_value =
         Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
-    GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
+    GOOGLE_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE);
   }
 
   // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
index 4bfcf3e..4e6995e 100644
--- a/src/google/protobuf/extension_set_inl.h
+++ b/src/google/protobuf/extension_set_inl.h
@@ -235,11 +235,13 @@
                                    extension.descriptor);
 
           const char* p;
+          // We can't use regular parse from string as we have to track
+          // proper recursion depth and descriptor pools.
           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)));
+          GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) &&
+                                         tmp_ctx.EndedAtLimit());
         }
         type_id = 0;
       }
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index 221f81f..0c54eb7 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -165,7 +165,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FieldMask::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -187,8 +187,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index c0652c3..443a5db 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -50,6 +50,8 @@
 #include <google/protobuf/wire_format.h>
 
 
+#include <google/protobuf/port_def.inc>
+
 #define GOOGLE_PROTOBUF_HAS_ONEOF
 
 namespace google {
diff --git a/src/google/protobuf/generated_message_table_driven.h b/src/google/protobuf/generated_message_table_driven.h
index 857545e..8564f5e 100644
--- a/src/google/protobuf/generated_message_table_driven.h
+++ b/src/google/protobuf/generated_message_table_driven.h
@@ -273,23 +273,24 @@
 
 template <typename T>
 struct CompareHelper {
-  bool operator()(const T& a, const T& b) { return a < b; }
+  bool operator()(const T& a, const T& b) const { return a < b; }
 };
 
 template <>
 struct CompareHelper<ArenaStringPtr> {
-  bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) {
+  bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
     return a.Get() < b.Get();
   }
 };
 
 struct CompareMapKey {
   template <typename T>
-  bool operator()(const MapEntryHelper<T>& a, const MapEntryHelper<T>& b) {
+  bool operator()(const MapEntryHelper<T>& a,
+                  const MapEntryHelper<T>& b) const {
     return Compare(a.key_, b.key_);
   }
   template <typename T>
-  bool Compare(const T& a, const T& b) {
+  bool Compare(const T& a, const T& b) const {
     return CompareHelper<T>()(a, b);
   }
 };
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index fe91bcb..26a422f 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -35,9 +35,13 @@
 #include <google/protobuf/generated_message_util.h>
 
 #include <limits>
+
+#ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
 // We're only using this as a standard way for getting the thread id.
 // We're not using any thread functionality.
 #include <thread>  // NOLINT
+#endif  // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
 #include <vector>
 
 #include <google/protobuf/io/coded_stream_inl.h>
@@ -784,8 +788,17 @@
   static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
   // Either the default in case no initialization is running or the id of the
   // thread that is currently initializing.
+#ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
   static std::atomic<std::thread::id> runner;
   auto me = std::this_thread::get_id();
+#else
+  // This is a lightweight replacement for std::thread::id. std::thread does not
+  // work on Windows XP SP2 with the latest VC++ libraries, because it utilizes
+  // the Concurrency Runtime that is only supported on Windows XP SP3 and above.
+  static std::atomic_llong runner(-1);
+  auto me = ::GetCurrentThreadId();
+#endif  // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
   // This will only happen because the constructor will call InitSCC while
   // constructing the default instance.
   if (runner.load(std::memory_order_relaxed) == me) {
@@ -799,7 +812,13 @@
   mu.Lock();
   runner.store(me, std::memory_order_relaxed);
   InitSCC_DFS(scc);
+
+#ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
   runner.store(std::thread::id{}, std::memory_order_relaxed);
+#else
+  runner.store(-1, std::memory_order_relaxed);
+#endif  // #ifndef GOOGLE_PROTOBUF_SUPPORT_WINDOWS_XP
+
   mu.Unlock();
 }
 
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
index 4cd0968..35e64f0 100644
--- a/src/google/protobuf/implicit_weak_message.cc
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -41,17 +41,18 @@
 namespace protobuf {
 namespace internal {
 
-bool ImplicitWeakMessage::MergePartialFromCodedStream(io::CodedInputStream* input) {
-  io::StringOutputStream string_stream(&data_);
-  io::CodedOutputStream coded_stream(&string_stream, false);
-  return WireFormatLite::SkipMessage(input, &coded_stream);
-}
-
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* ImplicitWeakMessage::_InternalParse(const char* ptr,
                                                 ParseContext* ctx) {
   return ctx->AppendString(ptr, &data_);
 }
+#else
+bool ImplicitWeakMessage::MergePartialFromCodedStream(
+    io::CodedInputStream* input) {
+  io::StringOutputStream string_stream(&data_);
+  io::CodedOutputStream coded_stream(&string_stream, false);
+  return WireFormatLite::SkipMessage(input, &coded_stream);
+}
 #endif
 
 ExplicitlyConstructed<ImplicitWeakMessage>
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
index 16b9164..cab5df9 100644
--- a/src/google/protobuf/implicit_weak_message.h
+++ b/src/google/protobuf/implicit_weak_message.h
@@ -76,10 +76,10 @@
     data_.append(static_cast<const ImplicitWeakMessage&>(other).data_);
   }
 
-  bool MergePartialFromCodedStream(io::CodedInputStream* input) override;
-
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
   const char* _InternalParse(const char* ptr, ParseContext* ctx) final;
+#else
+  bool MergePartialFromCodedStream(io::CodedInputStream* input) override;
 #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 891f6dd..2f1f270 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -710,6 +710,9 @@
   // Skips a number of bytes, leaving the bytes unmodified in the underlying
   // buffer.  Returns false if an underlying write error occurs.  This is
   // mainly useful with GetDirectBufferPointer().
+  // Note of caution, the skipped bytes may contain uninitialized data. The
+  // caller must make sure that the skipped bytes are properly initialized,
+  // otherwise you might leak bytes from your heap.
   bool Skip(int count);
 
   // Sets *data to point directly at the unwritten part of the
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index 008b323..65b2f52 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -44,6 +44,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <gtest/gtest.h>
+#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
@@ -1049,5 +1050,54 @@
       "\202\1\15\10\1\200\200\200\200\200\200\200\200\200\200\1"));
 }
 
+TEST(Lite, CorrectEnding) {
+  protobuf_unittest::TestAllTypesLite msg;
+  {
+    // All proto wireformat parsers should act the same on parsing data in as
+    // much as it concerns the parsing, ie. not the interpretation of the data.
+    // TestAllTypesLite is not a group inside another message. So in practice
+    // will not encounter an end-group tag. However the parser should behave
+    // like any wire format parser should.
+    static const char kWireFormat[] = "\204\1";
+    io::CodedInputStream cis(reinterpret_cast<const uint8*>(kWireFormat), 2);
+    // The old CodedInputStream parser got an optimization (ReadTagNoLastTag)
+    // for non-group messages (like TestAllTypesLite) which made it not accept
+    // end-group. This is not a real big deal, but I think going forward its
+    // good to have all parse loops behave 'exactly' the same.
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+    EXPECT_TRUE(msg.MergePartialFromCodedStream(&cis));
+    EXPECT_FALSE(cis.ConsumedEntireMessage());
+    EXPECT_TRUE(cis.LastTagWas(132));
+#endif
+  }
+  {
+    // This is an incomplete end-group tag. This should be a genuine parse
+    // failure.
+    static const char kWireFormat[] = "\214";
+    io::CodedInputStream cis(reinterpret_cast<const uint8*>(kWireFormat), 1);
+    // Unfortunately the old parser detects a parse error in ReadTag and returns
+    // 0 (as it states 0 is an invalid tag). However 0 is not an invalid tag
+    // as it can be used to terminate the stream, so this returns true.
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+    EXPECT_FALSE(msg.MergePartialFromCodedStream(&cis));
+#endif
+  }
+}
+
+TEST(Lite, DebugString) {
+  protobuf_unittest::TestAllTypesLite message1, message2;
+  EXPECT_TRUE(HasPrefixString(message1.DebugString(), "MessageLite at 0x"));
+  EXPECT_TRUE(HasPrefixString(message2.DebugString(), "MessageLite at 0x"));
+
+  // DebugString() and ShortDebugString() are the same for now.
+  EXPECT_EQ(message1.DebugString(), message1.ShortDebugString());
+
+  // Even identical lite protos should have different DebugString() output. Part
+  // of the reason for including the memory address is so that we get some
+  // non-determinism, which should make it easier for us to change the output
+  // later without breaking any code.
+  EXPECT_NE(message1.DebugString(), message2.DebugString());
+}
+
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 19f0b5f..756b9af 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -214,7 +214,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag, nullptr, ptr, ctx);
+        ptr = UnknownFieldParse(tag, static_cast<string*>(nullptr), ptr, ctx);
       }
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     }
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index a0c96df..5ed84f3 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -33,6 +33,8 @@
 
 #include <vector>
 
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace internal {
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 731f4ca..f531a7c 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -34,6 +34,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <climits>
+#include <cstdint>
 #include <string>
 
 #include <google/protobuf/stubs/logging.h>
@@ -48,6 +49,7 @@
 #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>
 #include <google/protobuf/stubs/stl_util.h>
 
@@ -60,6 +62,11 @@
   return "(cannot determine missing fields for lite message)";
 }
 
+std::string MessageLite::DebugString() const {
+  std::uintptr_t address = reinterpret_cast<std::uintptr_t>(this);
+  return StrCat("MessageLite at 0x", strings::Hex(address));
+}
+
 namespace {
 
 // When serializing, we first compute the byte size, then serialize the message.
@@ -123,7 +130,9 @@
   const char* ptr;
   internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
                              aliasing, &ptr, input);
-  return ctx.AtLegitimateEnd(msg->_InternalParse(ptr, &ctx));
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has an explicit limit set (length of string_view).
+  return ptr && ctx.EndedAtLimit();
 }
 
 template <bool aliasing>
@@ -131,7 +140,9 @@
   const char* ptr;
   internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
                              aliasing, &ptr, input);
-  return ctx.AtLegitimateEnd(msg->_InternalParse(ptr, &ctx));
+  ptr = msg->_InternalParse(ptr, &ctx);
+  // ctx has no explicit limit (hence we end on end of stream)
+  return ptr && ctx.EndedAtEndOfStream();
 }
 
 template <bool aliasing>
@@ -229,13 +240,15 @@
   ctx.data().pool = input->GetExtensionPool();
   ctx.data().factory = input->GetExtensionFactory();
   ptr = _InternalParse(ptr, &ctx);
-  if (!ptr) return false;
+  if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
   ctx.BackUp(ptr);
-  if (ctx.LastTagMinus1() != 0) {
-    input->SetLastTag(ctx.LastTagMinus1() + 1);
+  if (!ctx.EndedAtEndOfStream()) {
+    GOOGLE_DCHECK(ctx.LastTag() != 1);  // We can't end on a pushed limit.
+    if (ctx.IsExceedingLimit(ptr)) return false;
+    input->SetLastTag(ctx.LastTag());
     return true;
   }
-  if (ctx.AtLimit(ptr)) input->SetConsumed();
+  input->SetConsumed();
   return true;
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index ba9abf7..8deb143 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -234,6 +234,20 @@
   // results are undefined (probably crash).
   virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
 
+  // These methods return a human-readable summary of the message. Note that
+  // since the MessageLite interface does not support reflection, there is very
+  // little information that these methods can provide. They are shadowed by
+  // methods of the same name on the Message interface which provide much more
+  // information. The methods here are intended primarily to facilitate code
+  // reuse for logic that needs to interoperate with both full and lite protos.
+  //
+  // The format of the returned string is subject to change, so please do not
+  // assume it will remain stable over time.
+  std::string DebugString() const;
+  std::string ShortDebugString() const {
+    return DebugString();
+  }
+
   // Parsing ---------------------------------------------------------
   // Methods for parsing in protocol buffer format.  Most of these are
   // just simple wrappers around MergeFromCodedStream().  Clear() will be
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index abf7caf..2aec32e 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -157,11 +157,15 @@
   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.
+  // Did we exceeded the limit (parse error).
   if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
-  GOOGLE_DCHECK(overrun <= limit_);  // Follows from above
+  GOOGLE_DCHECK(overrun != limit_);  // Guaranteed by caller.
+  GOOGLE_DCHECK(overrun < limit_);   // Follows from above
+  // TODO(gerbens) Instead of this dcheck we could just assign, and remove
+  // updating the limit_end from PopLimit, ie.
+  // limit_end_ = buffer_end_ + (std::min)(0, limit_);
+  // if (ptr < limit_end_) return {ptr, false};
+  GOOGLE_DCHECK(limit_end_ == buffer_end_ + (std::min)(0, limit_));
   // At this point we know the following assertion holds.
   GOOGLE_DCHECK(limit_ > 0);
   GOOGLE_DCHECK(limit_end_ == buffer_end_);  // because limit_ > 0
@@ -174,6 +178,8 @@
       if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
       GOOGLE_DCHECK(limit_ > 0);
       limit_end_ = buffer_end_;
+      // Distinquish ending on a pushed limit or ending on end-of-stream.
+      SetEndOfStream();
       return {ptr, true};
     }
     limit_ -= buffer_end_ - p;  // Adjust limit_ relative to new anchor
@@ -193,12 +199,19 @@
   s->clear();
   // TODO(gerbens) assess security. At the moment its parity with
   // CodedInputStream but it allows a payload to reserve large memory.
-  if (size <= buffer_end_ - ptr + limit_) s->reserve(size);
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    s->reserve(size);
+  }
   return AppendStringFallback(ptr, size, s);
 }
 
 const char* EpsCopyInputStream::AppendStringFallback(const char* ptr, int size,
                                                      std::string* str) {
+  // TODO(gerbens) assess security. At the moment its parity with
+  // CodedInputStream but it allows a payload to reserve large memory.
+  if (PROTOBUF_PREDICT_TRUE(size <= buffer_end_ - ptr + limit_)) {
+    str->reserve(size);
+  }
   return AppendSize(ptr, size,
                     [str](const char* p, int s) { str->append(p, s); });
 }
@@ -264,7 +277,6 @@
   }
   next_chunk_ = nullptr;
   size_ = 0;
-  limit_ = 0;
   limit_end_ = buffer_end_ = buffer_;
   return buffer_;
 }
@@ -340,6 +352,13 @@
   return true;
 }
 
+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);
+}
+
 const char* InlineGreedyStringParserUTF8(std::string* s, const char* ptr,
                                          ParseContext* ctx,
                                          const char* field_name) {
@@ -348,16 +367,6 @@
   return p;
 }
 
-const char* InlineGreedyStringParserUTF8Verify(std::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) {
@@ -531,6 +540,12 @@
   return FieldParser(tag, field_parser, ptr, ctx);
 }
 
+const char* UnknownFieldParse(uint32 tag,
+                              InternalMetadataWithArenaLite* metadata,
+                              const char* ptr, ParseContext* ctx) {
+  return UnknownFieldParse(tag, metadata->mutable_unknown_fields(), ptr, ctx);
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index 82756e3..1bf6100 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/implicit_weak_message.h>
+#include <google/protobuf/metadata_lite.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -124,17 +125,17 @@
   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;
+    limit_end_ = buffer_end_ + (std::min)(0, limit);
     auto old_limit = limit_;
     limit_ = limit;
     return old_limit - limit;
   }
 
-  PROTOBUF_MUST_USE_RESULT bool PopLimit(int delta, const char* ptr) {
-    // Ensure not to forget to check PushLimit return value
-    GOOGLE_DCHECK(delta >= 0);
-    if (ptr == nullptr || ptr - buffer_end_ != limit_) return false;
+  PROTOBUF_MUST_USE_RESULT bool PopLimit(int delta) {
+    if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
     limit_ = limit_ + delta;
+    // TODO(gerbens) We could remove this line and hoist the code to
+    // DoneFallback. Study the perf/bin-size effects.
     limit_end_ = buffer_end_ + (std::min)(0, limit_);
     return true;
   }
@@ -175,9 +176,19 @@
   PROTOBUF_MUST_USE_RESULT const char* ReadPackedVarint(const char* ptr,
                                                         Add add);
 
-  bool AtLimit(const char* ptr) const {
-    return (ptr - buffer_end_ == limit_) ||
-           (next_chunk_ == nullptr && limit_ > 0 && ptr == buffer_end_);
+  uint32 LastTag() const { return last_tag_minus_1_ + 1; }
+  bool ConsumeEndGroup(uint32 start_tag) {
+    bool res = last_tag_minus_1_ == start_tag;
+    last_tag_minus_1_ = 0;
+    return res;
+  }
+  bool EndedAtLimit() const { return last_tag_minus_1_ == 0; }
+  bool EndedAtEndOfStream() const { return last_tag_minus_1_ == 1; }
+  void SetLastTag(uint32 tag) { last_tag_minus_1_ = tag - 1; }
+  void SetEndOfStream() { last_tag_minus_1_ = 1; }
+  bool IsExceedingLimit(const char* ptr) {
+    return ptr > limit_end_ &&
+           (next_chunk_ == nullptr || ptr - buffer_end_ > limit_);
   }
 
  protected:
@@ -233,6 +244,20 @@
   char buffer_[2 * kSlopBytes] = {};
   enum { kNoAliasing = 0, kOnPatch = 1, kNoDelta = 2 };
   std::uintptr_t aliasing_ = kNoAliasing;
+  // This variable is used to communicate how the parse ended, in order to
+  // completely verify the parsed data. A wire-format parse can end because of
+  // one of the following conditions:
+  // 1) A parse can end on a pushed limit.
+  // 2) A parse can end on End Of Stream (EOS).
+  // 3) A parse can end on 0 tag (only valid for toplevel message).
+  // 4) A parse can end on an end-group tag.
+  // This variable should always be set to 0, which indicates case 1. If the
+  // parse terminated due to EOS (case 2), it's set to 1. In case the parse
+  // ended due to a terminating tag (case 3 and 4) it's set to (tag - 1).
+  // This var doesn't really belong in EpsCopyInputStream and should be part of
+  // the ParseContext, but case 2 is most easily and optimally implemented in
+  // DoneFallback.
+  uint32 last_tag_minus_1_ = 0;
 
   std::pair<const char*, bool> DoneFallback(const char* ptr, int d);
   const char* Next(int overrun, int d);
@@ -306,12 +331,6 @@
   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_; }
@@ -331,8 +350,7 @@
     ptr = msg->_InternalParse(ptr, this);
     group_depth_--;
     depth_++;
-    if (last_tag_minus_1_ != tag) return nullptr;
-    last_tag_minus_1_ = 0;
+    if (PROTOBUF_PREDICT_FALSE(!ConsumeEndGroup(tag))) return nullptr;
     return ptr;
   }
 
@@ -346,7 +364,6 @@
   // 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;
   Data data_;
 };
 
@@ -403,12 +420,26 @@
 
 // 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 VarintParse<5>(p, out);
-}
 
 std::pair<const char*, uint32> ReadTagFallback(const char* p, uint32 res);
 
+inline const char* ReadTag(const char* p, uint32* out) {
+  uint32 res = static_cast<uint8>(p[0]);
+  if (res < 128) {
+    *out = res;
+    return p + 1;
+  }
+  uint32 second = static_cast<uint8>(p[1]);
+  res += (second - 1) << 7;
+  if (second < 128) {
+    *out = res;
+    return p + 2;
+  }
+  auto tmp = ReadTagFallback(p + 2, res);
+  *out = tmp.second;
+  return tmp.first;
+}
+
 // Will preload the next 2 bytes
 inline const char* ReadTag(const char* p, uint32* out, uint32* preload) {
   uint32 res = static_cast<uint8>(p[0]);
@@ -536,10 +567,11 @@
   int size = ReadSize(&ptr);
   if (!ptr) return nullptr;
   auto old = PushLimit(ptr, size);
-  if (--depth_ < 0 || old < 0) return nullptr;
+  if (--depth_ < 0) return nullptr;
   ptr = msg->_InternalParse(ptr, this);
+  if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
   depth_++;
-  if (!PopLimit(old, ptr) || last_tag_minus_1_ != 0) return nullptr;
+  if (!PopLimit(old)) return nullptr;
   return ptr;
 }
 
@@ -555,7 +587,7 @@
     if (!ptr) return nullptr;
     add(varint);
   }
-  if (!PopLimit(old, ptr)) return nullptr;
+  if (!PopLimit(old)) return nullptr;
   return ptr;
 }
 
@@ -564,19 +596,22 @@
 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_EXPORT PROTOBUF_MUST_USE_RESULT const char* InlineGreedyStringParser(
+    std::string* s, const char* ptr, ParseContext* ctx);
 
 PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char*
 InlineGreedyStringParserUTF8(std::string* s, const char* ptr, ParseContext* ctx,
                              const char* field_name);
-PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char*
-InlineGreedyStringParserUTF8Verify(std::string* s, const char* ptr,
-                                   ParseContext* ctx, const char* field_name);
+// Inline because we don't want to pay the price of field_name in opt mode.
+inline PROTOBUF_MUST_USE_RESULT const char* InlineGreedyStringParserUTF8Verify(
+    std::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;
+}
 
 
 // Add any of the following lines to debug which parse function is failing.
@@ -705,6 +740,9 @@
 // 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);
+PROTOBUF_EXPORT PROTOBUF_MUST_USE_RESULT const char* UnknownFieldParse(
+    uint32 tag, InternalMetadataWithArenaLite* metadata, const char* ptr,
+    ParseContext* ctx);
 
 }  // namespace internal
 }  // namespace protobuf
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index f1eea1f..f8f9dc3 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -46,6 +46,8 @@
 #include <google/protobuf/stubs/strutil.h>
 
 
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 namespace internal {
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index e6cce71..477091b 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -156,7 +156,6 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* SourceContext::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -175,8 +174,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index a75df43..aed2db9 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -276,7 +276,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Struct::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -298,8 +298,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -777,7 +776,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -832,8 +831,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1295,7 +1293,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* ListValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1317,8 +1315,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto
index 60dbfc7..dc6aaa3 100644
--- a/src/google/protobuf/test_messages_proto2.proto
+++ b/src/google/protobuf/test_messages_proto2.proto
@@ -33,6 +33,8 @@
 // - conformance tests
 //
 
+// LINT: ALLOW_GROUPS
+
 syntax = "proto2";
 
 package protobuf_test_messages.proto2;
@@ -180,6 +182,9 @@
   optional int32 field_name17__ = 417;
   optional int32 Field_name18__ = 418;
 
+  // Reserved for unknown fields test.
+  reserved 1000 to 9999;
+
   // message_set test case.
   message MessageSetCorrect {
     option message_set_wire_format = true;
@@ -214,3 +219,15 @@
 extend TestAllTypesProto2 {
   optional int32 extension_int32 = 120;
 }
+
+message UnknownToTestAllTypes {
+  optional int32  optional_int32 = 1001;
+  optional string optional_string = 1002;
+  optional ForeignMessageProto2 nested_message = 1003;
+  optional group OptionalGroup = 1004 {
+    optional int32 a = 1;
+  }
+  optional bool optional_bool = 1006;
+  repeated int32 repeated_int32 = 1011;
+}
+
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 34e442c..ba0c302 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -64,6 +64,8 @@
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 
+#include <google/protobuf/port_def.inc>
+
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 92db4ba..091caa5 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -171,7 +171,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Timestamp::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -197,8 +197,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index dbf8704..f30839c 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -498,7 +498,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Type::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -562,8 +562,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1091,7 +1090,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Field::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1178,8 +1177,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1871,7 +1869,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Enum::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1925,8 +1923,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2371,7 +2368,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* EnumValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2407,8 +2404,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2805,7 +2801,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Option::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2831,8 +2827,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 1907553..2f8b763 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -357,6 +357,11 @@
   return FieldParser(tag, field_parser, ptr, ctx);
 }
 
+const char* UnknownFieldParse(uint32 tag, InternalMetadataWithArena* metadata,
+                              const char* ptr, ParseContext* ctx) {
+  return UnknownFieldParse(tag, metadata->mutable_unknown_fields(), ptr, ctx);
+}
+
 }  // namespace internal
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 17b8c07..0d61f89 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -212,6 +212,9 @@
 PROTOBUF_EXPORT
 const char* UnknownFieldParse(uint64 tag, UnknownFieldSet* unknown,
                               const char* ptr, ParseContext* ctx);
+PROTOBUF_EXPORT
+const char* UnknownFieldParse(uint32 tag, InternalMetadataWithArena* metadata,
+                              const char* ptr, ParseContext* ctx);
 
 }  // namespace internal
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto
index 44f18f3..d773267 100644
--- a/src/google/protobuf/util/json_format.proto
+++ b/src/google/protobuf/util/json_format.proto
@@ -35,8 +35,8 @@
 // A proto file we will use for unit testing.
 
 syntax = "proto2";
-package protobuf_unittest;
 
+package protobuf_unittest;
 
 message TestFlagsAndStrings {
   required int32 A = 1;
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
index 28e593d..1e72794 100644
--- a/src/google/protobuf/util/json_format_proto3.proto
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -32,17 +32,17 @@
 
 package proto3;
 
-option java_package = "com.google.protobuf.util";
-option java_outer_classname = "JsonFormatProto3";
-
+import "google/protobuf/any.proto";
 import "google/protobuf/duration.proto";
+import "google/protobuf/field_mask.proto";
+import "google/protobuf/struct.proto";
 import "google/protobuf/timestamp.proto";
 import "google/protobuf/wrappers.proto";
-import "google/protobuf/struct.proto";
-import "google/protobuf/any.proto";
-import "google/protobuf/field_mask.proto";
 import "google/protobuf/unittest.proto";
 
+option java_package = "com.google.protobuf.util";
+option java_outer_classname = "JsonFormatProto3";
+
 enum EnumType {
   FOO = 0;
   BAR = 1;
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 1c7451e..7504227 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -127,7 +127,7 @@
   // defined as all fields within the two messages having the same value. This
   // differs from the Equals method above in that fields with default values
   // are considered set to said value automatically. For details on how default
-  // values are defined for each field type, see 
+  // values are defined for each field type, see:
   // https://developers.google.com/protocol-buffers/docs/proto?csw=1#optional.
   // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare()
   // if some fields should be ignored in the comparison.
diff --git a/src/google/protobuf/util/message_differencer_unittest.proto b/src/google/protobuf/util/message_differencer_unittest.proto
index 698775f..fafd19c 100644
--- a/src/google/protobuf/util/message_differencer_unittest.proto
+++ b/src/google/protobuf/util/message_differencer_unittest.proto
@@ -35,6 +35,7 @@
 // This file contains messages for testing repeated field comparison
 
 syntax = "proto2";
+
 package protobuf_unittest;
 
 option optimize_for = SPEED;
@@ -53,22 +54,21 @@
 
 message TestDiffMessage {
   repeated group Item = 1 {
-    optional int32  a  =  2;     // Test basic repeated field comparison.
-    optional string b  =  4;     // Test basic repeated field comparison.
-    repeated int32  ra =  3;     // Test SetOfSet Comparison.
-    repeated string rb =  5;     // Test TreatAsMap when key is repeated
-    optional TestField m  = 6;   // Test TreatAsMap when key is a message
-    repeated TestField rm = 7;   // Test TreatAsMap when key is a repeated
-                                 // message
+    optional int32 a = 2;       // Test basic repeated field comparison.
+    optional string b = 4;      // Test basic repeated field comparison.
+    repeated int32 ra = 3;      // Test SetOfSet Comparison.
+    repeated string rb = 5;     // Test TreatAsMap when key is repeated
+    optional TestField m = 6;   // Test TreatAsMap when key is a message
+    repeated TestField rm = 7;  // Test TreatAsMap when key is a repeated
+                                // message
   }
 
-  optional int32  v  = 13 [deprecated = true];
-  optional string w  = 14;
-  optional TestField m  = 15;
-  repeated int32  rv = 11;       // Test for combinations
-  repeated string rw = 10;       // Test for combinations
-  repeated TestField rm = 12 [deprecated = true];    // Test for combinations
+  optional int32 v = 13 [deprecated = true];
+  optional string w = 14;
+  optional TestField m = 15;
+  repeated int32 rv = 11;                          // Test for combinations
+  repeated string rw = 10;                         // Test for combinations
+  repeated TestField rm = 12 [deprecated = true];  // Test for combinations
 
   extensions 100 to 199;
 }
-
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 6c8c6b7..7a25207 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -52,6 +52,8 @@
 #include <google/protobuf/unknown_field_set.h>
 
 
+#include <google/protobuf/port_def.inc>
+
 const size_t kMapEntryTagByteSize = 2;
 
 namespace google {
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index b8ae08e..2468163 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -248,16 +248,6 @@
   // of these methods are defined in wire_format_lite_inl.h; you must #include
   // that file to use these.
 
-#ifdef NDEBUG
-#define INL PROTOBUF_ALWAYS_INLINE
-#else
-// Avoid excessive inlining in non-optimized builds. Without other optimizations
-// the inlining is not going to provide benefits anyway and the huge resulting
-// functions, especially in the proto-generated serialization functions, produce
-// stack frames so large that many tests run into stack overflows (b/32192897).
-#define INL
-#endif
-
   // Read fields, not including tags.  The assumption is that you already
   // read the tag to determine what field to read.
 
@@ -265,15 +255,16 @@
   // the represented type and the FieldType. These are specialized with the
   // appropriate definition for each declared type.
   template <typename CType, enum FieldType DeclaredType>
-  INL static bool ReadPrimitive(io::CodedInputStream* input, CType* value);
+  PROTOBUF_ALWAYS_INLINE static bool ReadPrimitive(io::CodedInputStream* input,
+                                                   CType* value);
 
   // Reads repeated primitive values, with optimizations for repeats.
   // tag_size and tag should both be compile-time constants provided by the
   // protocol compiler.
   template <typename CType, enum FieldType DeclaredType>
-  INL static bool ReadRepeatedPrimitive(int tag_size, uint32 tag,
-                                        io::CodedInputStream* input,
-                                        RepeatedField<CType>* value);
+  PROTOBUF_ALWAYS_INLINE static bool ReadRepeatedPrimitive(
+      int tag_size, uint32 tag, io::CodedInputStream* input,
+      RepeatedField<CType>* value);
 
   // Identical to ReadRepeatedPrimitive, except will not inline the
   // implementation.
@@ -288,15 +279,15 @@
   // This is only implemented for the types with fixed wire size, e.g.
   // float, double, and the (s)fixed* types.
   template <typename CType, enum FieldType DeclaredType>
-  INL static const uint8* ReadPrimitiveFromArray(const uint8* buffer,
-                                                 CType* value);
+  PROTOBUF_ALWAYS_INLINE static const uint8* ReadPrimitiveFromArray(
+      const uint8* buffer, CType* value);
 
   // Reads a primitive packed field.
   //
   // This is only implemented for packable types.
   template <typename CType, enum FieldType DeclaredType>
-  INL static bool ReadPackedPrimitive(io::CodedInputStream* input,
-                                      RepeatedField<CType>* value);
+  PROTOBUF_ALWAYS_INLINE static bool ReadPackedPrimitive(
+      io::CodedInputStream* input, RepeatedField<CType>* value);
 
   // Identical to ReadPackedPrimitive, except will not inline the
   // implementation.
@@ -364,28 +355,38 @@
   // Write a tag.  The Write*() functions typically include the tag, so
   // normally there's no need to call this unless using the Write*NoTag()
   // variants.
-  INL static void WriteTag(int field_number, WireType type,
-                           io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteTag(int field_number, WireType type,
+                                              io::CodedOutputStream* output);
 
   // Write fields, without tags.
-  INL static void WriteInt32NoTag(int32 value, io::CodedOutputStream* output);
-  INL static void WriteInt64NoTag(int64 value, io::CodedOutputStream* output);
-  INL static void WriteUInt32NoTag(uint32 value, io::CodedOutputStream* output);
-  INL static void WriteUInt64NoTag(uint64 value, io::CodedOutputStream* output);
-  INL static void WriteSInt32NoTag(int32 value, io::CodedOutputStream* output);
-  INL static void WriteSInt64NoTag(int64 value, io::CodedOutputStream* output);
-  INL static void WriteFixed32NoTag(uint32 value,
-                                    io::CodedOutputStream* output);
-  INL static void WriteFixed64NoTag(uint64 value,
-                                    io::CodedOutputStream* output);
-  INL static void WriteSFixed32NoTag(int32 value,
-                                     io::CodedOutputStream* output);
-  INL static void WriteSFixed64NoTag(int64 value,
-                                     io::CodedOutputStream* output);
-  INL static void WriteFloatNoTag(float value, io::CodedOutputStream* output);
-  INL static void WriteDoubleNoTag(double value, io::CodedOutputStream* output);
-  INL static void WriteBoolNoTag(bool value, io::CodedOutputStream* output);
-  INL static void WriteEnumNoTag(int value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteInt32NoTag(
+      int32 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteInt64NoTag(
+      int64 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteUInt32NoTag(
+      uint32 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteUInt64NoTag(
+      uint64 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteSInt32NoTag(
+      int32 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteSInt64NoTag(
+      int64 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteFixed32NoTag(
+      uint32 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteFixed64NoTag(
+      uint64 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteSFixed32NoTag(
+      int32 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteSFixed64NoTag(
+      int64 value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteFloatNoTag(
+      float value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteDoubleNoTag(
+      double value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteBoolNoTag(
+      bool value, io::CodedOutputStream* output);
+  PROTOBUF_ALWAYS_INLINE static void WriteEnumNoTag(
+      int value, io::CodedOutputStream* output);
 
   // Write array of primitive fields, without tags
   static void WriteFloatArray(const float* a, int n,
@@ -468,147 +469,161 @@
                                            io::CodedOutputStream* output);
 
   // Like above, but use only *ToArray methods of CodedOutputStream.
-  INL static uint8* WriteTagToArray(int field_number, WireType type,
-                                    uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteTagToArray(int field_number,
+                                                       WireType type,
+                                                       uint8* target);
 
   // Write fields, without tags.
-  INL static uint8* WriteInt32NoTagToArray(int32 value, uint8* target);
-  INL static uint8* WriteInt64NoTagToArray(int64 value, uint8* target);
-  INL static uint8* WriteUInt32NoTagToArray(uint32 value, uint8* target);
-  INL static uint8* WriteUInt64NoTagToArray(uint64 value, uint8* target);
-  INL static uint8* WriteSInt32NoTagToArray(int32 value, uint8* target);
-  INL static uint8* WriteSInt64NoTagToArray(int64 value, uint8* target);
-  INL static uint8* WriteFixed32NoTagToArray(uint32 value, uint8* target);
-  INL static uint8* WriteFixed64NoTagToArray(uint64 value, uint8* target);
-  INL static uint8* WriteSFixed32NoTagToArray(int32 value, uint8* target);
-  INL static uint8* WriteSFixed64NoTagToArray(int64 value, uint8* target);
-  INL static uint8* WriteFloatNoTagToArray(float value, uint8* target);
-  INL static uint8* WriteDoubleNoTagToArray(double value, uint8* target);
-  INL static uint8* WriteBoolNoTagToArray(bool value, uint8* target);
-  INL static uint8* WriteEnumNoTagToArray(int value, uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt32NoTagToArray(int32 value,
+                                                              uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt64NoTagToArray(int64 value,
+                                                              uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt32NoTagToArray(uint32 value,
+                                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt64NoTagToArray(uint64 value,
+                                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt32NoTagToArray(int32 value,
+                                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt64NoTagToArray(int64 value,
+                                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed32NoTagToArray(uint32 value,
+                                                                uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed64NoTagToArray(uint64 value,
+                                                                uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed32NoTagToArray(int32 value,
+                                                                 uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed64NoTagToArray(int64 value,
+                                                                 uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFloatNoTagToArray(float value,
+                                                              uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteDoubleNoTagToArray(double value,
+                                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteBoolNoTagToArray(bool value,
+                                                             uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteEnumNoTagToArray(int value,
+                                                             uint8* target);
 
   // Write fields, without tags.  These require that value.size() > 0.
   template <typename T>
-  INL static uint8* WritePrimitiveNoTagToArray(const RepeatedField<T>& value,
-                                               uint8* (*Writer)(T, uint8*),
-                                               uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WritePrimitiveNoTagToArray(
+      const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*),
+      uint8* target);
   template <typename T>
-  INL static uint8* WriteFixedNoTagToArray(const RepeatedField<T>& value,
-                                           uint8* (*Writer)(T, uint8*),
-                                           uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixedNoTagToArray(
+      const RepeatedField<T>& value, uint8* (*Writer)(T, uint8*),
+      uint8* target);
 
-  INL static uint8* WriteInt32NoTagToArray(const RepeatedField<int32>& value,
-                                           uint8* output);
-  INL static uint8* WriteInt64NoTagToArray(const RepeatedField<int64>& value,
-                                           uint8* output);
-  INL static uint8* WriteUInt32NoTagToArray(const RepeatedField<uint32>& value,
-                                            uint8* output);
-  INL static uint8* WriteUInt64NoTagToArray(const RepeatedField<uint64>& value,
-                                            uint8* output);
-  INL static uint8* WriteSInt32NoTagToArray(const RepeatedField<int32>& value,
-                                            uint8* output);
-  INL static uint8* WriteSInt64NoTagToArray(const RepeatedField<int64>& value,
-                                            uint8* output);
-  INL static uint8* WriteFixed32NoTagToArray(const RepeatedField<uint32>& value,
-                                             uint8* output);
-  INL static uint8* WriteFixed64NoTagToArray(const RepeatedField<uint64>& value,
-                                             uint8* output);
-  INL static uint8* WriteSFixed32NoTagToArray(const RepeatedField<int32>& value,
-                                              uint8* output);
-  INL static uint8* WriteSFixed64NoTagToArray(const RepeatedField<int64>& value,
-                                              uint8* output);
-  INL static uint8* WriteFloatNoTagToArray(const RepeatedField<float>& value,
-                                           uint8* output);
-  INL static uint8* WriteDoubleNoTagToArray(const RepeatedField<double>& value,
-                                            uint8* output);
-  INL static uint8* WriteBoolNoTagToArray(const RepeatedField<bool>& value,
-                                          uint8* output);
-  INL static uint8* WriteEnumNoTagToArray(const RepeatedField<int>& value,
-                                          uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt32NoTagToArray(
+      const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt64NoTagToArray(
+      const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt32NoTagToArray(
+      const RepeatedField<uint32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt64NoTagToArray(
+      const RepeatedField<uint64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt32NoTagToArray(
+      const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt64NoTagToArray(
+      const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed32NoTagToArray(
+      const RepeatedField<uint32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed64NoTagToArray(
+      const RepeatedField<uint64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed32NoTagToArray(
+      const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed64NoTagToArray(
+      const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFloatNoTagToArray(
+      const RepeatedField<float>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteDoubleNoTagToArray(
+      const RepeatedField<double>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteBoolNoTagToArray(
+      const RepeatedField<bool>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteEnumNoTagToArray(
+      const RepeatedField<int>& value, uint8* output);
 
   // Write fields, including tags.
-  INL static uint8* WriteInt32ToArray(int field_number, int32 value,
-                                      uint8* target);
-  INL static uint8* WriteInt64ToArray(int field_number, int64 value,
-                                      uint8* target);
-  INL static uint8* WriteUInt32ToArray(int field_number, uint32 value,
-                                       uint8* target);
-  INL static uint8* WriteUInt64ToArray(int field_number, uint64 value,
-                                       uint8* target);
-  INL static uint8* WriteSInt32ToArray(int field_number, int32 value,
-                                       uint8* target);
-  INL static uint8* WriteSInt64ToArray(int field_number, int64 value,
-                                       uint8* target);
-  INL static uint8* WriteFixed32ToArray(int field_number, uint32 value,
-                                        uint8* target);
-  INL static uint8* WriteFixed64ToArray(int field_number, uint64 value,
-                                        uint8* target);
-  INL static uint8* WriteSFixed32ToArray(int field_number, int32 value,
-                                         uint8* target);
-  INL static uint8* WriteSFixed64ToArray(int field_number, int64 value,
-                                         uint8* target);
-  INL static uint8* WriteFloatToArray(int field_number, float value,
-                                      uint8* target);
-  INL static uint8* WriteDoubleToArray(int field_number, double value,
-                                       uint8* target);
-  INL static uint8* WriteBoolToArray(int field_number, bool value,
-                                     uint8* target);
-  INL static uint8* WriteEnumToArray(int field_number, int value,
-                                     uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt32ToArray(int field_number,
+                                                         int32 value,
+                                                         uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt64ToArray(int field_number,
+                                                         int64 value,
+                                                         uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt32ToArray(int field_number,
+                                                          uint32 value,
+                                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt64ToArray(int field_number,
+                                                          uint64 value,
+                                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt32ToArray(int field_number,
+                                                          int32 value,
+                                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt64ToArray(int field_number,
+                                                          int64 value,
+                                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed32ToArray(int field_number,
+                                                           uint32 value,
+                                                           uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed64ToArray(int field_number,
+                                                           uint64 value,
+                                                           uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed32ToArray(int field_number,
+                                                            int32 value,
+                                                            uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed64ToArray(int field_number,
+                                                            int64 value,
+                                                            uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFloatToArray(int field_number,
+                                                         float value,
+                                                         uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteDoubleToArray(int field_number,
+                                                          double value,
+                                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteBoolToArray(int field_number,
+                                                        bool value,
+                                                        uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteEnumToArray(int field_number,
+                                                        int value,
+                                                        uint8* target);
 
   template <typename T>
-  INL static uint8* WritePrimitiveToArray(int field_number,
-                                          const RepeatedField<T>& value,
-                                          uint8* (*Writer)(int, T, uint8*),
-                                          uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WritePrimitiveToArray(
+      int field_number, const RepeatedField<T>& value,
+      uint8* (*Writer)(int, T, uint8*), uint8* target);
 
-  INL static uint8* WriteInt32ToArray(int field_number,
-                                      const RepeatedField<int32>& value,
-                                      uint8* output);
-  INL static uint8* WriteInt64ToArray(int field_number,
-                                      const RepeatedField<int64>& value,
-                                      uint8* output);
-  INL static uint8* WriteUInt32ToArray(int field_number,
-                                       const RepeatedField<uint32>& value,
-                                       uint8* output);
-  INL static uint8* WriteUInt64ToArray(int field_number,
-                                       const RepeatedField<uint64>& value,
-                                       uint8* output);
-  INL static uint8* WriteSInt32ToArray(int field_number,
-                                       const RepeatedField<int32>& value,
-                                       uint8* output);
-  INL static uint8* WriteSInt64ToArray(int field_number,
-                                       const RepeatedField<int64>& value,
-                                       uint8* output);
-  INL static uint8* WriteFixed32ToArray(int field_number,
-                                        const RepeatedField<uint32>& value,
-                                        uint8* output);
-  INL static uint8* WriteFixed64ToArray(int field_number,
-                                        const RepeatedField<uint64>& value,
-                                        uint8* output);
-  INL static uint8* WriteSFixed32ToArray(int field_number,
-                                         const RepeatedField<int32>& value,
-                                         uint8* output);
-  INL static uint8* WriteSFixed64ToArray(int field_number,
-                                         const RepeatedField<int64>& value,
-                                         uint8* output);
-  INL static uint8* WriteFloatToArray(int field_number,
-                                      const RepeatedField<float>& value,
-                                      uint8* output);
-  INL static uint8* WriteDoubleToArray(int field_number,
-                                       const RepeatedField<double>& value,
-                                       uint8* output);
-  INL static uint8* WriteBoolToArray(int field_number,
-                                     const RepeatedField<bool>& value,
-                                     uint8* output);
-  INL static uint8* WriteEnumToArray(int field_number,
-                                     const RepeatedField<int>& value,
-                                     uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt32ToArray(
+      int field_number, const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteInt64ToArray(
+      int field_number, const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt32ToArray(
+      int field_number, const RepeatedField<uint32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteUInt64ToArray(
+      int field_number, const RepeatedField<uint64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt32ToArray(
+      int field_number, const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSInt64ToArray(
+      int field_number, const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed32ToArray(
+      int field_number, const RepeatedField<uint32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFixed64ToArray(
+      int field_number, const RepeatedField<uint64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed32ToArray(
+      int field_number, const RepeatedField<int32>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteSFixed64ToArray(
+      int field_number, const RepeatedField<int64>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteFloatToArray(
+      int field_number, const RepeatedField<float>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteDoubleToArray(
+      int field_number, const RepeatedField<double>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteBoolToArray(
+      int field_number, const RepeatedField<bool>& value, uint8* output);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteEnumToArray(
+      int field_number, const RepeatedField<int>& value, uint8* output);
 
-  INL static uint8* WriteStringToArray(int field_number,
-                                       const std::string& value, uint8* target);
-  INL static uint8* WriteBytesToArray(int field_number,
-                                      const std::string& value, uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteStringToArray(
+      int field_number, const std::string& value, uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteBytesToArray(
+      int field_number, const std::string& value, uint8* target);
 
   // Whether to serialize deterministically (e.g., map keys are
   // sorted) is a property of a CodedOutputStream, and in the process
@@ -616,39 +631,33 @@
   // have a CodedOutputStream available, so they get an additional parameter
   // telling them whether to serialize deterministically.
   template <typename MessageType>
-  INL static uint8* InternalWriteGroupToArray(int field_number,
-                                              const MessageType& value,
-                                              uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteGroupToArray(
+      int field_number, const MessageType& value, uint8* target);
   template <typename MessageType>
-  INL static uint8* InternalWriteMessageToArray(int field_number,
-                                                const MessageType& value,
-                                                uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteMessageToArray(
+      int field_number, const MessageType& value, uint8* target);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
   // the subclass must not override SerializeWithCachedSizes()).
   template <typename MessageType>
-  INL static uint8* InternalWriteGroupNoVirtualToArray(int field_number,
-                                                       const MessageType& value,
-                                                       uint8* target);
+  PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteGroupNoVirtualToArray(
+      int field_number, const MessageType& value, uint8* target);
   template <typename MessageType>
-  INL static uint8* InternalWriteMessageNoVirtualToArray(
+  PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteMessageNoVirtualToArray(
       int field_number, const MessageType& value, uint8* target);
 
   // For backward-compatibility, the last four methods also have versions
   // that are non-deterministic always.
-  INL static uint8* WriteGroupToArray(int field_number,
-                                      const MessageLite& value, uint8* target) {
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteGroupToArray(
+      int field_number, const MessageLite& value, uint8* target) {
     return InternalWriteGroupToArray(field_number, value, target);
   }
-  INL static uint8* WriteMessageToArray(int field_number,
-                                        const MessageLite& value,
-                                        uint8* target) {
+  PROTOBUF_ALWAYS_INLINE static uint8* WriteMessageToArray(
+      int field_number, const MessageLite& value, uint8* target) {
     return InternalWriteMessageToArray(field_number, value, target);
   }
 
-#undef INL
-
   // Compute the byte size of a field.  The XxSize() functions do NOT include
   // the tag, so you must also call TagSize().  (This is because, for repeated
   // fields, you should only call TagSize() once and multiply it by the element
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
deleted file mode 100644
index 8b4522c..0000000
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
-#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
-
-// Please include wire_format_lite.h instead.
-
-#include <google/protobuf/wire_format_lite.h>
-
-#endif  // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 9833a69..c7277d9 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -385,7 +385,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* DoubleValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -404,8 +404,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -666,7 +665,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* FloatValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -685,8 +684,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -947,7 +945,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Int64Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -966,8 +964,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1230,7 +1227,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* UInt64Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1249,8 +1246,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1513,7 +1509,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* Int32Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1532,8 +1528,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -1796,7 +1791,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* UInt32Value::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -1815,8 +1810,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2079,7 +2073,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* BoolValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2098,8 +2092,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2367,7 +2360,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* StringValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2386,8 +2379,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }
@@ -2671,7 +2663,7 @@
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 const char* BytesValue::_InternalParse(const char* ptr, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext* ctx) {
-  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArena(); (void)arena;
+  ::PROTOBUF_NAMESPACE_ID::Arena* arena = GetArenaNoVirtual(); (void)arena;
   while (!ctx->Done(&ptr)) {
     ::PROTOBUF_NAMESPACE_ID::uint32 tag;
     ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
@@ -2690,8 +2682,7 @@
           ctx->SetLastTag(tag);
           return ptr;
         }
-        ptr = UnknownFieldParse(tag,
-          _internal_metadata_.mutable_unknown_fields(), ptr, ctx);
+        ptr = UnknownFieldParse(tag, &_internal_metadata_, ptr, ctx);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         break;
       }