Merge pull request #5332 from acozzette/integrate

Integrated internal changes from Google
diff --git a/BUILD b/BUILD
index 0130f55..80ae3e5 100644
--- a/BUILD
+++ b/BUILD
@@ -347,7 +347,6 @@
         "src/google/protobuf/compiler/plugin.pb.cc",
         "src/google/protobuf/compiler/python/python_generator.cc",
         "src/google/protobuf/compiler/ruby/ruby_generator.cc",
-        "src/google/protobuf/compiler/scc.cc",
         "src/google/protobuf/compiler/subprocess.cc",
         "src/google/protobuf/compiler/zip_writer.cc",
     ],
diff --git a/Makefile.am b/Makefile.am
index 0c86b93..309840a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1039,6 +1039,11 @@
   js/test8.proto                                                       \
   js/test9.proto                                                       \
   js/test10.proto                                                      \
+  js/test11.proto                                                      \
+  js/test12.proto                                                      \
+  js/test13.proto                                                      \
+  js/test14.proto                                                      \
+  js/test15.proto                                                      \
   js/test_bootstrap.js                                                 \
   js/testbinary.proto                                                  \
   js/testempty.proto
@@ -1084,14 +1089,17 @@
   examples/README.md                     \
   examples/WORKSPACE                     \
   examples/add_person.cc                 \
+  examples/add_person.dart               \
   examples/add_person.go                 \
   examples/add_person.py                 \
   examples/add_person_test.go            \
   examples/addressbook.proto             \
   examples/list_people.cc                \
+  examples/list_people.dart              \
   examples/list_people.go                \
   examples/list_people.py                \
   examples/list_people_test.go           \
+  examples/pubspec.yaml                  \
   protobuf.bzl                           \
   python/release/wheel/build_wheel_manylinux.sh  \
   python/release/wheel/Dockerfile                \
diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake
index 850a85a..063fc3d 100644
--- a/cmake/libprotoc.cmake
+++ b/cmake/libprotoc.cmake
@@ -78,7 +78,6 @@
   ${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
-  ${protobuf_source_dir}/src/google/protobuf/compiler/scc.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
   ${protobuf_source_dir}/src/google/protobuf/compiler/zip_writer.cc
 )
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 6995067..7affb95 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
index 9e37e9d..524ac06 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
@@ -113,7 +113,7 @@
   /// 01:30 UTC on January 15, 2017.
   ///
   /// In JavaScript, one can convert a Date object to this format using the
-  /// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+  /// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
   /// method. In Python, a standard `datetime.datetime` object can be converted
   /// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
   /// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 2c8929e..3c168e6 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -46,7 +46,6 @@
     implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -237,7 +236,7 @@
     ensureIsMutable();
     for (int i = 0; i < size; i++) {
       if (o.equals(array[i])) {
-        System.arraycopy(array, i + 1, array, i, size - i);
+        System.arraycopy(array, i + 1, array, i, size - i - 1);
         size--;
         modCount++;
         return true;
@@ -252,7 +251,7 @@
     ensureIndexInRange(index);
     boolean value = array[index];
     if (index < size - 1) {
-      System.arraycopy(array, index + 1, array, index, size - index);
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
     }
     size--;
     modCount++;
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 844d8a5..eca9ef1 100644
--- a/java/core/src/main/java/com/google/protobuf/ByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/ByteString.java
@@ -147,14 +147,23 @@
   public abstract byte byteAt(int index);
 
   /**
+   * Gets the byte at the given index, assumes bounds checking has already been performed.
+   *
+   * @param index index of byte
+   * @return the value
+   * @throws IndexOutOfBoundsException {@code index < 0 or index >= size}
+   */
+  abstract byte internalByteAt(int index);
+
+  /**
    * Return a {@link ByteString.ByteIterator} over the bytes in the ByteString. To avoid
    * auto-boxing, you may get the iterator manually and call {@link ByteIterator#nextByte()}.
    *
    * @return the iterator
    */
   @Override
-  public final ByteIterator iterator() {
-    return new ByteIterator() {
+  public ByteIterator iterator() {
+    return new AbstractByteIterator() {
       private int position = 0;
       private final int limit = size();
 
@@ -164,23 +173,13 @@
       }
 
       @Override
-      public Byte next() {
-        // Boxing calls Byte.valueOf(byte), which does not instantiate.
-        return nextByte();
-      }
-
-      @Override
       public byte nextByte() {
-        try {
-          return byteAt(position++);
-        } catch (IndexOutOfBoundsException e) {
-          throw new NoSuchElementException(e.getMessage());
+        int currentPos = position;
+        if (currentPos >= limit) {
+          throw new NoSuchElementException();
         }
-      }
-
-      @Override
-      public void remove() {
-        throw new UnsupportedOperationException();
+        position = currentPos + 1;
+        return internalByteAt(currentPos);
       }
     };
   }
@@ -198,6 +197,19 @@
     byte nextByte();
   }
 
+  abstract static class AbstractByteIterator implements ByteIterator {
+    @Override
+    public final Byte next() {
+      // Boxing calls Byte.valueOf(byte), which does not instantiate.
+      return nextByte();
+    }
+
+    @Override
+    public final void remove() {
+      throw new UnsupportedOperationException();
+    }
+  }
+
   /**
    * Gets the number of bytes.
    *
@@ -1281,6 +1293,11 @@
     }
 
     @Override
+    byte internalByteAt(int index) {
+      return bytes[index];
+    }
+
+    @Override
     public int size() {
       return bytes.length;
     }
@@ -1522,6 +1539,11 @@
     }
 
     @Override
+    byte internalByteAt(int index) {
+      return bytes[bytesOffset + index];
+    }
+
+    @Override
     public int size() {
       return bytesLength;
     }
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index df4cc66..161a1b6 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -2783,7 +2783,8 @@
                   sizeLimit - totalBytesRetired - bufferSize));
       if (bytesRead == 0 || bytesRead < -1 || bytesRead > buffer.length) {
         throw new IllegalStateException(
-            "InputStream#read(byte[]) returned invalid result: "
+            input.getClass()
+                + "#read(byte[]) returned invalid result: "
                 + bytesRead
                 + "\nThe InputStream implementation is buggy.");
       }
@@ -3005,20 +3006,46 @@
         throw InvalidProtocolBufferException.truncatedMessage();
       }
 
-      // Skipping more bytes than are in the buffer.  First skip what we have.
-      int tempPos = bufferSize - pos;
-      pos = bufferSize;
-
-      // Keep refilling the buffer until we get to the point we wanted to skip to.
-      // This has the side effect of ensuring the limits are updated correctly.
-      refillBuffer(1);
-      while (size - tempPos > bufferSize) {
-        tempPos += bufferSize;
+      if (refillCallback != null) {
+        // Skipping more bytes than are in the buffer.  First skip what we have.
+        int tempPos = bufferSize - pos;
         pos = bufferSize;
-        refillBuffer(1);
-      }
 
-      pos = size - tempPos;
+        // Keep refilling the buffer until we get to the point we wanted to skip to.
+        // This has the side effect of ensuring the limits are updated correctly.
+        refillBuffer(1);
+        while (size - tempPos > bufferSize) {
+          tempPos += bufferSize;
+          pos = bufferSize;
+          refillBuffer(1);
+        }
+
+        pos = size - tempPos;
+      } else {
+        // Skipping more bytes than are in the buffer.  First skip what we have.
+        totalBytesRetired += pos;
+        int totalSkipped = bufferSize - pos;
+        bufferSize = 0;
+        pos = 0;
+
+        try {
+          while (totalSkipped < size) {
+            int toSkip = size - totalSkipped;
+            long skipped = input.skip(toSkip);
+            if (skipped < 0 || skipped > toSkip) {
+              throw new IllegalStateException(
+                  input.getClass()
+                      + "#skip returned invalid result: "
+                      + skipped
+                      + "\nThe InputStream implementation is buggy.");
+            }
+            totalSkipped += (int) skipped;
+          }
+        } finally {
+          totalBytesRetired += totalSkipped;
+          recomputeBufferSizeAfterLimit();
+        }
+      }
     }
   }
 
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index e7b8fa8..d0fa9b7 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -46,7 +46,6 @@
     implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -104,7 +103,7 @@
 
     final double[] arr = other.array;
     for (int i = 0; i < size; i++) {
-      if (array[i] != arr[i]) {
+      if (Double.doubleToLongBits(array[i]) != Double.doubleToLongBits(arr[i])) {
         return false;
       }
     }
@@ -237,7 +236,7 @@
     ensureIsMutable();
     for (int i = 0; i < size; i++) {
       if (o.equals(array[i])) {
-        System.arraycopy(array, i + 1, array, i, size - i);
+        System.arraycopy(array, i + 1, array, i, size - i - 1);
         size--;
         modCount++;
         return true;
@@ -252,7 +251,7 @@
     ensureIndexInRange(index);
     double value = array[index];
     if (index < size - 1) {
-      System.arraycopy(array, index + 1, array, index, size - index);
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
     }
     size--;
     modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 85e09be..62330c3 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -46,7 +46,6 @@
     implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -104,7 +103,7 @@
 
     final float[] arr = other.array;
     for (int i = 0; i < size; i++) {
-      if (array[i] != arr[i]) {
+      if (Float.floatToIntBits(array[i]) != Float.floatToIntBits(arr[i])) {
         return false;
       }
     }
@@ -236,7 +235,7 @@
     ensureIsMutable();
     for (int i = 0; i < size; i++) {
       if (o.equals(array[i])) {
-        System.arraycopy(array, i + 1, array, i, size - i);
+        System.arraycopy(array, i + 1, array, i, size - i - 1);
         size--;
         modCount++;
         return true;
@@ -251,7 +250,7 @@
     ensureIndexInRange(index);
     float value = array[index];
     if (index < size - 1) {
-      System.arraycopy(array, index + 1, array, index, size - index);
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
     }
     size--;
     modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 0034c58..619ef09 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -451,16 +451,18 @@
     }
 
     @Override
-    public BuilderType mergeFrom(byte[] input, int offset, int length)
+    public BuilderType mergeFrom(
+        byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       // BEGIN REGULAR
-      return super.mergeFrom(input, offset, length);
+      return super.mergeFrom(input, offset, length, extensionRegistry);
       // END REGULAR
       // BEGIN EXPERIMENTAL
       // copyOnWrite();
       // try {
       //   Protobuf.getInstance().schemaFor(instance).mergeFrom(
-      //       instance, input, offset, offset + length, new ArrayDecoders.Registers());
+      //       instance, input, offset, offset + length,
+      //       new ArrayDecoders.Registers(extensionRegistry));
       // } catch (InvalidProtocolBufferException e) {
       //   throw e;
       // } catch (IndexOutOfBoundsException e) {
@@ -474,6 +476,18 @@
 
     @Override
     public BuilderType mergeFrom(
+        byte[] input, int offset, int length)
+        throws InvalidProtocolBufferException {
+      // BEGIN REGULAR
+      return super.mergeFrom(input, offset, length);
+      // END REGULAR
+      // BEGIN EXPERIMENTAL
+      // return mergeFrom(input, offset, length, ExtensionRegistryLite.getEmptyRegistry());
+      // END EXPERIMENTAL
+    }
+
+    @Override
+    public BuilderType mergeFrom(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws IOException {
@@ -483,6 +497,8 @@
         instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
         // END REGULAR
         // BEGIN EXPERIMENTAL
+        // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
+        // // fast path.
         // Protobuf.getInstance().schemaFor(instance).mergeFrom(
         //     instance, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
         // END EXPERIMENTAL
@@ -814,7 +830,7 @@
           .setField(extension.descriptor, extension.singularToFieldSetType(value));
     }
 
-    private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+    FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
       if (extensions.isImmutable()) {
         extensions = extensions.clone();
       }
@@ -1558,8 +1574,11 @@
     }
 
     @Override
-    public T parsePartialFrom(byte[] input) throws InvalidProtocolBufferException {
-      return GeneratedMessageLite.parsePartialFrom(defaultInstance, input);
+    public T parsePartialFrom(
+        byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return GeneratedMessageLite.parsePartialFrom(
+          defaultInstance, input, offset, length, extensionRegistry);
     }
   }
 
@@ -1578,6 +1597,8 @@
       result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry);
       // END REGULAR
       // BEGIN EXPERIMENTAL
+      // // TODO(yilunchong): Try to make input with type CodedInpuStream.ArrayDecoder use
+      // // fast path.
       // Protobuf.getInstance().schemaFor(result).mergeFrom(
       //     result, CodedInputStreamReader.forCodedInput(input), extensionRegistry);
       // END EXPERIMENTAL
@@ -1599,17 +1620,31 @@
   }
 
   /** A static helper method for parsing a partial from byte array. */
-  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(T instance, byte[] input)
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T instance, byte[] input, int offset, int length, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
     // BEGIN REGULAR
-    return parsePartialFrom(instance, input, ExtensionRegistryLite.getEmptyRegistry());
+    T message;
+    try {
+      CodedInputStream cis = CodedInputStream.newInstance(input, offset, length);
+      message = parsePartialFrom(instance, cis, extensionRegistry);
+      try {
+        cis.checkLastTagWas(0);
+      } catch (InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(message);
+      }
+      return message;
+    } catch (InvalidProtocolBufferException e) {
+      throw e;
+    }
     // END REGULAR
     // BEGIN EXPERIMENTAL
     // @SuppressWarnings("unchecked") // Guaranteed by protoc
     // T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE);
     // try {
     //   Protobuf.getInstance().schemaFor(result).mergeFrom(
-    //       result, input, 0, input.length, new ArrayDecoders.Registers());
+    //       result, input, offset, offset + length,
+    //       new ArrayDecoders.Registers(extensionRegistry));
     //   result.makeImmutable();
     //   if (result.memoizedHashCode != 0) {
     //     throw new RuntimeException();
@@ -1701,32 +1736,23 @@
   private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
       T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
-    T message;
-    try {
-      CodedInputStream input = CodedInputStream.newInstance(data);
-      message = parsePartialFrom(defaultInstance, input, extensionRegistry);
-      try {
-        input.checkLastTagWas(0);
-      } catch (InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(message);
-      }
-      return message;
-    } catch (InvalidProtocolBufferException e) {
-      throw e;
-    }
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
   }
 
   // Validates last tag.
   protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
       T defaultInstance, byte[] data) throws InvalidProtocolBufferException {
-    return checkMessageInitialized(parsePartialFrom(defaultInstance, data));
+    return checkMessageInitialized(parsePartialFrom(
+        defaultInstance, data, 0, data.length, ExtensionRegistryLite.getEmptyRegistry()));
   }
 
   // Validates last tag.
   protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
       T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry)
       throws InvalidProtocolBufferException {
-    return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
+    return checkMessageInitialized(
+        parsePartialFrom(defaultInstance, data, 0, data.length, extensionRegistry));
   }
 
   // Does not validate last tag.
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index c9b12c4..ad128b5 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -46,7 +46,6 @@
     implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final IntArrayList EMPTY_LIST = new IntArrayList();
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -236,7 +235,7 @@
     ensureIsMutable();
     for (int i = 0; i < size; i++) {
       if (o.equals(array[i])) {
-        System.arraycopy(array, i + 1, array, i, size - i);
+        System.arraycopy(array, i + 1, array, i, size - i - 1);
         size--;
         modCount++;
         return true;
@@ -251,7 +250,7 @@
     ensureIndexInRange(index);
     int value = array[index];
     if (index < size - 1) {
-      System.arraycopy(array, index + 1, array, index, size - index);
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
     }
     size--;
     modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index 8cdab12..99f7fdb 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -46,7 +46,6 @@
     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final LongArrayList EMPTY_LIST = new LongArrayList();
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -236,7 +235,7 @@
     ensureIsMutable();
     for (int i = 0; i < size; i++) {
       if (o.equals(array[i])) {
-        System.arraycopy(array, i + 1, array, i, size - i);
+        System.arraycopy(array, i + 1, array, i, size - i - 1);
         size--;
         modCount++;
         return true;
@@ -251,7 +250,7 @@
     ensureIndexInRange(index);
     long value = array[index];
     if (index < size - 1) {
-      System.arraycopy(array, index + 1, array, index, size - index);
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
     }
     size--;
     modCount++;
diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java
index 52b4a20..08f6244 100644
--- a/java/core/src/main/java/com/google/protobuf/Message.java
+++ b/java/core/src/main/java/com/google/protobuf/Message.java
@@ -149,8 +149,12 @@
     Descriptors.Descriptor getDescriptorForType();
 
     /**
-     * Create a Builder for messages of the appropriate type for the given field. Messages built
-     * with this can then be passed to setField(), setRepeatedField(), or addRepeatedField().
+     * Create a builder for messages of the appropriate type for the given field. The
+     * builder is NOT nested in the current builder. However, messages built with the
+     * builder can then be passed to the {@link #setField()}, {@link #setRepeatedField()}, or {@link
+     * #addRepeatedField()} method of the current builder.
+     *
+     * <p>To obtain a builder nested in the current builder, use {@link #getFieldBuilder()} instead.
      */
     Builder newBuilderForField(Descriptors.FieldDescriptor field);
 
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index 9fc72bd..cbcf938 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -334,6 +334,14 @@
     MergeTarget newMergeTargetForField(
         Descriptors.FieldDescriptor descriptor, Message defaultInstance);
 
+    /**
+     * Returns an empty merge target for a sub-field. When defaultInstance is provided, it indicates
+     * the descriptor is for an extension type, and implementations should create a new instance
+     * from the defaultInstance prototype directly.
+     */
+    MergeTarget newEmptyTargetForField(
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance);
+
     /** Finishes the merge and returns the underlying object. */
     Object finish();
   }
@@ -494,11 +502,31 @@
     @Override
     public MergeTarget newMergeTargetForField(
         Descriptors.FieldDescriptor field, Message defaultInstance) {
+      Message.Builder subBuilder;
       if (defaultInstance != null) {
-        return new BuilderAdapter(defaultInstance.newBuilderForType());
+        subBuilder = defaultInstance.newBuilderForType();
       } else {
-        return new BuilderAdapter(builder.newBuilderForField(field));
+        subBuilder = builder.newBuilderForField(field);
       }
+      if (!field.isRepeated()) {
+        Message originalMessage = (Message) getField(field);
+        if (originalMessage != null) {
+          subBuilder.mergeFrom(originalMessage);
+        }
+      }
+      return new BuilderAdapter(subBuilder);
+    }
+
+    @Override
+    public MergeTarget newEmptyTargetForField(
+        Descriptors.FieldDescriptor field, Message defaultInstance) {
+      Message.Builder subBuilder;
+      if (defaultInstance != null) {
+        subBuilder = defaultInstance.newBuilderForType();
+      } else {
+        subBuilder = builder.newBuilderForField(field);
+      }
+      return new BuilderAdapter(subBuilder);
     }
 
     @Override
@@ -662,6 +690,12 @@
     }
 
     @Override
+    public MergeTarget newEmptyTargetForField(
+        Descriptors.FieldDescriptor descriptor, Message defaultInstance) {
+      throw new UnsupportedOperationException("newEmptyTargetForField() called on FieldSet object");
+    }
+
+    @Override
     public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) {
       if (descriptor.needsUtf8Check()) {
         return WireFormat.Utf8Validation.STRICT;
diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java
index 64de6b1..64c46be 100644
--- a/java/core/src/main/java/com/google/protobuf/NioByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java
@@ -82,6 +82,13 @@
   }
 
   @Override
+  public byte internalByteAt(int index) {
+    // it isn't possible to avoid the bounds checking inside of ByteBuffer, so just use the default
+    // implementation.
+    return byteAt(index);
+  }
+
+  @Override
   public int size() {
     return buffer.remaining();
   }
diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
index 154fd5d..140cbe4 100644
--- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java
@@ -38,12 +38,12 @@
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
-import java.util.Stack;
 
 /**
  * Class to represent {@code ByteStrings} formed by concatenation of other ByteStrings, without
@@ -240,13 +240,17 @@
   @Override
   public byte byteAt(int index) {
     checkIndex(index, totalLength);
+    return internalByteAt(index);
+  }
 
+  @Override
+  byte internalByteAt(int index) {
     // Find the relevant piece by recursive descent
     if (index < leftLength) {
-      return left.byteAt(index);
+      return left.internalByteAt(index);
     }
 
-    return right.byteAt(index - leftLength);
+    return right.internalByteAt(index - leftLength);
   }
 
   @Override
@@ -254,6 +258,37 @@
     return totalLength;
   }
 
+  @Override
+  public ByteIterator iterator() {
+    return new AbstractByteIterator() {
+      final PieceIterator pieces = new PieceIterator(RopeByteString.this);
+      ByteIterator current = nextPiece();
+
+      private ByteIterator nextPiece() {
+        // NOTE: PieceIterator is guaranteed to return non-empty pieces, so this method will always
+        // return non-empty iterators (or null)
+        return pieces.hasNext() ? pieces.next().iterator() : null;
+      }
+
+      @Override
+      public boolean hasNext() {
+        return current != null;
+      }
+
+      @Override
+      public byte nextByte() {
+        if (current == null) {
+          throw new NoSuchElementException();
+        }
+        byte b = current.nextByte();
+        if (!current.hasNext()) {
+          current = nextPiece();
+        }
+        return b;
+      }
+    };
+  }
+
   // =================================================================
   // Pieces
 
@@ -546,7 +581,7 @@
     // Stack containing the part of the string, starting from the left, that
     // we've already traversed.  The final string should be the equivalent of
     // concatenating the strings on the stack from bottom to top.
-    private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
+    private final ArrayDeque<ByteString> prefixesStack = new ArrayDeque<>();
 
     private ByteString balance(ByteString left, ByteString right) {
       doBalance(left);
@@ -650,9 +685,8 @@
    *
    * <p>This iterator is used to implement {@link RopeByteString#equalsFragments(ByteString)}.
    */
-  private static class PieceIterator implements Iterator<LeafByteString> {
-
-    private final Stack<RopeByteString> breadCrumbs = new Stack<RopeByteString>();
+  private static final class PieceIterator implements Iterator<LeafByteString> {
+    private final ArrayDeque<RopeByteString> breadCrumbs = new ArrayDeque<>();
     private LeafByteString next;
 
     private PieceIterator(ByteString root) {
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index f89768a..aaea097 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -1127,6 +1127,7 @@
     PARSER.merge(input, builder);
   }
 
+
   /**
    * Parse a text-format message from {@code input}.
    *
@@ -1166,6 +1167,7 @@
     PARSER.merge(input, extensionRegistry, builder);
   }
 
+
   /**
    * Parse a text-format message from {@code input}. Extensions will be recognized if they are
    * registered in {@code extensionRegistry}.
@@ -1185,6 +1187,7 @@
   }
 
 
+
   /**
    * Parser for text-format proto2 instances. This class is thread-safe. The implementation largely
    * follows google/protobuf/text_format.cc.
@@ -1205,24 +1208,60 @@
      * </ul>
      */
     public enum SingularOverwritePolicy {
-      /** The last value is retained. */
+      /**
+       * Later values are merged with earlier values. For primitive fields or conflicting oneofs,
+       * the last value is retained.
+       */
       ALLOW_SINGULAR_OVERWRITES,
       /** An error is issued. */
       FORBID_SINGULAR_OVERWRITES
     }
 
+    /**
+     * Determines how to deal with repeated values for singular Message fields. For example,
+     * given a field "foo" containing subfields "baz" and "qux":
+     *
+     * <ul>
+     *   <li>"foo { baz: 1 } foo { baz: 2 }", or
+     *   <li>"foo { baz: 1 } foo { qux: 2 }"
+     * </ul>
+     */
+    public enum MergingStyle {
+      /**
+       * Merge the values in standard protobuf fashion:
+       *
+       * <ul>
+       *   <li>"foo { baz: 2 }" and
+       *   <li>"foo { baz: 1, qux: 2 }", respectively.
+       * </ul>
+       */
+      RECURSIVE,
+      /**
+       * Later values overwrite ("clobber") previous values:
+       *
+       * <ul>
+       *   <li>"foo { baz: 2 }" and
+       *   <li>"foo { qux: 2 }", respectively.
+       * </ul>
+       */
+      NON_RECURSIVE
+    }
+
     private final boolean allowUnknownFields;
     private final boolean allowUnknownEnumValues;
+    private final boolean allowUnknownExtensions;
     private final SingularOverwritePolicy singularOverwritePolicy;
     private TextFormatParseInfoTree.Builder parseInfoTreeBuilder;
 
     private Parser(
         boolean allowUnknownFields,
         boolean allowUnknownEnumValues,
+        boolean allowUnknownExtensions,
         SingularOverwritePolicy singularOverwritePolicy,
         TextFormatParseInfoTree.Builder parseInfoTreeBuilder) {
       this.allowUnknownFields = allowUnknownFields;
       this.allowUnknownEnumValues = allowUnknownEnumValues;
+      this.allowUnknownExtensions = allowUnknownExtensions;
       this.singularOverwritePolicy = singularOverwritePolicy;
       this.parseInfoTreeBuilder = parseInfoTreeBuilder;
     }
@@ -1236,11 +1275,23 @@
     public static class Builder {
       private boolean allowUnknownFields = false;
       private boolean allowUnknownEnumValues = false;
+      private boolean allowUnknownExtensions = false;
       private SingularOverwritePolicy singularOverwritePolicy =
           SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES;
       private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null;
 
 
+      /**
+       * Set whether this parser will allow unknown extensions. By default, an
+       * exception is thrown if unknown extension is encountered. If this is set true,
+       * the parser will only log a warning. Allow unknown extensions does not mean
+       * allow normal unknown fields.
+       */
+      public Builder setAllowUnknownExtensions(boolean allowUnknownExtensions) {
+        this.allowUnknownExtensions = allowUnknownExtensions;
+        return this;
+      }
+
       /** Sets parser behavior when a non-repeated field appears more than once. */
       public Builder setSingularOverwritePolicy(SingularOverwritePolicy p) {
         this.singularOverwritePolicy = p;
@@ -1256,6 +1307,7 @@
         return new Parser(
             allowUnknownFields,
             allowUnknownEnumValues,
+            allowUnknownExtensions,
             singularOverwritePolicy,
             parseInfoTreeBuilder);
       }
@@ -1297,6 +1349,7 @@
     }
 
 
+
     private static final int BUFFER_SIZE = 4096;
 
     // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
@@ -1315,25 +1368,56 @@
       return text;
     }
 
+    static final class UnknownField {
+      static enum Type {
+        FIELD, EXTENSION;
+      }
+
+      final String message;
+      final Type type;
+
+      UnknownField(String message, Type type) {
+        this.message = message;
+        this.type = type;
+      }
+    }
+
     // Check both unknown fields and unknown extensions and log warning messages
     // or throw exceptions according to the flag.
-    private void checkUnknownFields(final List<String> unknownFields) throws ParseException {
+    private void checkUnknownFields(final List<UnknownField> unknownFields) throws ParseException {
       if (unknownFields.isEmpty()) {
         return;
       }
 
       StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:");
-      for (String field : unknownFields) {
-        msg.append('\n').append(field);
+      for (UnknownField field : unknownFields) {
+        msg.append('\n').append(field.message);
       }
 
       if (allowUnknownFields) {
         logger.warning(msg.toString());
-      } else {
-        String[] lineColumn = unknownFields.get(0).split(":");
-        throw new ParseException(
-            Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
+        return;
       }
+
+      int firstErrorIndex = 0;
+      if (allowUnknownExtensions) {
+        boolean allUnknownExtensions = true;
+        for (UnknownField field : unknownFields) {
+          if (field.type == UnknownField.Type.FIELD) {
+            allUnknownExtensions = false;
+            break;
+          }
+          ++firstErrorIndex;
+        }
+        if (allUnknownExtensions) {
+          logger.warning(msg.toString());
+          return;
+        }
+      }
+
+      String[] lineColumn = unknownFields.get(firstErrorIndex).message.split(":");
+      throw new ParseException(
+          Integer.parseInt(lineColumn[0]), Integer.parseInt(lineColumn[1]), msg.toString());
     }
 
     /**
@@ -1348,24 +1432,32 @@
       final Tokenizer tokenizer = new Tokenizer(input);
       MessageReflection.BuilderAdapter target = new MessageReflection.BuilderAdapter(builder);
 
-      List<String> unknownFields = new ArrayList<String>();
+      List<UnknownField> unknownFields = new ArrayList<UnknownField>();
 
       while (!tokenizer.atEnd()) {
-        mergeField(tokenizer, extensionRegistry, target, unknownFields);
+        mergeField(tokenizer, extensionRegistry, target, MergingStyle.RECURSIVE, unknownFields);
       }
 
       checkUnknownFields(unknownFields);
     }
 
 
+
     /** Parse a single field from {@code tokenizer} and merge it into {@code builder}. */
     private void mergeField(
         final Tokenizer tokenizer,
         final ExtensionRegistry extensionRegistry,
         final MessageReflection.MergeTarget target,
-        List<String> unknownFields)
+        final MergingStyle mergingStyle,
+        List<UnknownField> unknownFields)
         throws ParseException {
-      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, unknownFields);
+      mergeField(
+          tokenizer,
+          extensionRegistry,
+          target,
+          parseInfoTreeBuilder,
+          mergingStyle,
+          unknownFields);
     }
 
     /** Parse a single field from {@code tokenizer} and merge it into {@code target}. */
@@ -1374,7 +1466,8 @@
         final ExtensionRegistry extensionRegistry,
         final MessageReflection.MergeTarget target,
         TextFormatParseInfoTree.Builder parseTreeBuilder,
-        List<String> unknownFields)
+        final MergingStyle mergingStyle,
+        List<UnknownField> unknownFields)
         throws ParseException {
       FieldDescriptor field = null;
       int startLine = tokenizer.getLine();
@@ -1393,15 +1486,15 @@
         extension = target.findExtensionByName(extensionRegistry, name.toString());
 
         if (extension == null) {
-          unknownFields.add(
-              (tokenizer.getPreviousLine() + 1)
-                  + ":"
-                  + (tokenizer.getPreviousColumn() + 1)
-                  + ":\t"
-                  + type.getFullName()
-                  + ".["
-                  + name
-                  + "]");
+          String message = (tokenizer.getPreviousLine() + 1)
+                           + ":"
+                           + (tokenizer.getPreviousColumn() + 1)
+                           + ":\t"
+                           + type.getFullName()
+                           + ".["
+                           + name
+                           + "]";
+          unknownFields.add(new UnknownField(message, UnknownField.Type.EXTENSION));
         } else {
           if (extension.descriptor.getContainingType() != type) {
             throw tokenizer.parseExceptionPreviousToken(
@@ -1440,14 +1533,14 @@
         }
 
         if (field == null) {
-          unknownFields.add(
-              (tokenizer.getPreviousLine() + 1)
-                  + ":"
-                  + (tokenizer.getPreviousColumn() + 1)
-                  + ":\t"
-                  + type.getFullName()
-                  + "."
-                  + name);
+          String message = (tokenizer.getPreviousLine() + 1)
+                           + ":"
+                           + (tokenizer.getPreviousColumn() + 1)
+                           + ":\t"
+                           + type.getFullName()
+                           + "."
+                           + name;
+          unknownFields.add(new UnknownField(message, UnknownField.Type.FIELD));
         }
       }
 
@@ -1480,6 +1573,7 @@
               field,
               extension,
               childParseTreeBuilder,
+              mergingStyle,
               unknownFields);
         } else {
           consumeFieldValues(
@@ -1489,6 +1583,7 @@
               field,
               extension,
               parseTreeBuilder,
+              mergingStyle,
               unknownFields);
         }
       } else {
@@ -1500,6 +1595,7 @@
             field,
             extension,
             parseTreeBuilder,
+            mergingStyle,
             unknownFields);
       }
 
@@ -1524,7 +1620,8 @@
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
         final TextFormatParseInfoTree.Builder parseTreeBuilder,
-        List<String> unknownFields)
+        final MergingStyle mergingStyle,
+        List<UnknownField> unknownFields)
         throws ParseException {
       // Support specifying repeated field values as a comma-separated list.
       // Ex."foo: [1, 2, 3]"
@@ -1538,6 +1635,7 @@
                 field,
                 extension,
                 parseTreeBuilder,
+                mergingStyle,
                 unknownFields);
             if (tokenizer.tryConsume("]")) {
               // End of list.
@@ -1554,6 +1652,7 @@
             field,
             extension,
             parseTreeBuilder,
+            mergingStyle,
             unknownFields);
       }
     }
@@ -1566,8 +1665,28 @@
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
         final TextFormatParseInfoTree.Builder parseTreeBuilder,
-        List<String> unknownFields)
+        final MergingStyle mergingStyle,
+        List<UnknownField> unknownFields)
         throws ParseException {
+      if (singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES
+          && !field.isRepeated()) {
+        if (target.hasField(field)) {
+          throw tokenizer.parseExceptionPreviousToken(
+              "Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
+        } else if (field.getContainingOneof() != null
+            && target.hasOneof(field.getContainingOneof())) {
+          Descriptors.OneofDescriptor oneof = field.getContainingOneof();
+          throw tokenizer.parseExceptionPreviousToken(
+              "Field \""
+                  + field.getFullName()
+                  + "\" is specified along with field \""
+                  + target.getOneofFieldDescriptor(oneof).getFullName()
+                  + "\", another member of oneof \""
+                  + oneof.getName()
+                  + "\".");
+        }
+      }
+
       Object value = null;
 
       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
@@ -1580,15 +1699,29 @@
         }
 
         final MessageReflection.MergeTarget subField;
-        subField =
-            target.newMergeTargetForField(
-                field, (extension == null) ? null : extension.defaultInstance);
+        Message defaultInstance = (extension == null) ? null : extension.defaultInstance;
+        switch (mergingStyle) {
+          case RECURSIVE:
+            subField = target.newMergeTargetForField(field, defaultInstance);
+            break;
+          case NON_RECURSIVE:
+            subField = target.newEmptyTargetForField(field, defaultInstance);
+            break;
+          default:
+            throw new AssertionError();
+        }
 
         while (!tokenizer.tryConsume(endToken)) {
           if (tokenizer.atEnd()) {
             throw tokenizer.parseException("Expected \"" + endToken + "\".");
           }
-          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, unknownFields);
+          mergeField(
+              tokenizer,
+              extensionRegistry,
+              subField,
+              parseTreeBuilder,
+              mergingStyle,
+              unknownFields);
         }
 
         value = subField.finish();
@@ -1693,22 +1826,6 @@
         // TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
         //     check for duplicate map keys here.
         target.addRepeatedField(field, value);
-      } else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
-          && target.hasField(field)) {
-        throw tokenizer.parseExceptionPreviousToken(
-            "Non-repeated field \"" + field.getFullName() + "\" cannot be overwritten.");
-      } else if ((singularOverwritePolicy == SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
-          && field.getContainingOneof() != null
-          && target.hasOneof(field.getContainingOneof())) {
-        Descriptors.OneofDescriptor oneof = field.getContainingOneof();
-        throw tokenizer.parseExceptionPreviousToken(
-            "Field \""
-                + field.getFullName()
-                + "\" is specified along with field \""
-                + target.getOneofFieldDescriptor(oneof).getFullName()
-                + "\", another member of oneof \""
-                + oneof.getName()
-                + "\".");
       } else {
         target.setField(field, value);
       }
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
index 50bc911..17df54a 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -83,6 +83,15 @@
   }
 
 
+  @SuppressWarnings("unchecked") // safe by method contract
+  static <T> T allocateInstance(Class<T> clazz) {
+    try {
+      return (T) UNSAFE.allocateInstance(clazz);
+    } catch (InstantiationException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   static long objectFieldOffset(Field field) {
     return MEMORY_ACCESSOR.objectFieldOffset(field);
   }
diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
index 1020c69..cc979ac 100644
--- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -522,8 +522,8 @@
   /**
    * Asserts that the given protos are not equal and have different hash codes.
    *
-   * @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
-   *     than it needs to be. However, this should happen relatively rarely.
+   * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
+   * stricter than it needs to be. However, this should happen relatively rarely.
    */
   private void checkNotEqual(Message m1, Message m2) {
     String equalsError = String.format("%s should not be equal to %s", m1, m2);
diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java
index 2fe04a9..d660ca7 100644
--- a/java/core/src/test/java/com/google/protobuf/AnyTest.java
+++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java
@@ -35,17 +35,14 @@
 import java.util.Objects;
 import junit.framework.TestCase;
 
-/**
- * Unit tests for Any message.
- */
+/** Unit tests for Any message. */
 public class AnyTest extends TestCase {
   public void testAnyGeneratedApi() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestUtil.setAllFields(builder);
     TestAllTypes message = builder.build();
 
-    TestAny container = TestAny.newBuilder()
-        .setValue(Any.pack(message)).build();
+    TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
 
     assertTrue(container.getValue().is(TestAllTypes.class));
     assertFalse(container.getValue().is(TestAny.class));
@@ -64,8 +61,7 @@
 
     // Test that unpacking throws an exception if parsing fails.
     TestAny.Builder containerBuilder = container.toBuilder();
-    containerBuilder.getValueBuilder().setValue(
-        ByteString.copyFrom(new byte[]{0x11}));
+    containerBuilder.getValueBuilder().setValue(ByteString.copyFrom(new byte[] {0x11}));
     container = containerBuilder.build();
     try {
       container.getValue().unpack(TestAllTypes.class);
@@ -80,12 +76,10 @@
     TestUtil.setAllFields(builder);
     TestAllTypes message = builder.build();
 
-    TestAny container = TestAny.newBuilder()
-        .setValue(Any.pack(message, "xxx.com")).build();
+    TestAny container = TestAny.newBuilder().setValue(Any.pack(message, "xxx.com")).build();
 
     assertEquals(
-        "xxx.com/" + TestAllTypes.getDescriptor().getFullName(),
-        container.getValue().getTypeUrl());
+        "xxx.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
 
     assertTrue(container.getValue().is(TestAllTypes.class));
     assertFalse(container.getValue().is(TestAny.class));
@@ -93,12 +87,10 @@
     TestAllTypes result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
 
-    container = TestAny.newBuilder()
-        .setValue(Any.pack(message, "yyy.com/")).build();
+    container = TestAny.newBuilder().setValue(Any.pack(message, "yyy.com/")).build();
 
     assertEquals(
-        "yyy.com/" + TestAllTypes.getDescriptor().getFullName(),
-        container.getValue().getTypeUrl());
+        "yyy.com/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
 
     assertTrue(container.getValue().is(TestAllTypes.class));
     assertFalse(container.getValue().is(TestAny.class));
@@ -106,12 +98,10 @@
     result = container.getValue().unpack(TestAllTypes.class);
     TestUtil.assertAllFieldsSet(result);
 
-    container = TestAny.newBuilder()
-        .setValue(Any.pack(message, "")).build();
+    container = TestAny.newBuilder().setValue(Any.pack(message, "")).build();
 
     assertEquals(
-        "/" + TestAllTypes.getDescriptor().getFullName(),
-        container.getValue().getTypeUrl());
+        "/" + TestAllTypes.getDescriptor().getFullName(), container.getValue().getTypeUrl());
 
     assertTrue(container.getValue().is(TestAllTypes.class));
     assertFalse(container.getValue().is(TestAny.class));
@@ -125,8 +115,7 @@
     TestUtil.setAllFields(builder);
     TestAllTypes message = builder.build();
 
-    TestAny container = TestAny.newBuilder()
-        .setValue(Any.pack(message)).build();
+    TestAny container = TestAny.newBuilder().setValue(Any.pack(message)).build();
 
     assertTrue(container.getValue().is(TestAllTypes.class));
 
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index 8ef8edd..ae50071 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -77,10 +77,10 @@
     list.addAll(asList(true, false, true, false));
     Iterator<Boolean> iterator = list.iterator();
     assertEquals(4, list.size());
-    assertTrue(list.get(0));
-    assertTrue(iterator.next());
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, (boolean) iterator.next());
     list.set(0, true);
-    assertFalse(iterator.next());
+    assertEquals(false, (boolean) iterator.next());
 
     list.remove(0);
     try {
@@ -101,9 +101,9 @@
   }
 
   public void testGet() {
-    assertTrue(TERTIARY_LIST.get(0));
-    assertFalse(TERTIARY_LIST.get(1));
-    assertTrue(TERTIARY_LIST.get(2));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(0));
+    assertEquals(false, (boolean) TERTIARY_LIST.get(1));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(2));
 
     try {
       TERTIARY_LIST.get(-1);
@@ -121,9 +121,9 @@
   }
 
   public void testGetBoolean() {
-    assertTrue(TERTIARY_LIST.getBoolean(0));
-    assertFalse(TERTIARY_LIST.getBoolean(1));
-    assertTrue(TERTIARY_LIST.getBoolean(2));
+    assertEquals(true, TERTIARY_LIST.getBoolean(0));
+    assertEquals(false, TERTIARY_LIST.getBoolean(1));
+    assertEquals(true, TERTIARY_LIST.getBoolean(2));
 
     try {
       TERTIARY_LIST.get(-1);
@@ -162,11 +162,11 @@
     list.addBoolean(false);
     list.addBoolean(false);
 
-    assertFalse(list.set(0, true));
-    assertTrue(list.getBoolean(0));
+    assertEquals(false, (boolean) list.set(0, true));
+    assertEquals(true, list.getBoolean(0));
 
-    assertFalse(list.set(1, false));
-    assertFalse(list.getBoolean(1));
+    assertEquals(false, (boolean) list.set(1, false));
+    assertEquals(false, list.getBoolean(1));
 
     try {
       list.set(-1, false);
@@ -187,11 +187,11 @@
     list.addBoolean(true);
     list.addBoolean(true);
 
-    assertTrue(list.setBoolean(0, false));
-    assertFalse(list.getBoolean(0));
+    assertEquals(true, list.setBoolean(0, false));
+    assertEquals(false, list.getBoolean(0));
 
-    assertTrue(list.setBoolean(1, false));
-    assertFalse(list.getBoolean(1));
+    assertEquals(true, list.setBoolean(1, false));
+    assertEquals(false, list.getBoolean(1));
 
     try {
       list.setBoolean(-1, false);
@@ -255,8 +255,8 @@
 
     assertTrue(list.addAll(Collections.singleton(true)));
     assertEquals(1, list.size());
-    assertTrue(list.get(0));
-    assertTrue(list.getBoolean(0));
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, list.getBoolean(0));
 
     assertTrue(list.addAll(asList(false, true, false, true, false)));
     assertEquals(asList(true, false, true, false, true, false), list);
@@ -268,9 +268,16 @@
     assertFalse(list.addAll(BooleanArrayList.emptyList()));
   }
 
+  public void testEquals() {
+    BooleanArrayList list1 = new BooleanArrayList();
+    BooleanArrayList list2 = new BooleanArrayList();
+
+    assertEquals(list1, list2);
+  }
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertTrue(list.remove(0));
+    assertEquals(true, (boolean) list.remove(0));
     assertEquals(asList(false, true), list);
 
     assertTrue(list.remove(Boolean.TRUE));
@@ -279,7 +286,7 @@
     assertFalse(list.remove(Boolean.TRUE));
     assertEquals(asList(false), list);
 
-    assertFalse(list.remove(0));
+    assertEquals(false, (boolean) list.remove(0));
     assertEquals(asList(), list);
 
     try {
@@ -296,13 +303,22 @@
     }
   }
 
-  public void testRemoveEndOfCapacity() {
+  public void testRemoveEnd_listAtCapacity() {
     BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
   }
 
+  public void testRemove_listAtCapacity() {
+    BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(2);
+    toRemove.addBoolean(true);
+    toRemove.addBoolean(false);
+    toRemove.remove(0);
+    assertEquals(1, toRemove.size());
+    assertEquals(false, (boolean) toRemove.get(0));
+  }
+
   public void testSublistRemoveEndOfCapacity() {
     BooleanList toRemove = BooleanArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addBoolean(true);
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index f64df33..998f4d5 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import static org.junit.Assert.assertArrayEquals;
 import protobuf_unittest.UnittestProto.BoolMessage;
 import protobuf_unittest.UnittestProto.Int32Message;
 import protobuf_unittest.UnittestProto.Int64Message;
@@ -51,9 +52,9 @@
  * @author kenton@google.com Kenton Varda
  */
 public class CodedInputStreamTest extends TestCase {
-  
-  private static final int DEFAULT_BLOCK_SIZE = 4096; 
-  
+
+  private static final int DEFAULT_BLOCK_SIZE = 4096;
+
   private enum InputType {
     ARRAY {
       @Override
@@ -88,10 +89,10 @@
         if (blockSize > DEFAULT_BLOCK_SIZE) {
           blockSize = DEFAULT_BLOCK_SIZE;
         }
-        ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+        ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
         for (int i = 0; i < data.length; i += blockSize) {
-          int rl = Math.min(blockSize, data.length - i); 
-          ByteBuffer rb = ByteBuffer.allocateDirect(rl); 
+          int rl = Math.min(blockSize, data.length - i);
+          ByteBuffer rb = ByteBuffer.allocateDirect(rl);
           rb.put(data, i, rl);
           rb.flip();
           input.add(rb);
@@ -105,10 +106,10 @@
         if (blockSize > DEFAULT_BLOCK_SIZE) {
           blockSize = DEFAULT_BLOCK_SIZE;
         }
-        ArrayList <ByteBuffer> input = new ArrayList <ByteBuffer>();
+        ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
         for (int i = 0; i < data.length; i += blockSize) {
-          int rl = Math.min(blockSize, data.length - i); 
-          ByteBuffer rb = ByteBuffer.allocateDirect(rl); 
+          int rl = Math.min(blockSize, data.length - i);
+          ByteBuffer rb = ByteBuffer.allocateDirect(rl);
           rb.put(data, i, rl);
           rb.flip();
           input.add(rb);
@@ -116,8 +117,6 @@
         return CodedInputStream.newInstance(new IterableByteBufferInputStream(input));
       }
     };
-    
-    
 
     CodedInputStream newDecoder(byte[] data) {
       return newDecoder(data, data.length);
@@ -144,6 +143,8 @@
    */
   private static final class SmallBlockInputStream extends FilterInputStream {
     private final int blockSize;
+    private int skipCalls;
+    private int readCalls;
 
     public SmallBlockInputStream(byte[] data, int blockSize) {
       super(new ByteArrayInputStream(data));
@@ -151,14 +152,28 @@
     }
 
     @Override
+    public int read() throws IOException {
+      readCalls++;
+      return super.read();
+    }
+
+    @Override
     public int read(byte[] b) throws IOException {
+      readCalls++;
       return super.read(b, 0, Math.min(b.length, blockSize));
     }
 
     @Override
     public int read(byte[] b, int off, int len) throws IOException {
+      readCalls++;
       return super.read(b, off, Math.min(len, blockSize));
     }
+
+    @Override
+    public long skip(long len) throws IOException {
+      skipCalls++;
+      return super.skip(Math.min(len, blockSize));
+    }
   }
 
   private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
@@ -430,6 +445,41 @@
     }
   }
 
+  /**
+   * Test that calling skipRawBytes (when not merging a message) actually skips from the underlying
+   * inputstream, regardless of the buffer size used.
+   */
+  public void testSkipRawBytesActuallySkips() throws Exception {
+    SmallBlockInputStream bytes = new SmallBlockInputStream(new byte[] {1, 2, 3, 4, 5}, 3);
+    CodedInputStream input = CodedInputStream.newInstance(bytes, 1); // Tiny buffer
+    input.skipRawBytes(3);
+    input.skipRawBytes(2);
+    assertEquals(2, bytes.skipCalls);
+    assertEquals(0, bytes.readCalls);
+  }
+
+  public void testSkipHugeBlob() throws Exception {
+    // Allocate and initialize a 1MB blob.
+    int blobSize = 1 << 20;
+    byte[] blob = new byte[blobSize];
+    for (int i = 0; i < blob.length; i++) {
+      blob[i] = (byte) i;
+    }
+
+    for (InputType inputType : InputType.values()) {
+      CodedInputStream decoder = inputType.newDecoder(blob);
+      decoder.skipRawBytes(blobSize - 10);
+      byte[] remaining = decoder.readRawBytes(10);
+      assertArrayEquals(Arrays.copyOfRange(blob, blobSize - 10, blobSize), remaining);
+    }
+  }
+
+  /** Skipping a huge blob should not allocate excessive memory, so there should be no limit */
+  public void testSkipMaliciouslyHugeBlob() throws Exception {
+    InputStream is = new RepeatingInputStream(new byte[]{1}, Integer.MAX_VALUE);
+    CodedInputStream.newInstance(is).skipRawBytes(Integer.MAX_VALUE);
+  }
+
   public void testReadHugeBlob() throws Exception {
     // Allocate and initialize a 1MB blob.
     byte[] blob = new byte[1 << 20];
@@ -485,8 +535,9 @@
   }
 
   /**
-   * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT
-   * in size (2G or Integer#MAX_SIZE).
+   * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or
+   * Integer#MAX_SIZE).
+   *
    * @throws IOException
    */
   public void testParseMessagesCloseTo2G() throws IOException {
@@ -501,8 +552,9 @@
   }
 
   /**
-   * Test there is an exception if a message exceeds
-   * CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE).
+   * Test there is an exception if a message exceeds CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G
+   * or Integer#MAX_SIZE).
+   *
    * @throws IOException
    */
   public void testParseMessagesOver2G() throws IOException {
@@ -526,7 +578,7 @@
    * @return A serialized big message.
    */
   private static byte[] getBigSerializedMessage() {
-    byte[] value = new byte[16 * 1024 * 1024]; 
+    byte[] value = new byte[16 * 1024 * 1024];
     ByteString bsValue = ByteString.wrap(value);
     return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArray();
   }
@@ -654,7 +706,7 @@
       checkSizeLimitExceeded(expected);
     }
   }
-  
+
   public void testRefillBufferWithCorrectSize() throws Exception {
     // NOTE: refillBuffer only applies to the stream-backed CIS.
     byte[] bytes = "123456789".getBytes("UTF-8");
@@ -672,14 +724,15 @@
     output.flush();
 
     // Input is two string with length 9 and one raw byte.
-    byte[] rawInput = rawOutput.toByteArray(); 
-    for (int inputStreamBufferLength = 8; 
-        inputStreamBufferLength <= rawInput.length + 1; inputStreamBufferLength++) {
-      CodedInputStream input = CodedInputStream.newInstance(
-              new ByteArrayInputStream(rawInput), inputStreamBufferLength);
+    byte[] rawInput = rawOutput.toByteArray();
+    for (int inputStreamBufferLength = 8;
+        inputStreamBufferLength <= rawInput.length + 1;
+        inputStreamBufferLength++) {
+      CodedInputStream input =
+          CodedInputStream.newInstance(new ByteArrayInputStream(rawInput), inputStreamBufferLength);
       input.setSizeLimit(rawInput.length - 1);
       input.readString();
-      input.readString(); 
+      input.readString();
       try {
         input.readRawByte(); // Hits limit.
         fail("Should have thrown an exception!");
@@ -690,9 +743,8 @@
   }
 
   public void testIsAtEnd() throws Exception {
-    CodedInputStream input = CodedInputStream.newInstance(
-        new ByteArrayInputStream(new byte[5]));
-    try {   
+    CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(new byte[5]));
+    try {
       for (int i = 0; i < 5; i++) {
         assertEquals(false, input.isAtEnd());
         input.readRawByte();
@@ -715,19 +767,18 @@
     output.flush();
 
     byte[] rawInput = rawOutput.toByteArray();
-    CodedInputStream input = CodedInputStream.newInstance(
-              new ByteArrayInputStream(rawInput));
+    CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(rawInput));
     // The length of the whole rawInput
     input.setSizeLimit(11);
     // Some number that is smaller than the rawInput's length
-    // but larger than 2 
+    // but larger than 2
     input.pushLimit(5);
     try {
       input.readString();
       fail("Should have thrown an exception");
     } catch (InvalidProtocolBufferException expected) {
-      assertEquals(expected.getMessage(), 
-          InvalidProtocolBufferException.truncatedMessage().getMessage());
+      assertEquals(
+          expected.getMessage(), InvalidProtocolBufferException.truncatedMessage().getMessage());
     }
   }
 
@@ -936,13 +987,14 @@
     output.flush();
     byte[] data = rawOutput.toByteString().toByteArray();
 
-    CodedInputStream input = CodedInputStream.newInstance(
-        new ByteArrayInputStream(data) {
-          @Override
-          public synchronized int available() {
-            return 0;
-          }
-        });
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new ByteArrayInputStream(data) {
+              @Override
+              public synchronized int available() {
+                return 0;
+              }
+            });
     ByteString result = input.readBytes();
     assertEquals(ByteString.copyFrom(bytes), result);
   }
@@ -959,13 +1011,14 @@
     output.flush();
     byte[] data = rawOutput.toByteString().toByteArray();
 
-    CodedInputStream input = CodedInputStream.newInstance(
-        new ByteArrayInputStream(data) {
-          @Override
-          public synchronized int available() {
-            return 0;
-          }
-        });
+    CodedInputStream input =
+        CodedInputStream.newInstance(
+            new ByteArrayInputStream(data) {
+              @Override
+              public synchronized int available() {
+                return 0;
+              }
+            });
     byte[] result = input.readByteArray();
     assertTrue(Arrays.equals(bytes, result));
   }
@@ -1034,8 +1087,8 @@
     byte[] data = byteArrayStream.toByteArray();
 
     for (InputType inputType : InputType.values()) {
-      if (inputType == InputType.STREAM 
-          || inputType == InputType.STREAM_ITER_DIRECT 
+      if (inputType == InputType.STREAM
+          || inputType == InputType.STREAM_ITER_DIRECT
           || inputType == InputType.ITER_DIRECT) {
         // Aliasing doesn't apply to stream-backed CIS.
         continue;
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index b60cd62..5f91324 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -79,8 +79,7 @@
   private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
 
   public void testFieldTypeEnumMapping() throws Exception {
-    assertEquals(FieldDescriptor.Type.values().length,
-        FieldDescriptorProto.Type.values().length);
+    assertEquals(FieldDescriptor.Type.values().length, FieldDescriptorProto.Type.values().length);
     for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
       FieldDescriptorProto.Type protoType = type.toProto();
       assertEquals("TYPE_" + type.name(), protoType.name());
@@ -95,11 +94,9 @@
     assertEquals("protobuf_unittest", file.getPackage());
 
     assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
-    assertEquals("google/protobuf/unittest.proto",
-                 file.toProto().getName());
+    assertEquals("google/protobuf/unittest.proto", file.toProto().getName());
 
-    assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
-                 file.getDependencies());
+    assertEquals(Arrays.asList(UnittestImport.getDescriptor()), file.getDependencies());
 
     Descriptor messageType = TestAllTypes.getDescriptor();
     assertEquals(messageType, file.getMessageTypes().get(0));
@@ -115,9 +112,9 @@
     assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
     assertNull(file.findEnumTypeByName("NoSuchType"));
     assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
-    assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
-                               ImportEnumForMap.getDescriptor()),
-                 UnittestImport.getDescriptor().getEnumTypes());
+    assertEquals(
+        Arrays.asList(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()),
+        UnittestImport.getDescriptor().getEnumTypes());
     for (int i = 0; i < file.getEnumTypes().size(); i++) {
       assertEquals(i, file.getEnumTypes().get(i).getIndex());
     }
@@ -127,22 +124,17 @@
     assertEquals(service, file.findServiceByName("TestService"));
     assertNull(file.findServiceByName("NoSuchType"));
     assertNull(file.findServiceByName("protobuf_unittest.TestService"));
-    assertEquals(Collections.emptyList(),
-                 UnittestImport.getDescriptor().getServices());
+    assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getServices());
     for (int i = 0; i < file.getServices().size(); i++) {
       assertEquals(i, file.getServices().get(i).getIndex());
     }
 
-    FieldDescriptor extension =
-      UnittestProto.optionalInt32Extension.getDescriptor();
+    FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
     assertEquals(extension, file.getExtensions().get(0));
-    assertEquals(extension,
-                 file.findExtensionByName("optional_int32_extension"));
+    assertEquals(extension, file.findExtensionByName("optional_int32_extension"));
     assertNull(file.findExtensionByName("no_such_ext"));
-    assertNull(file.findExtensionByName(
-      "protobuf_unittest.optional_int32_extension"));
-    assertEquals(Collections.emptyList(),
-                 UnittestImport.getDescriptor().getExtensions());
+    assertNull(file.findExtensionByName("protobuf_unittest.optional_int32_extension"));
+    assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getExtensions());
     for (int i = 0; i < file.getExtensions().size(); i++) {
       assertEquals(i, file.getExtensions().get(i).getIndex());
     }
@@ -156,13 +148,11 @@
     assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
     assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
     assertNull(messageType.getContainingType());
-    assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
-                 messageType.getOptions());
+    assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), messageType.getOptions());
     assertEquals("TestAllTypes", messageType.toProto().getName());
 
     assertEquals("NestedMessage", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
-                 nestedType.getFullName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.getFullName());
     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
     assertEquals(messageType, nestedType.getContainingType());
 
@@ -194,36 +184,28 @@
 
   public void testFieldDescriptor() throws Exception {
     Descriptor messageType = TestAllTypes.getDescriptor();
-    FieldDescriptor primitiveField =
-      messageType.findFieldByName("optional_int32");
-    FieldDescriptor enumField =
-      messageType.findFieldByName("optional_nested_enum");
-    FieldDescriptor messageField =
-      messageType.findFieldByName("optional_foreign_message");
-    FieldDescriptor cordField =
-      messageType.findFieldByName("optional_cord");
-    FieldDescriptor extension =
-      UnittestProto.optionalInt32Extension.getDescriptor();
+    FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
+    FieldDescriptor enumField = messageType.findFieldByName("optional_nested_enum");
+    FieldDescriptor messageField = messageType.findFieldByName("optional_foreign_message");
+    FieldDescriptor cordField = messageType.findFieldByName("optional_cord");
+    FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
     FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
 
     assertEquals("optional_int32", primitiveField.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
-                 primitiveField.getFullName());
+    assertEquals("protobuf_unittest.TestAllTypes.optional_int32", primitiveField.getFullName());
     assertEquals(1, primitiveField.getNumber());
     assertEquals(messageType, primitiveField.getContainingType());
     assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
     assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
     assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
-                 primitiveField.getOptions());
+    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), primitiveField.getOptions());
     assertFalse(primitiveField.isExtension());
     assertEquals("optional_int32", primitiveField.toProto().getName());
 
     assertEquals("optional_nested_enum", enumField.getName());
     assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
     assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
-    assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
-                 enumField.getEnumType());
+    assertEquals(TestAllTypes.NestedEnum.getDescriptor(), enumField.getEnumType());
 
     assertEquals("optional_foreign_message", messageField.getName());
     assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
@@ -233,38 +215,29 @@
     assertEquals("optional_cord", cordField.getName());
     assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
     assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
-                 cordField.getOptions().getCtype());
+    assertEquals(DescriptorProtos.FieldOptions.CType.CORD, cordField.getOptions().getCtype());
 
     assertEquals("optional_int32_extension", extension.getName());
-    assertEquals("protobuf_unittest.optional_int32_extension",
-                 extension.getFullName());
+    assertEquals("protobuf_unittest.optional_int32_extension", extension.getFullName());
     assertEquals(1, extension.getNumber());
-    assertEquals(TestAllExtensions.getDescriptor(),
-                 extension.getContainingType());
+    assertEquals(TestAllExtensions.getDescriptor(), extension.getContainingType());
     assertEquals(UnittestProto.getDescriptor(), extension.getFile());
     assertEquals(FieldDescriptor.Type.INT32, extension.getType());
     assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
-    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
-                 extension.getOptions());
+    assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), extension.getOptions());
     assertTrue(extension.isExtension());
     assertEquals(null, extension.getExtensionScope());
     assertEquals("optional_int32_extension", extension.toProto().getName());
 
     assertEquals("single", nestedExtension.getName());
-    assertEquals("protobuf_unittest.TestRequired.single",
-                 nestedExtension.getFullName());
-    assertEquals(TestRequired.getDescriptor(),
-                 nestedExtension.getExtensionScope());
+    assertEquals("protobuf_unittest.TestRequired.single", nestedExtension.getFullName());
+    assertEquals(TestRequired.getDescriptor(), nestedExtension.getExtensionScope());
   }
 
   public void testFieldDescriptorLabel() throws Exception {
-    FieldDescriptor requiredField =
-      TestRequired.getDescriptor().findFieldByName("a");
-    FieldDescriptor optionalField =
-      TestAllTypes.getDescriptor().findFieldByName("optional_int32");
-    FieldDescriptor repeatedField =
-      TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+    FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
+    FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+    FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
 
     assertTrue(requiredField.isRequired());
     assertFalse(requiredField.isRepeated());
@@ -273,7 +246,7 @@
     assertFalse(repeatedField.isRequired());
     assertTrue(repeatedField.isRepeated());
   }
-  
+
   public void testFieldDescriptorJsonName() throws Exception {
     FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
     FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
@@ -292,9 +265,8 @@
 
     d = TestExtremeDefaultValues.getDescriptor();
     assertEquals(
-      ByteString.copyFrom(
-        "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
-      d.findFieldByName("escaped_bytes").getDefaultValue());
+        ByteString.copyFrom("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
+        d.findFieldByName("escaped_bytes").getDefaultValue());
     assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
     assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
   }
@@ -307,12 +279,10 @@
     assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
     assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
     assertNull(enumType.getContainingType());
-    assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
-                 enumType.getOptions());
+    assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), enumType.getOptions());
 
     assertEquals("NestedEnum", nestedType.getName());
-    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
-                 nestedType.getFullName());
+    assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", nestedType.getFullName());
     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
     assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
 
@@ -339,18 +309,14 @@
 
     MethodDescriptor fooMethod = service.getMethods().get(0);
     assertEquals("Foo", fooMethod.getName());
-    assertEquals(UnittestProto.FooRequest.getDescriptor(),
-                 fooMethod.getInputType());
-    assertEquals(UnittestProto.FooResponse.getDescriptor(),
-                 fooMethod.getOutputType());
+    assertEquals(UnittestProto.FooRequest.getDescriptor(), fooMethod.getInputType());
+    assertEquals(UnittestProto.FooResponse.getDescriptor(), fooMethod.getOutputType());
     assertEquals(fooMethod, service.findMethodByName("Foo"));
 
     MethodDescriptor barMethod = service.getMethods().get(1);
     assertEquals("Bar", barMethod.getName());
-    assertEquals(UnittestProto.BarRequest.getDescriptor(),
-                 barMethod.getInputType());
-    assertEquals(UnittestProto.BarResponse.getDescriptor(),
-                 barMethod.getOutputType());
+    assertEquals(UnittestProto.BarRequest.getDescriptor(), barMethod.getInputType());
+    assertEquals(UnittestProto.BarResponse.getDescriptor(), barMethod.getOutputType());
     assertEquals(barMethod, service.findMethodByName("Bar"));
 
     assertNull(service.findMethodByName("NoSuchMethod"));
@@ -367,58 +333,53 @@
     // dependencies are also properly initialized.
     Descriptor descriptor =
         TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
-        .findFieldByName("field").getMessageType();
+            .findFieldByName("field")
+            .getMessageType();
 
-    assertTrue(
-      descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
-    assertEquals(Integer.valueOf(-56),
-      descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+    assertTrue(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
+    assertEquals(
+        Integer.valueOf(-56),
+        descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
 
     FieldDescriptor field = descriptor.findFieldByName("field1");
     assertNotNull(field);
 
-    assertTrue(
-      field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
-    assertEquals(Long.valueOf(8765432109L),
-      field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+    assertTrue(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
+    assertEquals(
+        Long.valueOf(8765432109L),
+        field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
 
     OneofDescriptor oneof = descriptor.getOneofs().get(0);
     assertNotNull(oneof);
 
-    assertTrue(
-      oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
-    assertEquals(Integer.valueOf(-99),
-      oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
+    assertTrue(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
+    assertEquals(
+        Integer.valueOf(-99), oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
 
     EnumDescriptor enumType =
-      UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
+        UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
 
-    assertTrue(
-      enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
-    assertEquals(Integer.valueOf(-789),
-      enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+    assertTrue(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
+    assertEquals(
+        Integer.valueOf(-789), enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
 
-    ServiceDescriptor service =
-      UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
+    ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
 
-    assertTrue(
-      service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
-    assertEquals(Long.valueOf(-9876543210L),
-      service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+    assertTrue(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
+    assertEquals(
+        Long.valueOf(-9876543210L),
+        service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
 
     MethodDescriptor method = service.findMethodByName("Foo");
     assertNotNull(method);
 
-    assertTrue(
-      method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
-    assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
-      method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+    assertTrue(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
+    assertEquals(
+        UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
+        method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
   }
 
-  /**
-   * Test that the FieldDescriptor.Type enum is the same as the
-   * WireFormat.FieldType enum.
-   */
+  /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
   public void testFieldTypeTablesMatch() throws Exception {
     FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
     WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
@@ -430,10 +391,7 @@
     }
   }
 
-  /**
-   * Test that the FieldDescriptor.JavaType enum is the same as the
-   * WireFormat.JavaType enum.
-   */
+  /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
   public void testJavaTypeTablesMatch() throws Exception {
     FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
     WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
@@ -448,31 +406,29 @@
   public void testEnormousDescriptor() throws Exception {
     // The descriptor for this file is larger than 64k, yet it did not cause
     // a compiler error due to an over-long string literal.
-    assertTrue(
-        UnittestEnormousDescriptor.getDescriptor()
-          .toProto().getSerializedSize() > 65536);
+    assertTrue(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize() > 65536);
   }
 
-  /**
-   * Tests that the DescriptorValidationException works as intended.
-   */
+  /** Tests that the DescriptorValidationException works as intended. */
   public void testDescriptorValidatorException() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-      .setName("foo.proto")
-      .addMessageType(DescriptorProto.newBuilder()
-      .setName("Foo")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setType(FieldDescriptorProto.Type.TYPE_INT32)
-          .setName("foo")
-          .setNumber(1)
-          .setDefaultValue("invalid")
-          .build())
-        .build())
-      .build();
+    FileDescriptorProto fileDescriptorProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setType(FieldDescriptorProto.Type.TYPE_INT32)
+                            .setName("foo")
+                            .setNumber(1)
+                            .setDefaultValue("invalid")
+                            .build())
+                    .build())
+            .build();
     try {
-      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
-          new FileDescriptor[0]);
+      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
       fail("DescriptorValidationException expected");
     } catch (DescriptorValidationException e) {
       // Expected; check that the error message contains some useful hints
@@ -485,35 +441,39 @@
   }
 
   /**
-   * Tests the translate/crosslink for an example where a message field's name
-   * and type name are the same.
+   * Tests the translate/crosslink for an example where a message field's name and type name are the
+   * same.
    */
   public void testDescriptorComplexCrosslink() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-      .setName("foo.proto")
-      .addMessageType(DescriptorProto.newBuilder()
-        .setName("Foo")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setType(FieldDescriptorProto.Type.TYPE_INT32)
-          .setName("foo")
-          .setNumber(1)
-          .build())
-        .build())
-      .addMessageType(DescriptorProto.newBuilder()
-        .setName("Bar")
-        .addField(FieldDescriptorProto.newBuilder()
-          .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-          .setTypeName("Foo")
-          .setName("Foo")
-          .setNumber(1)
-          .build())
-        .build())
-      .build();
+    FileDescriptorProto fileDescriptorProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setType(FieldDescriptorProto.Type.TYPE_INT32)
+                            .setName("foo")
+                            .setNumber(1)
+                            .build())
+                    .build())
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Bar")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setTypeName("Foo")
+                            .setName("Foo")
+                            .setNumber(1)
+                            .build())
+                    .build())
+            .build();
     // translate and crosslink
     FileDescriptor file =
-      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
-          new FileDescriptor[0]);
+        Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
     // verify resulting descriptors
     assertNotNull(file);
     List<Descriptor> msglist = file.getMessageTypes();
@@ -535,62 +495,57 @@
   }
 
   public void testDependencyOrder() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto").build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addDependency("foo.proto")
-        .build();
-    FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
-        .setName("baz.proto")
-        .addDependency("foo.proto")
-        .addDependency("bar.proto")
-        .addPublicDependency(0)
-        .addPublicDependency(1)
-        .build();
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
-        new FileDescriptor[0]);
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
-        new FileDescriptor[] {fooFile});
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
+    FileDescriptorProto barProto =
+        FileDescriptorProto.newBuilder().setName("bar.proto").addDependency("foo.proto").build();
+    FileDescriptorProto bazProto =
+        FileDescriptorProto.newBuilder()
+            .setName("baz.proto")
+            .addDependency("foo.proto")
+            .addDependency("bar.proto")
+            .addPublicDependency(0)
+            .addPublicDependency(1)
+            .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+    FileDescriptor barFile =
+        Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
 
     // Items in the FileDescriptor array can be in any order.
-    Descriptors.FileDescriptor.buildFrom(bazProto,
-        new FileDescriptor[] {fooFile, barFile});
-    Descriptors.FileDescriptor.buildFrom(bazProto,
-        new FileDescriptor[] {barFile, fooFile});
+    Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile});
+    Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
   }
 
   public void testInvalidPublicDependency() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto").build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("boo.proto")
-        .addDependency("foo.proto")
-        .addPublicDependency(1)  // Error, should be 0.
-        .build();
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
-        new FileDescriptor[0]);
+    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
+    FileDescriptorProto barProto =
+        FileDescriptorProto.newBuilder()
+            .setName("boo.proto")
+            .addDependency("foo.proto")
+            .addPublicDependency(1) // Error, should be 0.
+            .build();
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
     try {
-      Descriptors.FileDescriptor.buildFrom(barProto,
-          new FileDescriptor[] {fooFile});
+      Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
       fail("DescriptorValidationException expected");
     } catch (DescriptorValidationException e) {
-      assertTrue(
-          e.getMessage().indexOf("Invalid public dependency index.") != -1);
+      assertTrue(e.getMessage().indexOf("Invalid public dependency index.") != -1);
     }
   }
 
   public void testUnknownFieldsDenied() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setTypeName("Bar")
+                            .setName("bar")
+                            .setNumber(1)))
+            .build();
 
     try {
       Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
@@ -602,48 +557,54 @@
   }
 
   public void testUnknownFieldsAllowed() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("bar.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addDependency("bar.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setTypeName("Bar")
+                            .setName("bar")
+                            .setNumber(1)))
+            .build();
     Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
   }
 
   public void testHiddenDependency() throws Exception {
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
-        .build();
-    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
-        .setName("forward.proto")
-        .addDependency("bar.proto")
-        .build();
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("forward.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[0]);
-    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
-        forwardProto, new FileDescriptor[] {barFile});
+    FileDescriptorProto barProto =
+        FileDescriptorProto.newBuilder()
+            .setName("bar.proto")
+            .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+            .build();
+    FileDescriptorProto forwardProto =
+        FileDescriptorProto.newBuilder()
+            .setName("forward.proto")
+            .addDependency("bar.proto")
+            .build();
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addDependency("forward.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setTypeName("Bar")
+                            .setName("bar")
+                            .setNumber(1)))
+            .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile =
+        Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
 
     try {
-      Descriptors.FileDescriptor.buildFrom(
-          fooProto, new FileDescriptor[] {forwardFile});
+      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
       fail("DescriptorValidationException expected");
     } catch (DescriptorValidationException e) {
       assertTrue(e.getMessage().indexOf("Bar") != -1);
@@ -652,65 +613,67 @@
   }
 
   public void testPublicDependency() throws Exception {
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
-        .build();
-    FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
-        .setName("forward.proto")
-        .addDependency("bar.proto")
-        .addPublicDependency(0)
-        .build();
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("forward.proto")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("Foo")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
-                .setTypeName("Bar")
-                .setName("bar")
-                .setNumber(1)))
-        .build();
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[0]);
-    FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
-        forwardProto, new FileDescriptor[]{barFile});
-    Descriptors.FileDescriptor.buildFrom(
-        fooProto, new FileDescriptor[] {forwardFile});
+    FileDescriptorProto barProto =
+        FileDescriptorProto.newBuilder()
+            .setName("bar.proto")
+            .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
+            .build();
+    FileDescriptorProto forwardProto =
+        FileDescriptorProto.newBuilder()
+            .setName("forward.proto")
+            .addDependency("bar.proto")
+            .addPublicDependency(0)
+            .build();
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addDependency("forward.proto")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Foo")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+                            .setTypeName("Bar")
+                            .setName("bar")
+                            .setNumber(1)))
+            .build();
+    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
+    FileDescriptor forwardFile =
+        Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
+    Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
   }
 
-  /**
-   * Tests the translate/crosslink for an example with a more complex namespace
-   * referencing.
-   */
+  /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
   public void testComplexNamespacePublicDependency() throws Exception {
-    FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
-        .setName("bar.proto")
-        .setPackage("a.b.c.d.bar.shared")
-        .addEnumType(EnumDescriptorProto.newBuilder()
-            .setName("MyEnum")
-            .addValue(EnumValueDescriptorProto.newBuilder()
-                .setName("BLAH")
-                .setNumber(1)))
-        .build();
-    FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addDependency("bar.proto")
-        .setPackage("a.b.c.d.foo.shared")
-        .addMessageType(DescriptorProto.newBuilder()
-            .setName("MyMessage")
-            .addField(FieldDescriptorProto.newBuilder()
-                .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
-                .setTypeName("bar.shared.MyEnum")
-                .setName("MyField")
-                .setNumber(1)))
-        .build();
+    FileDescriptorProto fooProto =
+        FileDescriptorProto.newBuilder()
+            .setName("bar.proto")
+            .setPackage("a.b.c.d.bar.shared")
+            .addEnumType(
+                EnumDescriptorProto.newBuilder()
+                    .setName("MyEnum")
+                    .addValue(EnumValueDescriptorProto.newBuilder().setName("BLAH").setNumber(1)))
+            .build();
+    FileDescriptorProto barProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addDependency("bar.proto")
+            .setPackage("a.b.c.d.foo.shared")
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("MyMessage")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+                            .setTypeName("bar.shared.MyEnum")
+                            .setName("MyField")
+                            .setNumber(1)))
+            .build();
     // translate and crosslink
-    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
-        fooProto, new FileDescriptor[0]);
-    FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
-        barProto, new FileDescriptor[]{fooFile});
+    FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
+    FileDescriptor barFile =
+        Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
     // verify resulting descriptors
     assertNotNull(barFile);
     List<Descriptor> msglist = barFile.getMessageTypes();
@@ -726,15 +689,13 @@
       assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
       assertTrue(field.getEnumType().getName().equals("MyEnum"));
       assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
-      assertTrue(field.getEnumType().getFile().getPackage().equals(
-          "a.b.c.d.bar.shared"));
+      assertTrue(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"));
     }
   }
 
   public void testOneofDescriptor() throws Exception {
     Descriptor messageType = TestAllTypes.getDescriptor();
-    FieldDescriptor field =
-        messageType.findFieldByName("oneof_nested_message");
+    FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
     OneofDescriptor oneofDescriptor = field.getContainingOneof();
     assertNotNull(oneofDescriptor);
     assertSame(oneofDescriptor, messageType.getOneofs().get(0));
@@ -774,36 +735,38 @@
   }
 
   public void testToString() {
-    assertEquals("protobuf_unittest.TestAllTypes.optional_uint64",
-        UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber(
-            UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString());
+    assertEquals(
+        "protobuf_unittest.TestAllTypes.optional_uint64",
+        UnittestProto.TestAllTypes.getDescriptor()
+            .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
+            .toString());
   }
 
   public void testPackedEnumField() throws Exception {
-    FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
-        .setName("foo.proto")
-        .addEnumType(EnumDescriptorProto.newBuilder()
-          .setName("Enum")
-          .addValue(EnumValueDescriptorProto.newBuilder()
-            .setName("FOO")
-            .setNumber(1)
-            .build())
-          .build())
-        .addMessageType(DescriptorProto.newBuilder()
-          .setName("Message")
-          .addField(FieldDescriptorProto.newBuilder()
-            .setName("foo")
-            .setTypeName("Enum")
-            .setNumber(1)
-            .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
-            .setOptions(DescriptorProtos.FieldOptions.newBuilder()
-              .setPacked(true)
-              .build())
-            .build())
-          .build())
-        .build();
-    Descriptors.FileDescriptor.buildFrom(
-        fileDescriptorProto, new FileDescriptor[0]);
+    FileDescriptorProto fileDescriptorProto =
+        FileDescriptorProto.newBuilder()
+            .setName("foo.proto")
+            .addEnumType(
+                EnumDescriptorProto.newBuilder()
+                    .setName("Enum")
+                    .addValue(
+                        EnumValueDescriptorProto.newBuilder().setName("FOO").setNumber(1).build())
+                    .build())
+            .addMessageType(
+                DescriptorProto.newBuilder()
+                    .setName("Message")
+                    .addField(
+                        FieldDescriptorProto.newBuilder()
+                            .setName("foo")
+                            .setTypeName("Enum")
+                            .setNumber(1)
+                            .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
+                            .setOptions(
+                                DescriptorProtos.FieldOptions.newBuilder().setPacked(true).build())
+                            .build())
+                    .build())
+            .build();
+    Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
   }
 
   public void testFieldJsonName() throws Exception {
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index 6a94212..3a8254a 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -266,6 +266,15 @@
     assertFalse(list.addAll(DoubleArrayList.emptyList()));
   }
 
+  public void testEquals() {
+    DoubleArrayList list1 = new DoubleArrayList();
+    DoubleArrayList list2 = new DoubleArrayList();
+
+    list1.addDouble(Double.longBitsToDouble(0x7ff0000000000001L));
+    list2.addDouble(Double.longBitsToDouble(0x7ff0000000000002L));
+    assertEquals(list1, list2);
+  }
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1D, (double) list.remove(0), 0.0);
@@ -294,13 +303,22 @@
     }
   }
 
-  public void testRemoveEndOfCapacity() {
+  public void testRemoveEnd_listAtCapacity() {
     DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
   }
 
+  public void testRemove_listAtCapacity() {
+    DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(2);
+    toRemove.addDouble(3);
+    toRemove.addDouble(4);
+    toRemove.remove(0);
+    assertEquals(1, toRemove.size());
+    assertEquals(4D, (double) toRemove.get(0));
+  }
+
   public void testSublistRemoveEndOfCapacity() {
     DoubleList toRemove = DoubleArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addDouble(3);
diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
index a0e9137..d1e4a29 100644
--- a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -238,7 +238,7 @@
     classLoader.loadClass(ExtensionRegistryFactory.class.getName());
     Class<?> test = classLoader.loadClass(testClass.getName());
     String testName = getName();
-    test.getMethod(testName).invoke(test.newInstance());
+    test.getMethod(testName).invoke(test.getDeclaredConstructor().newInstance());
   }
 
   /**
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index 7ed6134..77a2839 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -266,6 +266,15 @@
     assertFalse(list.addAll(FloatArrayList.emptyList()));
   }
 
+  public void testEquals() {
+    FloatArrayList list1 = new FloatArrayList();
+    FloatArrayList list2 = new FloatArrayList();
+
+    list1.addFloat(Float.intBitsToFloat(0xff800001));
+    list2.addFloat(Float.intBitsToFloat(0xff800002));
+    assertEquals(list1, list2);
+  }
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1F, (float) list.remove(0), 0.0f);
@@ -294,13 +303,22 @@
     }
   }
 
-  public void testRemoveEndOfCapacity() {
+  public void testRemoveEnd_listAtCapacity() {
     FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
   }
 
+  public void testRemove_listAtCapacity() {
+    FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(2);
+    toRemove.addFloat(3);
+    toRemove.addFloat(4);
+    toRemove.remove(0);
+    assertEquals(1, toRemove.size());
+    assertEquals(4F, (float) toRemove.get(0));
+  }
+
   public void testSublistRemoveEndOfCapacity() {
     FloatList toRemove = FloatArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addFloat(3);
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index d6943e0..51ebc98 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -266,6 +266,13 @@
     assertFalse(list.addAll(IntArrayList.emptyList()));
   }
 
+  public void testEquals() {
+    IntArrayList list1 = new IntArrayList();
+    IntArrayList list2 = new IntArrayList();
+
+    assertEquals(list1, list2);
+  }
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1, (int) list.remove(0));
@@ -294,13 +301,22 @@
     }
   }
 
-  public void testRemoveEndOfCapacity() {
+  public void testRemoveEnd_listAtCapacity() {
     IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
   }
 
+  public void testRemove_listAtCapacity() {
+    IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(2);
+    toRemove.addInt(3);
+    toRemove.addInt(4);
+    toRemove.remove(0);
+    assertEquals(1, toRemove.size());
+    assertEquals(4, (int) toRemove.get(0));
+  }
+
   public void testSublistRemoveEndOfCapacity() {
     IntList toRemove = IntArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addInt(3);
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
index 2518f20..6a737f1 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java
@@ -168,7 +168,7 @@
     // A sanity check.
     int actual = 0;
     for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
-      actual += shard.expected;
+      actual = (int) (actual + shard.expected);
     }
     assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual);
   }
diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
index 2c086e1..67d2f59 100644
--- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
@@ -218,9 +218,9 @@
   private static List<Shard> generateFourByteShards(int numShards, long[] expected) {
     assertEquals(numShards, expected.length);
     List<Shard> shards = new ArrayList<Shard>(numShards);
-    long LIM = 1L << 32;
-    long increment = LIM / numShards;
-    assertTrue(LIM % numShards == 0);
+    long lim = 1L << 32;
+    long increment = lim / numShards;
+    assertTrue(lim % numShards == 0);
     for (int i = 0; i < numShards; i++) {
       shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i]));
     }
diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
index 813fe6b..8c13aca 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java
@@ -117,8 +117,8 @@
     LazyFieldLite original = createLazyFieldLiteFromMessage(message);
     LazyFieldLite merged = new LazyFieldLite();
     merged.merge(original);
-    TestAllExtensions value = (TestAllExtensions) merged.getValue(
-        TestAllExtensions.getDefaultInstance());
+    TestAllExtensions value =
+        (TestAllExtensions) merged.getValue(TestAllExtensions.getDefaultInstance());
     assertEquals(message, value);
   }
 
@@ -130,8 +130,8 @@
 
   public void testInvalidProto() throws Exception {
     // Silently fails and uses the default instance.
-    LazyFieldLite field = new LazyFieldLite(
-        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    LazyFieldLite field =
+        new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
     assertEquals(
         TestAllTypes.getDefaultInstance(), field.getValue(TestAllTypes.getDefaultInstance()));
     assertEquals(0, field.getSerializedSize());
@@ -158,7 +158,7 @@
         TestAllTypes.newBuilder().setOptionalInt32(1).setOptionalInt64(2).build();
 
     LazyFieldLite field1 = LazyFieldLite.fromValue(message1);
-    field1.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    field1.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
     LazyFieldLite field2 = createLazyFieldLiteFromMessage(message2);
     field1.merge(field2);
     assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
@@ -166,7 +166,7 @@
     // Now reverse which one is parsed first.
     field1 = LazyFieldLite.fromValue(message1);
     field2 = createLazyFieldLiteFromMessage(message2);
-    field2.getValue(TestAllTypes.getDefaultInstance());  // Force parsing.
+    field2.getValue(TestAllTypes.getDefaultInstance()); // Force parsing.
     field1.merge(field2);
     assertEquals(expected, field1.getValue(TestAllTypes.getDefaultInstance()));
   }
@@ -175,8 +175,8 @@
     // Test a few different paths that involve one message that was not parsed.
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(1).build();
     LazyFieldLite valid = LazyFieldLite.fromValue(message);
-    LazyFieldLite invalid = new LazyFieldLite(
-        TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
+    LazyFieldLite invalid =
+        new LazyFieldLite(TestUtil.getExtensionRegistry(), ByteString.copyFromUtf8("invalid"));
     invalid.merge(valid);
 
     // We swallow the exception and just use the set field.
@@ -206,13 +206,13 @@
     // Now try parsing the empty field first.
     field = LazyFieldLite.fromValue(messageWithExtensions);
     LazyFieldLite other = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
-    other.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    other.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
     field.merge(other);
     assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
 
     // And again reverse.
     field = createLazyFieldLiteFromMessage(emptyRegistry, emptyMessage);
-    field.getValue(TestAllExtensions.getDefaultInstance());  // Force parsing.
+    field.getValue(TestAllExtensions.getDefaultInstance()); // Force parsing.
     other = LazyFieldLite.fromValue(messageWithExtensions);
     field.merge(other);
     assertEquals(messageWithExtensions, field.getValue(TestAllExtensions.getDefaultInstance()));
@@ -239,8 +239,7 @@
   }
 
   private void assertNotEqual(Object unexpected, Object actual) {
-    assertFalse(unexpected == actual
-        || (unexpected != null && unexpected.equals(actual)));
+    assertFalse(unexpected == actual || (unexpected != null && unexpected.equals(actual)));
   }
 
 }
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index b20114e..89213a7 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -81,7 +81,7 @@
     //
     // We put this in setUp() rather than in its own test method because we
     // need to make sure it runs before any actual tests.
-    assertTrue(TestNestedExtensionLite.nestedExtension != null);
+    assertNotNull(TestNestedExtensionLite.nestedExtension);
   }
 
   public void testLite() throws Exception {
@@ -320,16 +320,16 @@
     assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
 
     message = builder.build();
-    ForeignMessageLite.Builder foreignMessageBuilder = ForeignMessageLite.newBuilder().setC(3);
-    builder.setOptionalForeignMessage(foreignMessageBuilder);
+    ForeignMessageLite foreignMessageC3 = ForeignMessageLite.newBuilder().setC(3).build();
+    builder.setOptionalForeignMessage(foreignMessageC3);
     assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
-    assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage());
+    assertEquals(foreignMessageC3, builder.getOptionalForeignMessage());
     messageAfterBuild = builder.build();
-    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
     assertEquals(ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage());
     builder.clearOptionalForeignMessage();
     assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage());
-    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(foreignMessageC3, messageAfterBuild.getOptionalForeignMessage());
 
     message = builder.build();
     OptionalGroup optionalGroup = OptionalGroup.newBuilder().setA(1).build();
@@ -1033,11 +1033,11 @@
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
-    builder.addRepeatedForeignMessage(foreignMessageBuilder);
+    builder.addRepeatedForeignMessage(foreignMessageC3);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignMessageCount());
     builder.setRepeatedForeignMessage(0, ForeignMessageLite.getDefaultInstance());
-    assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(foreignMessageC3, messageAfterBuild.getRepeatedForeignMessage(0));
     assertEquals(ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0));
     builder.clearRepeatedForeignMessage();
 
@@ -1045,9 +1045,9 @@
     builder.addRepeatedForeignMessage(0, foreignMessage);
     messageAfterBuild = builder.build();
     assertEquals(0, message.getRepeatedForeignMessageCount());
-    builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
+    builder.setRepeatedForeignMessage(0, foreignMessageC3);
     assertEquals(foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
-    assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0));
+    assertEquals(foreignMessageC3, builder.getRepeatedForeignMessage(0));
     builder.clearRepeatedForeignMessage();
 
     message = builder.build();
@@ -1533,7 +1533,7 @@
   private static void assertToStringEquals(String expected, MessageLite message) {
     String toString = message.toString();
     assertEquals('#', toString.charAt(0));
-    if (toString.indexOf("\n") >= 0) {
+    if (toString.contains("\n")) {
       toString = toString.substring(toString.indexOf("\n") + 1);
     } else {
       toString = "";
@@ -2210,29 +2210,29 @@
 
   public void testAddAllIteratesOnce() {
     TestAllTypesLite.newBuilder()
-        .addAllRepeatedBool(new OneTimeIterableList(false))
-        .addAllRepeatedInt32(new OneTimeIterableList(0))
-        .addAllRepeatedInt64(new OneTimeIterableList(0L))
-        .addAllRepeatedFloat(new OneTimeIterableList(0f))
-        .addAllRepeatedDouble(new OneTimeIterableList(0d))
-        .addAllRepeatedBytes(new OneTimeIterableList(ByteString.EMPTY))
-        .addAllRepeatedString(new OneTimeIterableList(""))
-        .addAllRepeatedNestedMessage(new OneTimeIterableList(NestedMessage.getDefaultInstance()))
-        .addAllRepeatedBool(new OneTimeIterable(false))
-        .addAllRepeatedInt32(new OneTimeIterable(0))
-        .addAllRepeatedInt64(new OneTimeIterable(0L))
-        .addAllRepeatedFloat(new OneTimeIterable(0f))
-        .addAllRepeatedDouble(new OneTimeIterable(0d))
-        .addAllRepeatedBytes(new OneTimeIterable(ByteString.EMPTY))
-        .addAllRepeatedString(new OneTimeIterable(""))
-        .addAllRepeatedNestedMessage(new OneTimeIterable(NestedMessage.getDefaultInstance()))
+        .addAllRepeatedBool(new OneTimeIterableList<>(false))
+        .addAllRepeatedInt32(new OneTimeIterableList<>(0))
+        .addAllRepeatedInt64(new OneTimeIterableList<>(0L))
+        .addAllRepeatedFloat(new OneTimeIterableList<>(0f))
+        .addAllRepeatedDouble(new OneTimeIterableList<>(0d))
+        .addAllRepeatedBytes(new OneTimeIterableList<>(ByteString.EMPTY))
+        .addAllRepeatedString(new OneTimeIterableList<>(""))
+        .addAllRepeatedNestedMessage(new OneTimeIterableList<>(NestedMessage.getDefaultInstance()))
+        .addAllRepeatedBool(new OneTimeIterable<>(false))
+        .addAllRepeatedInt32(new OneTimeIterable<>(0))
+        .addAllRepeatedInt64(new OneTimeIterable<>(0L))
+        .addAllRepeatedFloat(new OneTimeIterable<>(0f))
+        .addAllRepeatedDouble(new OneTimeIterable<>(0d))
+        .addAllRepeatedBytes(new OneTimeIterable<>(ByteString.EMPTY))
+        .addAllRepeatedString(new OneTimeIterable<>(""))
+        .addAllRepeatedNestedMessage(new OneTimeIterable<>(NestedMessage.getDefaultInstance()))
         .build();
   }
 
   public void testAddAllIteratesOnce_throwsOnNull() {
     TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
     try {
-      builder.addAllRepeatedBool(new OneTimeIterableList(true, false, (Boolean) null));
+      builder.addAllRepeatedBool(new OneTimeIterableList<>(true, false, null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2240,7 +2240,7 @@
     }
 
     try {
-      builder.addAllRepeatedBool(new OneTimeIterable(true, false, (Boolean) null));
+      builder.addAllRepeatedBool(new OneTimeIterable<>(true, false, null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2249,7 +2249,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedBool(new OneTimeIterableList((Boolean) null));
+      builder.addAllRepeatedBool(new OneTimeIterableList<>((Boolean) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2258,7 +2258,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedInt32(new OneTimeIterableList((Integer) null));
+      builder.addAllRepeatedInt32(new OneTimeIterableList<>((Integer) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2267,7 +2267,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedInt64(new OneTimeIterableList((Long) null));
+      builder.addAllRepeatedInt64(new OneTimeIterableList<>((Long) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2276,7 +2276,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedFloat(new OneTimeIterableList((Float) null));
+      builder.addAllRepeatedFloat(new OneTimeIterableList<>((Float) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2285,7 +2285,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedDouble(new OneTimeIterableList((Double) null));
+      builder.addAllRepeatedDouble(new OneTimeIterableList<>((Double) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2294,7 +2294,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedBytes(new OneTimeIterableList((ByteString) null));
+      builder.addAllRepeatedBytes(new OneTimeIterableList<>((ByteString) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2303,7 +2303,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedString(new OneTimeIterableList("", "", (String) null, ""));
+      builder.addAllRepeatedString(new OneTimeIterableList<>("", "", null, ""));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2312,7 +2312,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedString(new OneTimeIterable("", "", (String) null, ""));
+      builder.addAllRepeatedString(new OneTimeIterable<>("", "", null, ""));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 2 is null.", expected.getMessage());
@@ -2321,7 +2321,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedString(new OneTimeIterableList((String) null));
+      builder.addAllRepeatedString(new OneTimeIterableList<>((String) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
@@ -2330,7 +2330,7 @@
 
     try {
       builder = TestAllTypesLite.newBuilder();
-      builder.addAllRepeatedNestedMessage(new OneTimeIterableList((NestedMessage) null));
+      builder.addAllRepeatedNestedMessage(new OneTimeIterableList<>((NestedMessage) null));
       fail();
     } catch (NullPointerException expected) {
       assertEquals("Element at index 0 is null.", expected.getMessage());
diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 9e5adb7..0131ea2 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -369,13 +369,13 @@
           }
 
           @Override
-          public void writeLazy(byte[] value, int offset, int length) throws IOException {
-            Arrays.fill(value, offset, offset + length, (byte) 0);
+          public void write(ByteBuffer value) throws IOException {
+            throw new UnsupportedOperationException();
           }
 
           @Override
-          public void write(ByteBuffer value) throws IOException {
-            throw new UnsupportedOperationException();
+          public void writeLazy(byte[] value, int offset, int length) throws IOException {
+            Arrays.fill(value, offset, offset + length, (byte) 0);
           }
 
           @Override
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index 4b5e6c7..1935100 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -266,6 +266,13 @@
     assertFalse(list.addAll(LongArrayList.emptyList()));
   }
 
+  public void testEquals() {
+    LongArrayList list1 = new LongArrayList();
+    LongArrayList list2 = new LongArrayList();
+
+    assertEquals(list1, list2);
+  }
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1L, (long) list.remove(0));
@@ -294,13 +301,22 @@
     }
   }
 
-  public void testRemoveEndOfCapacity() {
+  public void testRemoveEnd_listAtCapacity() {
     LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
     toRemove.remove(0);
     assertEquals(0, toRemove.size());
   }
 
+  public void testRemove_listAtCapacity() {
+    LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(2);
+    toRemove.addLong(3);
+    toRemove.addLong(4);
+    toRemove.remove(0);
+    assertEquals(1, toRemove.size());
+    assertEquals(4L, (long) toRemove.get(0));
+  }
+
   public void testSublistRemoveEndOfCapacity() {
     LongList toRemove = LongArrayList.emptyList().mutableCopyWithCapacity(1);
     toRemove.addLong(3);
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index 41fef07..adca1d5 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -440,12 +440,12 @@
 
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
-    TestMap.Builder b1 =
+    TestMap m1 =
         TestMap.newBuilder()
             .putInt32ToInt32Field(1, 2)
             .putInt32ToInt32Field(3, 4)
-            .putInt32ToInt32Field(5, 6);
-    TestMap m1 = b1.build();
+            .putInt32ToInt32Field(5, 6)
+            .build();
 
     TestMap.Builder b2 =
         TestMap.newBuilder()
@@ -466,9 +466,12 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
-    ByteString data = builder.build().toByteString();
+    ByteString data =
+        TestUnknownEnumValue.newBuilder()
+            .putInt32ToInt32Field(1, 1)
+            .putInt32ToInt32Field(2, 54321)
+            .build()
+            .toByteString();
 
     TestMap message = TestMap.parseFrom(data);
     // Entries with unknown enum values will be stored into UnknownFieldSet so
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
index bcfd927..4961042 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -49,9 +49,7 @@
 import java.util.Map;
 import junit.framework.TestCase;
 
-/**
- * Unit tests for map fields in proto2 protos.
- */
+/** Unit tests for map fields in proto2 protos. */
 public class MapForProto2Test extends TestCase {
 
   private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
@@ -88,23 +86,18 @@
         .putInt32ToInt32Field(1, 11)
         .putInt32ToInt32Field(2, 22)
         .putInt32ToInt32Field(3, 33)
-
         .putInt32ToStringField(1, "11")
         .putInt32ToStringField(2, "22")
         .putInt32ToStringField(3, "33")
-
         .putInt32ToBytesField(1, TestUtil.toBytes("11"))
         .putInt32ToBytesField(2, TestUtil.toBytes("22"))
         .putInt32ToBytesField(3, TestUtil.toBytes("33"))
-
         .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
         .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
         .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
-
         .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
         .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
         .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
-
         .putStringToInt32Field("1", 11)
         .putStringToInt32Field("2", 22)
         .putStringToInt32Field("3", 33);
@@ -199,23 +192,18 @@
         .putInt32ToInt32Field(1, 111)
         .removeInt32ToInt32Field(2)
         .putInt32ToInt32Field(4, 44)
-
         .putInt32ToStringField(1, "111")
         .removeInt32ToStringField(2)
         .putInt32ToStringField(4, "44")
-
         .putInt32ToBytesField(1, TestUtil.toBytes("111"))
         .removeInt32ToBytesField(2)
         .putInt32ToBytesField(4, TestUtil.toBytes("44"))
-
         .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
         .removeInt32ToEnumField(2)
         .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
-
         .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
         .removeInt32ToMessageField(2)
         .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
-
         .putStringToInt32Field("1", 111)
         .removeStringToInt32Field("2")
         .putStringToInt32Field("4", 44);
@@ -337,7 +325,7 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     builder.getMutableInt32ToInt32Field().put(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
- //
+  //
     Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
     enumMap.put(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
@@ -432,7 +420,19 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
-
+  //
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  //
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
 
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
@@ -543,30 +543,22 @@
     ByteString bytes = TestUtil.toBytes("SOME BYTES");
     String stringKey = "a string key";
 
-    TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
-        .putInt32ToInt32Field(5, bytes)
-        .build());
+    TestMap map =
+        tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build());
     assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1));
 
-    map = tryParseTestMap(BizarroTestMap.newBuilder()
-        .putInt32ToStringField(stringKey, 5)
-        .build());
+    map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build());
     assertEquals("", map.getInt32ToStringFieldOrDefault(0, null));
 
-    map = tryParseTestMap(BizarroTestMap.newBuilder()
-        .putInt32ToBytesField(stringKey, 5)
-        .build());
+    map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build());
     assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
 
-    map = tryParseTestMap(BizarroTestMap.newBuilder()
-        .putInt32ToEnumField(stringKey, bytes)
-        .build());
+    map =
+        tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build());
     assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null));
 
     try {
-      tryParseTestMap(BizarroTestMap.newBuilder()
-          .putInt32ToMessageField(stringKey, bytes)
-          .build());
+      tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build());
       fail();
     } catch (InvalidProtocolBufferException expected) {
       assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
@@ -574,9 +566,9 @@
       assertTrue(map.getInt32ToMessageField().isEmpty());
     }
 
-    map = tryParseTestMap(BizarroTestMap.newBuilder()
-        .putStringToInt32Field(stringKey, bytes)
-        .build());
+    map =
+        tryParseTestMap(
+            BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build());
     assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1));
   }
 
@@ -657,8 +649,7 @@
     }
   }
 
-  private static <KeyType, ValueType>
-  Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
+  private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) {
     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
     Message.Builder entryBuilder = builder.newBuilderForField(field);
     FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key");
@@ -677,9 +668,8 @@
     builder.setField(field, entryList);
   }
 
-  private static <KeyType, ValueType> Map<KeyType, ValueType> mapForValues(
-      KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
-    Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
+  private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
@@ -687,17 +677,19 @@
 
   public void testReflectionApi() throws Exception {
     // In reflection API, map fields are just repeated message fields.
-    TestMap.Builder builder = TestMap.newBuilder()
-        .putInt32ToInt32Field(1, 2)
-        .putInt32ToInt32Field(3, 4)
-        .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
-        .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
+    TestMap.Builder builder =
+        TestMap.newBuilder()
+            .putInt32ToInt32Field(1, 2)
+            .putInt32ToInt32Field(3, 4)
+            .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build())
+            .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build());
     TestMap message = builder.build();
 
     // Test getField(), getRepeatedFieldCount(), getRepeatedField().
-    assertHasMapValues(message, "int32_to_int32_field",
-        mapForValues(1, 2, 3, 4));
-    assertHasMapValues(message, "int32_to_message_field",
+    assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4));
+    assertHasMapValues(
+        message,
+        "int32_to_message_field",
         mapForValues(
             11, MessageValue.newBuilder().setValue(22).build(),
             33, MessageValue.newBuilder().setValue(44).build()));
@@ -710,9 +702,10 @@
     assertEquals(0, message.getInt32ToMessageField().size());
 
     // Test setField()
-    setMapValues(builder, "int32_to_int32_field",
-        mapForValues(11, 22, 33, 44));
-    setMapValues(builder, "int32_to_message_field",
+    setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44));
+    setMapValues(
+        builder,
+        "int32_to_message_field",
         mapForValues(
             111, MessageValue.newBuilder().setValue(222).build(),
             333, MessageValue.newBuilder().setValue(444).build()));
@@ -723,20 +716,28 @@
     assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
 
     // Test addRepeatedField
-    builder.addRepeatedField(f("int32_to_int32_field"),
-        newMapEntry(builder, "int32_to_int32_field", 55, 66));
-    builder.addRepeatedField(f("int32_to_message_field"),
-        newMapEntry(builder, "int32_to_message_field", 555,
+    builder.addRepeatedField(
+        f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66));
+    builder.addRepeatedField(
+        f("int32_to_message_field"),
+        newMapEntry(
+            builder,
+            "int32_to_message_field",
+            555,
             MessageValue.newBuilder().setValue(666).build()));
     message = builder.build();
     assertEquals(66, message.getInt32ToInt32Field().get(55).intValue());
     assertEquals(666, message.getInt32ToMessageField().get(555).getValue());
 
     // Test addRepeatedField (overriding existing values)
-    builder.addRepeatedField(f("int32_to_int32_field"),
-        newMapEntry(builder, "int32_to_int32_field", 55, 55));
-    builder.addRepeatedField(f("int32_to_message_field"),
-        newMapEntry(builder, "int32_to_message_field", 555,
+    builder.addRepeatedField(
+        f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55));
+    builder.addRepeatedField(
+        f("int32_to_message_field"),
+        newMapEntry(
+            builder,
+            "int32_to_message_field",
+            555,
             MessageValue.newBuilder().setValue(555).build()));
     message = builder.build();
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
@@ -779,10 +780,9 @@
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    Message dynamicDefaultInstance =
-        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
-    Message dynamicMessage = dynamicDefaultInstance
-        .newBuilderForType().mergeFrom(message.toByteString()).build();
+    Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message dynamicMessage =
+        dynamicDefaultInstance.newBuilderForType().mergeFrom(message.toByteString()).build();
 
     assertEquals(message, dynamicMessage);
     assertEquals(message.hashCode(), dynamicMessage.hashCode());
@@ -793,8 +793,7 @@
   public void testDynamicMessageUnsetKeyAndValue() throws Exception {
     FieldDescriptor field = f("int32_to_int32_field");
 
-    Message dynamicDefaultInstance =
-        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     Message.Builder builder = dynamicDefaultInstance.newBuilderForType();
     // Add an entry without key and value.
     builder.addRepeatedField(field, builder.newBuilderForField(field).build());
@@ -811,8 +810,7 @@
     // of map entries when comparing/hashing map fields.
 
     // We use DynamicMessage to test reflection based equals()/hashCode().
-    Message dynamicDefaultInstance =
-        DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
+    Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     FieldDescriptor field = f("int32_to_int32_field");
 
     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
@@ -839,9 +837,8 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
-        .putInt32ToInt32Field(1, 1)
-        .putInt32ToInt32Field(2, 54321);
+    TestUnknownEnumValue.Builder builder =
+        TestUnknownEnumValue.newBuilder().putInt32ToInt32Field(1, 1).putInt32ToInt32Field(2, 54321);
     ByteString data = builder.build().toByteString();
 
     TestMap message = TestMap.parseFrom(data);
@@ -853,8 +850,7 @@
     assertFalse(message.getUnknownFields().asMap().isEmpty());
     // Serializing and parsing should preserve the unknown entry.
     data = message.toByteString();
-    TestUnknownEnumValue messageWithUnknownEnums =
-        TestUnknownEnumValue.parseFrom(data);
+    TestUnknownEnumValue messageWithUnknownEnums = TestUnknownEnumValue.parseFrom(data);
     assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size());
     assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue());
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
@@ -887,7 +883,8 @@
     setMapValuesUsingAccessors(builder);
     TestMap message = builder.build();
 
-    assertEquals(Arrays.asList("1", "2", "3"),
+    assertEquals(
+        Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
 
@@ -979,7 +976,8 @@
     assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
     assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
 
-    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+    assertEquals(
+        MessageValue.newBuilder().setValue(11).build(),
         testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
     assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
 
@@ -1037,7 +1035,8 @@
       // expected
     }
 
-    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+    assertEquals(
+        MessageValue.newBuilder().setValue(11).build(),
         testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
     try {
       testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
@@ -1146,15 +1145,20 @@
 
   // Regression test for b/20494788
   public void testMapInitializationOrder() throws Exception {
-    assertEquals("RedactAllTypes", map_test.RedactAllTypes
-        .getDefaultInstance().getDescriptorForType().getName());
+    assertEquals(
+        "RedactAllTypes",
+        map_test.RedactAllTypes.getDefaultInstance()
+            .getDescriptorForType()
+            .getName());
 
     map_test.Message1.Builder builder =
         map_test.Message1.newBuilder();
     builder.putMapField("key", true);
     map_test.Message1 message = builder.build();
-    Message mapEntry = (Message) message.getRepeatedField(
-        message.getDescriptorForType().findFieldByName("map_field"), 0);
+    Message mapEntry =
+        (Message)
+            message.getRepeatedField(
+                message.getDescriptorForType().findFieldByName("map_field"), 0);
     assertEquals(2, mapEntry.getAllFields().size());
   }
 
@@ -1163,35 +1167,14 @@
     ReservedAsMapFieldWithEnumValue.newBuilder().build();
   }
 
-  private static <K, V> Map<K, V> newMap(K key1, V value1) {
-    Map<K, V> map = new HashMap<K, V>();
-    map.put(key1, value1);
-    return map;
-  }
-
-  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
-    Map<K, V> map = new HashMap<K, V>();
-    map.put(key1, value1);
-    map.put(key2, value2);
-    return map;
-  }
-
   public void testGetMap() {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValuesUsingAccessors(builder);
     assertMapValuesSet(builder);
     TestMap message = builder.build();
-    assertEquals(
-        message.getStringToInt32Field(),
-        message.getStringToInt32FieldMap());
-    assertEquals(
-        message.getInt32ToBytesField(),
-        message.getInt32ToBytesFieldMap());
-    assertEquals(
-        message.getInt32ToEnumField(),
-        message.getInt32ToEnumFieldMap());
-    assertEquals(
-        message.getInt32ToMessageField(),
-        message.getInt32ToMessageFieldMap());
+    assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap());
+    assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap());
+    assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap());
+    assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap());
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index ef8b27e..6007d8e 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -477,12 +477,12 @@
   }
 
   public void testPutForUnknownEnumValues() throws Exception {
-    TestMap.Builder builder =
+    TestMap message =
         TestMap.newBuilder()
             .putInt32ToEnumFieldValue(0, 0)
             .putInt32ToEnumFieldValue(1, 1)
-            .putInt32ToEnumFieldValue(2, 1000); // unknown value.
-    TestMap message = builder.build();
+            .putInt32ToEnumFieldValue(2, 1000) // unknown value.
+            .build();
     assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
     assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
     assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2));
@@ -608,12 +608,12 @@
 
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
-    TestMap.Builder b1 =
+    TestMap m1 =
         TestMap.newBuilder()
             .putInt32ToInt32Field(1, 2)
             .putInt32ToInt32Field(3, 4)
-            .putInt32ToInt32Field(5, 6);
-    TestMap m1 = b1.build();
+            .putInt32ToInt32Field(5, 6)
+            .build();
 
     TestMap.Builder b2 =
         TestMap.newBuilder()
@@ -654,8 +654,8 @@
     assertEquals(3, message.getOptionalMessage().getInt32ToInt32Field().get(1).intValue());
 
     // Make another change using mergeFrom()
-    TestMap.Builder other = TestMap.newBuilder().putInt32ToInt32Field(1, 4);
-    parent.getOptionalMessageBuilder().mergeFrom(other.build());
+    TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build();
+    parent.getOptionalMessageBuilder().mergeFrom(other);
 
     // Should be able to observe the change.
     message = parent.build();
@@ -751,7 +751,7 @@
   }
 
   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
-    List<Message> entryList = new ArrayList<Message>();
+    List<Message> entryList = new ArrayList<>();
     for (Map.Entry<?, ?> entry : values.entrySet()) {
       entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue()));
     }
@@ -760,7 +760,7 @@
   }
 
   private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) {
-    Map<K, V> map = new HashMap<K, V>();
+    Map<K, V> map = new HashMap<>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
@@ -1002,8 +1002,7 @@
     TestMap message = builder.build();
 
     assertEquals(
-        Arrays.asList("1", "2", "3"),
-        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+        Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet()));
   }
 
   public void testGetMap() {
@@ -1336,10 +1335,10 @@
     output.flush();
 
     CodedInputStream input = CodedInputStream.newInstance(serialized);
-    List<Integer> int32Keys = new ArrayList<Integer>();
-    List<Integer> uint32Keys = new ArrayList<Integer>();
-    List<Long> int64Keys = new ArrayList<Long>();
-    List<String> stringKeys = new ArrayList<String>();
+    List<Integer> int32Keys = new ArrayList<>();
+    List<Integer> uint32Keys = new ArrayList<>();
+    List<Long> int64Keys = new ArrayList<>();
+    List<String> stringKeys = new ArrayList<>();
     int tag;
     while (true) {
       tag = input.readTag();
@@ -1450,20 +1449,20 @@
   }
 
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
-    Map<K, V> map = new HashMap<K, V>();
+    Map<K, V> map = new HashMap<>();
     map.put(key1, value1);
     return map;
   }
 
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
-    Map<K, V> map = new HashMap<K, V>();
+    Map<K, V> map = new HashMap<>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
 
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) {
-    Map<K, V> map = new HashMap<K, V>();
+    Map<K, V> map = new HashMap<>();
     map.put(key1, value1);
     map.put(key2, value2);
     map.put(key3, value3);
diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
index 4a68c8b..304261c 100644
--- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
+++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java
@@ -385,12 +385,12 @@
           }
 
           @Override
-          public void writeLazy(byte[] value, int offset, int length) throws IOException {
+          public void write(ByteBuffer value) throws IOException {
             throw new UnsupportedOperationException();
           }
 
           @Override
-          public void write(ByteBuffer value) throws IOException {
+          public void writeLazy(byte[] value, int offset, int length) throws IOException {
             throw new UnsupportedOperationException();
           }
 
diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java
index 1e89111..983caec 100644
--- a/java/core/src/test/java/com/google/protobuf/ParserTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java
@@ -58,8 +58,7 @@
     }
   }
 
-  private void assertRoundTripEquals(MessageLite message,
-                                     ExtensionRegistryLite registry)
+  private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry)
       throws Exception {
     final byte[] data = message.toByteArray();
     final int offset = 20;
@@ -67,15 +66,12 @@
     final int padding = 30;
     Parser<? extends MessageLite> parser = message.getParserForType();
     assertMessageEquals(message, parser.parseFrom(data, registry));
-    assertMessageEquals(message, parser.parseFrom(
-        generatePaddingArray(data, offset, padding),
-        offset, length, registry));
-    assertMessageEquals(message, parser.parseFrom(
-        message.toByteString(), registry));
-    assertMessageEquals(message, parser.parseFrom(
-        new ByteArrayInputStream(data), registry));
-    assertMessageEquals(message, parser.parseFrom(
-        CodedInputStream.newInstance(data), registry));
+    assertMessageEquals(
+        message,
+        parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry));
+    assertMessageEquals(message, parser.parseFrom(message.toByteString(), registry));
+    assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry));
+    assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry));
     assertMessageEquals(
         message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
   }
@@ -87,23 +83,17 @@
     final int length = data.length;
     final int padding = 30;
 
-    Parser<MessageLite> parser =
-        (Parser<MessageLite>) message.getParserForType();
+    Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType();
     assertMessageEquals(message, parser.parseFrom(data));
-    assertMessageEquals(message, parser.parseFrom(
-        generatePaddingArray(data, offset, padding),
-        offset, length));
+    assertMessageEquals(
+        message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length));
     assertMessageEquals(message, parser.parseFrom(message.toByteString()));
-    assertMessageEquals(message, parser.parseFrom(
-        new ByteArrayInputStream(data)));
-    assertMessageEquals(message, parser.parseFrom(
-        CodedInputStream.newInstance(data)));
+    assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data)));
+    assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data)));
     assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
   }
 
-  private void assertMessageEquals(
-      MessageLite expected, MessageLite actual)
-      throws Exception {
+  private void assertMessageEquals(MessageLite expected, MessageLite actual) throws Exception {
     if (expected instanceof Message) {
       assertEquals(expected, actual);
     } else {
@@ -126,20 +116,16 @@
     assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
   }
 
-  private <T extends MessageLite> void assertParsePartial(
-      Parser<T> parser, T partialMessage) throws Exception {
-    final String errorString =
-        "Should throw exceptions when the parsed message isn't initialized.";
+  private <T extends MessageLite> void assertParsePartial(Parser<T> parser, T partialMessage)
+      throws Exception {
+    final String errorString = "Should throw exceptions when the parsed message isn't initialized.";
 
     // parsePartialFrom should pass.
     byte[] data = partialMessage.toByteArray();
     assertEquals(partialMessage, parser.parsePartialFrom(data));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        partialMessage.toByteString()));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        new ByteArrayInputStream(data)));
-    assertEquals(partialMessage, parser.parsePartialFrom(
-        CodedInputStream.newInstance(data)));
+    assertEquals(partialMessage, parser.parsePartialFrom(partialMessage.toByteString()));
+    assertEquals(partialMessage, parser.parsePartialFrom(new ByteArrayInputStream(data)));
+    assertEquals(partialMessage, parser.parsePartialFrom(CodedInputStream.newInstance(data)));
 
     // parseFrom(ByteArray)
     try {
@@ -167,8 +153,7 @@
 
     // parseFrom(CodedInputStream)
     try {
-      parser.parseFrom(CodedInputStream.newInstance(
-          partialMessage.toByteArray()));
+      parser.parseFrom(CodedInputStream.newInstance(partialMessage.toByteArray()));
       fail(errorString);
     } catch (IOException e) {
       // pass.
@@ -176,14 +161,12 @@
   }
 
   public void testParseExtensions() throws Exception {
-    assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
-                          TestUtil.getExtensionRegistry());
+    assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry());
   }
 
   public void testParsePacked() throws Exception {
     assertRoundTripEquals(TestUtil.getPackedSet());
-    assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
-                          TestUtil.getExtensionRegistry());
+    assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry());
   }
 
   public void testParseDelimitedTo() throws Exception {
@@ -202,9 +185,7 @@
     // All fields will be treated as unknown fields in emptyMessage.
     TestEmptyMessage emptyMessage =
         TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString());
-    assertEquals(
-        TestUtil.getAllSet().toByteString(),
-        emptyMessage.toByteString());
+    assertEquals(TestUtil.getAllSet().toByteString(), emptyMessage.toByteString());
   }
 
 
@@ -212,7 +193,8 @@
     TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
     builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
     builder.setExtension(TestOptimizedForSize.testExtension, 56);
-    builder.setExtension(TestOptimizedForSize.testExtension2,
+    builder.setExtension(
+        TestOptimizedForSize.testExtension2,
         TestRequiredOptimizedForSize.newBuilder().setX(78).build());
 
     TestOptimizedForSize message = builder.build();
@@ -222,9 +204,8 @@
     assertRoundTripEquals(message, registry);
   }
 
-  /** Helper method for {@link #testParsingMerge()}.*/
-  private void assertMessageMerged(TestAllTypes allTypes)
-      throws Exception {
+  /** Helper method for {@link #testParsingMerge()}. */
+  private void assertMessageMerged(TestAllTypes allTypes) throws Exception {
     assertEquals(3, allTypes.getOptionalInt32());
     assertEquals(2, allTypes.getOptionalInt64());
     assertEquals("hello", allTypes.getOptionalString());
@@ -237,39 +218,48 @@
     builder.clear();
     TestAllTypes msg2 = builder.setOptionalInt64(2).build();
     builder.clear();
-    TestAllTypes msg3 = builder.setOptionalInt32(3)
-        .setOptionalString("hello").build();
+    TestAllTypes msg3 = builder.setOptionalInt32(3).setOptionalString("hello").build();
 
     // Build groups.
     TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg1).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg1).build();
     TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg2).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg2).build();
     TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
-        .setField1(msg3).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg3).build();
     TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg1).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg1).build();
     TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg2).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg2).build();
     TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
-        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
-        .setField1(msg3).build();
+        TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg3).build();
 
     // Assign and serialize RepeatedFieldsGenerator.
-    ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
-        .addField1(msg1).addField1(msg2).addField1(msg3)
-        .addField2(msg1).addField2(msg2).addField2(msg3)
-        .addField3(msg1).addField3(msg2).addField3(msg3)
-        .addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
-        .addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
-        .addExt1(msg1).addExt1(msg2).addExt1(msg3)
-        .addExt2(msg1).addExt2(msg2).addExt2(msg3)
-        .build().toByteString();
+    ByteString data =
+        TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
+            .addField1(msg1)
+            .addField1(msg2)
+            .addField1(msg3)
+            .addField2(msg1)
+            .addField2(msg2)
+            .addField2(msg3)
+            .addField3(msg1)
+            .addField3(msg2)
+            .addField3(msg3)
+            .addGroup1(optionalG1)
+            .addGroup1(optionalG2)
+            .addGroup1(optionalG3)
+            .addGroup2(repeatedG1)
+            .addGroup2(repeatedG2)
+            .addGroup2(repeatedG3)
+            .addExt1(msg1)
+            .addExt1(msg2)
+            .addExt1(msg3)
+            .addExt2(msg1)
+            .addExt2(msg2)
+            .addExt2(msg3)
+            .build()
+            .toByteString();
 
     // Parse TestParsingMerge.
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
@@ -279,21 +269,18 @@
     // Required and optional fields should be merged.
     assertMessageMerged(parsingMerge.getRequiredAllTypes());
     assertMessageMerged(parsingMerge.getOptionalAllTypes());
-    assertMessageMerged(
-        parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
-    assertMessageMerged(parsingMerge.getExtension(
-        TestParsingMerge.optionalExt));
+    assertMessageMerged(parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
+    assertMessageMerged(parsingMerge.getExtension(TestParsingMerge.optionalExt));
 
     // Repeated fields should not be merged.
     assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
     assertEquals(3, parsingMerge.getRepeatedGroupCount());
-    assertEquals(3, parsingMerge.getExtensionCount(
-        TestParsingMerge.repeatedExt));
+    assertEquals(3, parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt));
   }
 
   public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() {
     try {
-      TestUtil.getAllSet().parseDelimitedFrom(
+      TestAllTypes.parseDelimitedFrom(
           new InputStream() {
             @Override
             public int read() throws IOException {
@@ -308,7 +295,7 @@
 
   public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() {
     try {
-      TestUtil.getAllSet().parseDelimitedFrom(
+      TestAllTypes.parseDelimitedFrom(
           new InputStream() {
             private int i;
 
diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
index 1e58332..d9a6d7c 100644
--- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java
@@ -58,9 +58,9 @@
   private RpcController mockController;
 
   private final Descriptors.MethodDescriptor fooDescriptor =
-    TestService.getDescriptor().getMethods().get(0);
+      TestService.getDescriptor().getMethods().get(0);
   private final Descriptors.MethodDescriptor barDescriptor =
-    TestService.getDescriptor().getMethods().get(1);
+      TestService.getDescriptor().getMethods().get(1);
 
   @Override
   protected void setUp() throws Exception {
@@ -79,16 +79,22 @@
     MockCallback<Message> barCallback = new MockCallback<Message>();
     TestService mockService = control.createMock(TestService.class);
 
-    mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
-                    this.<FooResponse>wrapsCallback(fooCallback));
-    mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
-                    this.<BarResponse>wrapsCallback(barCallback));
+    mockService.foo(
+        EasyMock.same(mockController),
+        EasyMock.same(fooRequest),
+        this.<FooResponse>wrapsCallback(fooCallback));
+    mockService.bar(
+        EasyMock.same(mockController),
+        EasyMock.same(barRequest),
+        this.<BarResponse>wrapsCallback(barCallback));
     control.replay();
 
-    mockService.callMethod(fooDescriptor, mockController,
-                           fooRequest, fooCallback);
-    mockService.callMethod(barDescriptor, mockController,
-                           barRequest, barCallback);
+    mockService.callMethod(
+        fooDescriptor, mockController,
+        fooRequest, fooCallback);
+    mockService.callMethod(
+        barDescriptor, mockController,
+        barRequest, barCallback);
     control.verify();
   }
 
@@ -96,14 +102,10 @@
   public void testGetPrototype() throws Exception {
     TestService mockService = control.createMock(TestService.class);
 
-    assertSame(mockService.getRequestPrototype(fooDescriptor),
-               FooRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(fooDescriptor),
-               FooResponse.getDefaultInstance());
-    assertSame(mockService.getRequestPrototype(barDescriptor),
-               BarRequest.getDefaultInstance());
-    assertSame(mockService.getResponsePrototype(barDescriptor),
-               BarResponse.getDefaultInstance());
+    assertSame(mockService.getRequestPrototype(fooDescriptor), FooRequest.getDefaultInstance());
+    assertSame(mockService.getResponsePrototype(fooDescriptor), FooResponse.getDefaultInstance());
+    assertSame(mockService.getRequestPrototype(barDescriptor), BarRequest.getDefaultInstance());
+    assertSame(mockService.getResponsePrototype(barDescriptor), BarResponse.getDefaultInstance());
   }
 
   /** Tests generated stubs. */
@@ -116,17 +118,17 @@
     TestService stub = TestService.newStub(mockChannel);
 
     mockChannel.callMethod(
-      EasyMock.same(fooDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(fooRequest),
-      EasyMock.same(FooResponse.getDefaultInstance()),
-      this.<Message>wrapsCallback(fooCallback));
+        EasyMock.same(fooDescriptor),
+        EasyMock.same(mockController),
+        EasyMock.same(fooRequest),
+        EasyMock.same(FooResponse.getDefaultInstance()),
+        this.<Message>wrapsCallback(fooCallback));
     mockChannel.callMethod(
-      EasyMock.same(barDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(barRequest),
-      EasyMock.same(BarResponse.getDefaultInstance()),
-      this.<Message>wrapsCallback(barCallback));
+        EasyMock.same(barDescriptor),
+        EasyMock.same(mockController),
+        EasyMock.same(barRequest),
+        EasyMock.same(BarResponse.getDefaultInstance()),
+        this.<Message>wrapsCallback(barCallback));
     control.replay();
 
     stub.foo(mockController, fooRequest, fooCallback);
@@ -138,24 +140,26 @@
   public void testBlockingStub() throws Exception {
     FooRequest fooRequest = FooRequest.newBuilder().build();
     BarRequest barRequest = BarRequest.newBuilder().build();
-    BlockingRpcChannel mockChannel =
-        control.createMock(BlockingRpcChannel.class);
-    TestService.BlockingInterface stub =
-        TestService.newBlockingStub(mockChannel);
+    BlockingRpcChannel mockChannel = control.createMock(BlockingRpcChannel.class);
+    TestService.BlockingInterface stub = TestService.newBlockingStub(mockChannel);
 
     FooResponse fooResponse = FooResponse.newBuilder().build();
     BarResponse barResponse = BarResponse.newBuilder().build();
 
-    EasyMock.expect(mockChannel.callBlockingMethod(
-      EasyMock.same(fooDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(fooRequest),
-      EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
-    EasyMock.expect(mockChannel.callBlockingMethod(
-      EasyMock.same(barDescriptor),
-      EasyMock.same(mockController),
-      EasyMock.same(barRequest),
-      EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
+    EasyMock.expect(
+            mockChannel.callBlockingMethod(
+                EasyMock.same(fooDescriptor),
+                EasyMock.same(mockController),
+                EasyMock.same(fooRequest),
+                EasyMock.same(FooResponse.getDefaultInstance())))
+        .andReturn(fooResponse);
+    EasyMock.expect(
+            mockChannel.callBlockingMethod(
+                EasyMock.same(barDescriptor),
+                EasyMock.same(mockController),
+                EasyMock.same(barRequest),
+                EasyMock.same(BarResponse.getDefaultInstance())))
+        .andReturn(barResponse);
     control.replay();
 
     assertSame(fooResponse, stub.foo(mockController, fooRequest));
@@ -164,13 +168,11 @@
   }
 
   public void testNewReflectiveService() {
-    ServiceWithNoOuter.Interface impl =
-        control.createMock(ServiceWithNoOuter.Interface.class);
+    ServiceWithNoOuter.Interface impl = control.createMock(ServiceWithNoOuter.Interface.class);
     RpcController controller = control.createMock(RpcController.class);
     Service service = ServiceWithNoOuter.newReflectiveService(impl);
 
-    MethodDescriptor fooMethod =
-        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
     RpcCallback<Message> callback =
         new RpcCallback<Message>() {
@@ -180,11 +182,9 @@
             fail();
           }
         };
-    RpcCallback<TestAllTypes> specializedCallback =
-        RpcUtil.specializeCallback(callback);
+    RpcCallback<TestAllTypes> specializedCallback = RpcUtil.specializeCallback(callback);
 
-    impl.foo(EasyMock.same(controller), EasyMock.same(request),
-        EasyMock.same(specializedCallback));
+    impl.foo(EasyMock.same(controller), EasyMock.same(request), EasyMock.same(specializedCallback));
     EasyMock.expectLastCall();
 
     control.replay();
@@ -198,11 +198,9 @@
     ServiceWithNoOuter.BlockingInterface impl =
         control.createMock(ServiceWithNoOuter.BlockingInterface.class);
     RpcController controller = control.createMock(RpcController.class);
-    BlockingService service =
-        ServiceWithNoOuter.newReflectiveBlockingService(impl);
+    BlockingService service = ServiceWithNoOuter.newReflectiveBlockingService(impl);
 
-    MethodDescriptor fooMethod =
-        ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+    MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
     MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
 
     TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
@@ -211,8 +209,7 @@
 
     control.replay();
 
-    Message response =
-        service.callBlockingMethod(fooMethod, controller, request);
+    Message response = service.callBlockingMethod(fooMethod, controller, request);
     assertEquals(expectedResponse, response);
 
     control.verify();
@@ -221,16 +218,16 @@
   public void testNoGenericServices() throws Exception {
     // Non-services should be usable.
     UnittestNoGenericServices.TestMessage message =
-      UnittestNoGenericServices.TestMessage.newBuilder()
-        .setA(123)
-        .setExtension(UnittestNoGenericServices.testExtension, 456)
-        .build();
+        UnittestNoGenericServices.TestMessage.newBuilder()
+            .setA(123)
+            .setExtension(UnittestNoGenericServices.testExtension, 456)
+            .build();
     assertEquals(123, message.getA());
     assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
 
     // Build a list of the class names nested in UnittestNoGenericServices.
-    String outerName = "google.protobuf.no_generic_services_test." +
-                       "UnittestNoGenericServices";
+    String outerName =
+        "google.protobuf.no_generic_services_test.UnittestNoGenericServices";
     Class<?> outerClass = Class.forName(outerName);
 
     Set<String> innerClassNames = new HashSet<String>();
@@ -244,9 +241,9 @@
       //   separator.
       assertTrue(fullName.startsWith(outerName));
 
-      if (!Service.class.isAssignableFrom(innerClass) &&
-          !Message.class.isAssignableFrom(innerClass) &&
-          !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
+      if (!Service.class.isAssignableFrom(innerClass)
+          && !Message.class.isAssignableFrom(innerClass)
+          && !ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
         // Ignore any classes not generated by the base code generator.
         continue;
       }
@@ -264,8 +261,7 @@
     assertEquals(1, file.getServices().size());
     assertEquals("TestService", file.getServices().get(0).getName());
     assertEquals(1, file.getServices().get(0).getMethods().size());
-    assertEquals("Foo",
-        file.getServices().get(0).getMethods().get(0).getName());
+    assertEquals("Foo", file.getServices().get(0).getMethods().get(0).getName());
   }
 
 
@@ -284,13 +280,18 @@
   private static class MockCallback<T extends Message> implements RpcCallback<T> {
     private boolean called = false;
 
-    public boolean isCalled() { return called; }
+    public boolean isCalled() {
+      return called;
+    }
 
-    public void reset() { called = false; }
+    public void reset() {
+      called = false;
+    }
 
     @Override
     public void run(T message) {
-      called = true; }
+      called = true;
+    }
   }
 
   /** Implementation of the wrapsCallback() argument matcher. */
@@ -307,7 +308,7 @@
       if (!(actual instanceof RpcCallback)) {
         return false;
       }
-      RpcCallback actualCallback = (RpcCallback)actual;
+      RpcCallback actualCallback = (RpcCallback) actual;
 
       callback.reset();
       actualCallback.run(null);
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 48ee957..36e5eea 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -119,8 +119,6 @@
 import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
 import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
 import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
-import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
-import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
 import static protobuf_unittest.UnittestProto.defaultBoolExtension;
 import static protobuf_unittest.UnittestProto.defaultBytesExtension;
 import static protobuf_unittest.UnittestProto.defaultCordExtension;
@@ -222,6 +220,8 @@
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto.ForeignEnum;
 import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import protobuf_unittest.UnittestProto.RepeatedGroup_extension;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
 import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder;
 import protobuf_unittest.UnittestProto.TestAllTypes;
@@ -234,6 +234,11 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
 import junit.framework.Assert;
 
 /**
@@ -2634,7 +2639,6 @@
         break;
       case FOO_NOT_SET:
         break;
-      default:
         // TODO(b/18683919): go/enum-switch-lsc
     }
   }
@@ -2702,7 +2706,7 @@
       this.publicImportFile = importFile.getDependencies().get(0);
 
       Descriptors.Descriptor testAllTypes;
-      if (baseDescriptor.getName() == "TestAllTypes") {
+      if ("TestAllTypes".equals(baseDescriptor.getName())) {
         testAllTypes = baseDescriptor;
       } else {
         testAllTypes = file.findMessageTypeByName("TestAllTypes");
@@ -3857,4 +3861,28 @@
     }
   }
   // END FULL-RUNTIME
+
+  /** Helper class to test logged messages */
+  public static class TestLogHandler extends Handler {
+    /** We will keep a private list of all logged records */
+    private final List<LogRecord> list = new ArrayList<>();
+
+    /** Adds the most recently logged record to our list. */
+    @Override
+    public synchronized void publish(LogRecord record) {
+      list.add(record);
+    }
+
+    @Override
+    public void flush() {}
+
+    @Override
+    public void close() {}
+
+    /** Returns a snapshot of the logged records. */
+    public synchronized List<LogRecord> getStoredLogRecords() {
+      List<LogRecord> result = new ArrayList<>(list);
+      return Collections.unmodifiableList(result);
+    }
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index d240088..2fad0b9 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -49,6 +49,7 @@
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 import java.io.StringReader;
 import java.util.List;
+import java.util.logging.Logger;
 import junit.framework.TestCase;
 
 /**
@@ -131,6 +132,8 @@
           + "  i: 456\n"
           + "}\n";
 
+  private final TextFormat.Parser parserAllowingUnknownExtensions =
+      TextFormat.Parser.newBuilder().setAllowUnknownExtensions(true).build();
 
   private final TextFormat.Parser parserWithOverwriteForbidden =
       TextFormat.Parser.newBuilder()
@@ -467,7 +470,7 @@
       fail("expected parse exception");
     } catch (TextFormat.ParseException e) {
       assertEquals(
-          "6:1: Non-repeated field "
+          "4:44: Non-repeated field "
               + "\"protobuf_unittest.TestMessageSetExtension1.message_set_extension\""
               + " cannot be overwritten.",
           e.getMessage());
@@ -519,6 +522,23 @@
   }
 
 
+  private void assertParseErrorWithUnknownExtensions(String error, String text) {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    try {
+      parserAllowingUnknownExtensions.merge(text, builder);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
+  }
+
+  private TestAllTypes assertParseSuccessWithUnknownExtensions(String text)
+      throws TextFormat.ParseException {
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    parserAllowingUnknownExtensions.merge(text, builder);
+    return builder.build();
+  }
+
   private void assertParseErrorWithOverwriteForbidden(String error, String text) {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
@@ -954,6 +974,54 @@
   }
 
 
+  public void testParseUnknownExtensions() throws Exception {
+    TestUtil.TestLogHandler logHandler = new TestUtil.TestLogHandler();
+    Logger logger = Logger.getLogger(TextFormat.class.getName());
+    logger.addHandler(logHandler);
+    // Test unknown extension can pass.
+    assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123");
+    assertParseSuccessWithUnknownExtensions("[unknown_extension]: 123\n"
+        + "[unknown_ext]: inf\n"
+        + "[unknown]: 1.234");
+    // Test warning messages.
+    assertEquals("Input contains unknown fields and/or extensions:\n"
+        + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]",
+        logHandler.getStoredLogRecords().get(0).getMessage());
+    assertEquals("Input contains unknown fields and/or extensions:\n"
+        + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+        + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_ext]\n"
+        + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown]",
+        logHandler.getStoredLogRecords().get(1).getMessage());
+
+    // Test unknown field can not pass.
+    assertParseErrorWithUnknownExtensions(
+        "2:1: Input contains unknown fields and/or extensions:\n"
+        + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+        + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field",
+        "[unknown_extension]: 1\n"
+        + "unknown_field: 12345");
+    assertParseErrorWithUnknownExtensions(
+        "3:1: Input contains unknown fields and/or extensions:\n"
+        + "1:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension1]\n"
+        + "2:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension2]\n"
+        + "3:1:\tprotobuf_unittest.TestAllTypes.unknown_field\n"
+        + "4:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension3]",
+        "[unknown_extension1]: 1\n"
+        + "[unknown_extension2]: 2\n"
+        + "unknown_field: 12345\n"
+        + "[unknown_extension3]: 3\n");
+    assertParseErrorWithUnknownExtensions(
+        "1:1: Input contains unknown fields and/or extensions:\n"
+        + "1:1:\tprotobuf_unittest.TestAllTypes.unknown_field1\n"
+        + "2:1:\tprotobuf_unittest.TestAllTypes.unknown_field2\n"
+        + "3:2:\tprotobuf_unittest.TestAllTypes.[unknown_extension]\n"
+        + "4:1:\tprotobuf_unittest.TestAllTypes.unknown_field3",
+        "unknown_field1: 1\n"
+        + "unknown_field2: 2\n"
+        + "[unknown_extension]: 12345\n"
+        + "unknown_field3: 3\n");
+  }
+
   // See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
   public void testParseNonRepeatedFields() throws Exception {
     assertParseSuccessWithOverwriteForbidden("repeated_int32: 1\nrepeated_int32: 2\n");
@@ -962,29 +1030,29 @@
         "repeated_nested_message { bb: 1 }\nrepeated_nested_message { bb: 2 }\n");
 
     assertParseErrorWithOverwriteForbidden(
-        "3:17: Non-repeated field "
+        "3:15: Non-repeated field "
             + "\"protobuf_unittest.TestAllTypes.optional_int32\" "
             + "cannot be overwritten.",
         "optional_int32: 1\noptional_bool: true\noptional_int32: 1\n");
     assertParseErrorWithOverwriteForbidden(
-        "2:17: Non-repeated field "
+        "2:1: Non-repeated field "
             + "\"protobuf_unittest.TestAllTypes.optionalgroup\" "
             + "cannot be overwritten.",
         "OptionalGroup { a: 1 }\nOptionalGroup { }\n");
     assertParseErrorWithOverwriteForbidden(
-        "2:33: Non-repeated field "
+        "2:1: Non-repeated field "
             + "\"protobuf_unittest.TestAllTypes.optional_nested_message\" "
             + "cannot be overwritten.",
         "optional_nested_message { }\noptional_nested_message { bb: 3 }\n");
     assertParseErrorWithOverwriteForbidden(
-        "2:16: Non-repeated field "
+        "2:14: Non-repeated field "
             + "\"protobuf_unittest.TestAllTypes.default_int32\" "
             + "cannot be overwritten.",
         "default_int32: 41\n"
             + // the default value
             "default_int32: 41\n");
     assertParseErrorWithOverwriteForbidden(
-        "2:17: Non-repeated field "
+        "2:15: Non-repeated field "
             + "\"protobuf_unittest.TestAllTypes.default_string\" "
             + "cannot be overwritten.",
         "default_string: \"zxcv\"\ndefault_string: \"asdf\"\n");
@@ -1044,7 +1112,7 @@
       fail("Expected parse exception.");
     } catch (TextFormat.ParseException e) {
       assertEquals(
-          "1:36: Field \"protobuf_unittest.TestOneof2.foo_int\""
+          "1:34: Field \"protobuf_unittest.TestOneof2.foo_int\""
               + " is specified along with field \"protobuf_unittest.TestOneof2.foo_string\","
               + " another member of oneof \"foo\".",
           e.getMessage());
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index 86630f6..6316bd8 100644
--- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -353,8 +353,8 @@
   /**
    * Asserts that the given field sets are not equal and have different hash codes.
    *
-   * @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
-   *     than it needs to be. However, this should happen relatively rarely.
+   * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
+   * stricter than it needs to be. However, this should happen relatively rarely.
    */
   private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
     String equalsError = String.format("%s should not be equal to %s", s1, s2);
diff --git a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
index 00f201c..bc73cc9 100644
--- a/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/UnmodifiableLazyStringListTest.java
@@ -42,13 +42,13 @@
  */
 public class UnmodifiableLazyStringListTest extends TestCase {
 
-  private static String STRING_A = "A";
-  private static String STRING_B = "B";
-  private static String STRING_C = "C";
+  private static final String STRING_A = "A";
+  private static final String STRING_B = "B";
+  private static final String STRING_C = "C";
 
-  private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
-  private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
-  private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
+  private static final ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
+  private static final ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
+  private static final ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
 
   public void testReadOnlyMethods() {
     LazyStringArrayList rawList = createSampleList();
diff --git a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
index 2367bd8..28f3658 100644
--- a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
@@ -53,7 +53,7 @@
   NestedEnum optional_nested_enum = 4;
   NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
-  NestedMessage optional_lazy_message = 7 [lazy=true];
+  NestedMessage optional_lazy_message = 7 [lazy = true];
 
   oneof oneof_field {
     int32 oneof_int32 = 11;
@@ -81,7 +81,7 @@
   TestAllTypes.NestedEnum optional_nested_enum = 4;
   TestAllTypes.NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
-  TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy=true];
+  TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy = true];
 }
 
 message TestRepeatedFieldsOnly {
diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
index 20fa03b..080c519 100644
--- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
+++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto
@@ -69,8 +69,7 @@
   optional string name = 1;
 }
 
-message Empty {
-}
+message Empty {}
 
 extend Foo {
   optional int32 varint = 101;
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
index 2ca0251..4ec9688 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -44,12 +44,12 @@
     QUX = 3;
   }
 
-  map<int32, int32>         int32_to_int32_field = 1;
-  map<int32, string>        int32_to_string_field = 2;
-  map<int32, bytes>         int32_to_bytes_field = 3;
-  map<int32, EnumValue>     int32_to_enum_field = 4;
-  map<int32, MessageValue>  int32_to_message_field = 5;
-  map<string, int32>        string_to_int32_field = 6;
+  map<int32, int32> int32_to_int32_field = 1;
+  map<int32, string> int32_to_string_field = 2;
+  map<int32, bytes> int32_to_bytes_field = 3;
+  map<int32, EnumValue> int32_to_enum_field = 4;
+  map<int32, MessageValue> int32_to_message_field = 5;
+  map<string, int32> string_to_int32_field = 6;
 
   message MessageWithRequiredFields {
     required int32 value = 1;
@@ -70,15 +70,20 @@
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
 
-
 // a decoy of TestMap for testing parsing errors
 message BizarroTestMap {
-  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
-  map<string, int32> int32_to_string_field = 2; // different key and value types
-  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
-  map<string, bytes> int32_to_enum_field = 4; // different key and value types
-  map<string, bytes> int32_to_message_field = 5; // different key and value types
-  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+  // same key type, different value
+  map<int32, bytes> int32_to_int32_field = 1;
+  // different key and value types
+  map<string, int32> int32_to_string_field = 2;
+  // different key types, same value
+  map<string, int32> int32_to_bytes_field = 3;
+  // different key and value types
+  map<string, bytes> int32_to_enum_field = 4;
+  // different key and value types
+  map<string, bytes> int32_to_message_field = 5;
+  // same key type, different value
+  map<string, bytes> string_to_int32_field = 6;
 }
 
 // Used to test that java reserved words can be used as protobuf field names
@@ -92,11 +97,13 @@
   map<string, uint32> class = 4;
   map<string, uint32> int = 5;
   map<string, uint32> void = 6;
-  map<string, uint32> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, uint32> string = 7;
   map<string, uint32> package = 8;
-  map<string, uint32> enum = 9; // Most recent Java reserved word
-  map<string, uint32> null = 10;
+  // Most recent Java reserved word
+  map<string, uint32> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, uint32> null = 10;
 }
 
 message ReservedAsMapFieldWithEnumValue {
@@ -110,11 +117,13 @@
   map<string, SampleEnum> class = 4;
   map<string, SampleEnum> int = 5;
   map<string, SampleEnum> void = 6;
-  map<string, SampleEnum> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, SampleEnum> string = 7;
   map<string, SampleEnum> package = 8;
-  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
-  map<string, SampleEnum> null = 10;
+  // Most recent Java reserved word
+  map<string, SampleEnum> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, SampleEnum> null = 10;
 }
 package map_for_proto2_lite_test;
 option java_package = "map_lite_test";
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
index 974f8a2..f73bd63 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
@@ -46,12 +46,12 @@
     QUX = 3;
   }
 
-  map<int32, int32>         int32_to_int32_field = 1;
-  map<int32, string>        int32_to_string_field = 2;
-  map<int32, bytes>         int32_to_bytes_field = 3;
-  map<int32, EnumValue>     int32_to_enum_field = 4;
-  map<int32, MessageValue>  int32_to_message_field = 5;
-  map<string, int32>        string_to_int32_field = 6;
+  map<int32, int32> int32_to_int32_field = 1;
+  map<int32, string> int32_to_string_field = 2;
+  map<int32, bytes> int32_to_bytes_field = 3;
+  map<int32, EnumValue> int32_to_enum_field = 4;
+  map<int32, MessageValue> int32_to_message_field = 5;
+  map<string, int32> string_to_int32_field = 6;
 
   message MessageWithRequiredFields {
     required int32 value = 1;
@@ -72,15 +72,20 @@
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
 
-
 // a decoy of TestMap for testing parsing errors
 message BizarroTestMap {
-  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
-  map<string, int32> int32_to_string_field = 2; // different key and value types
-  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
-  map<string, bytes> int32_to_enum_field = 4; // different key and value types
-  map<string, bytes> int32_to_message_field = 5; // different key and value types
-  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+  // same key type, different value
+  map<int32, bytes> int32_to_int32_field = 1;
+  // different key and value types
+  map<string, int32> int32_to_string_field = 2;
+  // different key types, same value
+  map<string, int32> int32_to_bytes_field = 3;
+  // different key and value types
+  map<string, bytes> int32_to_enum_field = 4;
+  // different key and value types
+  map<string, bytes> int32_to_message_field = 5;
+  // same key type, different value
+  map<string, bytes> string_to_int32_field = 6;
 }
 
 // Used to test that java reserved words can be used as protobuf field names
@@ -94,11 +99,13 @@
   map<string, uint32> class = 4;
   map<string, uint32> int = 5;
   map<string, uint32> void = 6;
-  map<string, uint32> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, uint32> string = 7;
   map<string, uint32> package = 8;
-  map<string, uint32> enum = 9; // Most recent Java reserved word
-  map<string, uint32> null = 10;
+  // Most recent Java reserved word
+  map<string, uint32> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, uint32> null = 10;
 }
 
 message ReservedAsMapFieldWithEnumValue {
@@ -112,9 +119,11 @@
   map<string, SampleEnum> class = 4;
   map<string, SampleEnum> int = 5;
   map<string, SampleEnum> void = 6;
-  map<string, SampleEnum> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, SampleEnum> string = 7;
   map<string, SampleEnum> package = 8;
-  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
-  map<string, SampleEnum> null = 10;
+  // Most recent Java reserved word
+  map<string, SampleEnum> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, SampleEnum> null = 10;
 }
diff --git a/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
index b02ac59..6ebef5e 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_initialization_order_test.proto
@@ -57,5 +57,4 @@
   optional Message1 recursive_extension = 1001;
 }
 
-message RedactAllTypes {
-}
+message RedactAllTypes {}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
index c04f5d5..7324653 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_lite_test.proto
@@ -47,14 +47,14 @@
     QUX = 3;
   }
 
-  map<int32, int32>        int32_to_int32_field = 1;
-  map<int32, string>       int32_to_string_field = 2;
-  map<int32, bytes>        int32_to_bytes_field = 3;
-  map<int32, EnumValue>    int32_to_enum_field = 4;
+  map<int32, int32> int32_to_int32_field = 1;
+  map<int32, string> int32_to_string_field = 2;
+  map<int32, bytes> int32_to_bytes_field = 3;
+  map<int32, EnumValue> int32_to_enum_field = 4;
   map<int32, MessageValue> int32_to_message_field = 5;
-  map<string, int32>       string_to_int32_field = 6;
-  map<uint32, int32>       uint32_to_int32_field = 7;
-  map<int64, int32>        int64_to_int32_field = 8;
+  map<string, int32> string_to_int32_field = 6;
+  map<uint32, int32> uint32_to_int32_field = 7;
+  map<int64, int32> int64_to_int32_field = 8;
 }
 
 // Used to test that a nested builder containing map fields will properly
@@ -66,12 +66,18 @@
 
 // a decoy of TestMap for testing parsing errors
 message BizarroTestMap {
-  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
-  map<string, int32> int32_to_string_field = 2; // different key and value types
-  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
-  map<string, bytes> int32_to_enum_field = 4; // different key and value types
-  map<string, bytes> int32_to_message_field = 5; // different key and value types
-  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+  // same key type, different value
+  map<int32, bytes> int32_to_int32_field = 1;
+  // different key and value types
+  map<string, int32> int32_to_string_field = 2;
+  // different key types, same value
+  map<string, int32> int32_to_bytes_field = 3;
+  // different key and value types
+  map<string, bytes> int32_to_enum_field = 4;
+  // different key and value types
+  map<string, bytes> int32_to_message_field = 5;
+  // same key type, different value
+  map<string, bytes> string_to_int32_field = 6;
 }
 
 // Used to test that java reserved words can be used as protobuf field names
@@ -85,11 +91,13 @@
   map<string, uint32> class = 4;
   map<string, uint32> int = 5;
   map<string, uint32> void = 6;
-  map<string, uint32> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, uint32> string = 7;
   map<string, uint32> package = 8;
-  map<string, uint32> enum = 9; // Most recent Java reserved word
-  map<string, uint32> null = 10;
+  // Most recent Java reserved word
+  map<string, uint32> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, uint32> null = 10;
 }
 
 message ReservedAsMapFieldWithEnumValue {
@@ -103,9 +111,11 @@
   map<string, SampleEnum> class = 4;
   map<string, SampleEnum> int = 5;
   map<string, SampleEnum> void = 6;
-  map<string, SampleEnum> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, SampleEnum> string = 7;
   map<string, SampleEnum> package = 8;
-  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
-  map<string, SampleEnum> null = 10;
+  // Most recent Java reserved word
+  map<string, SampleEnum> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, SampleEnum> null = 10;
 }
diff --git a/java/core/src/test/proto/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
index bc2105e..240600f 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -46,14 +46,14 @@
     QUX = 3;
   }
 
-  map<int32, int32>        int32_to_int32_field = 1;
-  map<int32, string>       int32_to_string_field = 2;
-  map<int32, bytes>        int32_to_bytes_field = 3;
-  map<int32, EnumValue>    int32_to_enum_field = 4;
+  map<int32, int32> int32_to_int32_field = 1;
+  map<int32, string> int32_to_string_field = 2;
+  map<int32, bytes> int32_to_bytes_field = 3;
+  map<int32, EnumValue> int32_to_enum_field = 4;
   map<int32, MessageValue> int32_to_message_field = 5;
-  map<string, int32>       string_to_int32_field = 6;
-  map<uint32, int32>       uint32_to_int32_field = 7;
-  map<int64, int32>        int64_to_int32_field = 8;
+  map<string, int32> string_to_int32_field = 6;
+  map<uint32, int32> uint32_to_int32_field = 7;
+  map<int64, int32> int64_to_int32_field = 8;
 }
 
 // Used to test that a nested builder containing map fields will properly
@@ -65,12 +65,18 @@
 
 // a decoy of TestMap for testing parsing errors
 message BizarroTestMap {
-  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
-  map<string, int32> int32_to_string_field = 2; // different key and value types
-  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
-  map<string, bytes> int32_to_enum_field = 4; // different key and value types
-  map<string, bytes> int32_to_message_field = 5; // different key and value types
-  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+  // same key type, different value
+  map<int32, bytes> int32_to_int32_field = 1;
+  // different key and value types
+  map<string, int32> int32_to_string_field = 2;
+  // different key types, same value
+  map<string, int32> int32_to_bytes_field = 3;
+  // different key and value types
+  map<string, bytes> int32_to_enum_field = 4;
+  // different key and value types
+  map<string, bytes> int32_to_message_field = 5;
+  // same key type, different value
+  map<string, bytes> string_to_int32_field = 6;
 }
 
 // Used to test that java reserved words can be used as protobuf field names
@@ -84,11 +90,13 @@
   map<string, uint32> class = 4;
   map<string, uint32> int = 5;
   map<string, uint32> void = 6;
-  map<string, uint32> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, uint32> string = 7;
   map<string, uint32> package = 8;
-  map<string, uint32> enum = 9; // Most recent Java reserved word
-  map<string, uint32> null = 10;
+  // Most recent Java reserved word
+  map<string, uint32> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, uint32> null = 10;
 }
 
 message ReservedAsMapFieldWithEnumValue {
@@ -102,9 +110,11 @@
   map<string, SampleEnum> class = 4;
   map<string, SampleEnum> int = 5;
   map<string, SampleEnum> void = 6;
-  map<string, SampleEnum> string = 7; // These are also proto keywords
+  // These are also proto keywords
+  map<string, SampleEnum> string = 7;
   map<string, SampleEnum> package = 8;
-  map<string, SampleEnum> enum = 9; // Most recent Java reserved word
-  map<string, SampleEnum> null = 10;
+  // Most recent Java reserved word
+  map<string, SampleEnum> enum = 9;
   // null is not a 'reserved word' per se but as a literal needs similar care
+  map<string, SampleEnum> null = 10;
 }
diff --git a/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
index a5dd66d..07933ed 100644
--- a/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/nested_builders_test.proto
@@ -37,7 +37,6 @@
 option java_multiple_files = true;
 option java_outer_classname = "NestedBuilders";
 
-
 message Vehicle {
   optional Engine engine = 1;
   repeated Wheel wheel = 2;
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
index 31fac55..39c2c07 100644
--- a/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension.proto
@@ -41,10 +41,8 @@
   extensions 1 to max;
 }
 
-message MyNonNestedExtension {
-}
+message MyNonNestedExtension {}
 
 extend MessageToBeExtended {
   optional MyNonNestedExtension nonNestedExtension = 1;
 }
-
diff --git a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
index 37c369e..e2ba46c 100644
--- a/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
+++ b/java/core/src/test/proto/com/google/protobuf/non_nested_extension_lite.proto
@@ -42,10 +42,8 @@
   extensions 1 to max;
 }
 
-message MyNonNestedExtensionLite {
-}
+message MyNonNestedExtensionLite {}
 
 extend MessageLiteToBeExtended {
   optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
 }
-
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
index 4208368..28b8bb5 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test.proto
@@ -36,5 +36,4 @@
 // This message's name is the same with the default outer class name of this
 // proto file. It's used to test if the compiler can avoid this conflict
 // correctly.
-message OuterClassNameTest {
-}
+message OuterClassNameTest {}
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
index 3e5956b..b475510 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test2.proto
@@ -38,7 +38,6 @@
     // This message's name is the same with the default outer class name of this
     // proto file. It's used to test if the compiler can avoid this conflict
     // correctly.
-    message OuterClassNameTest2 {
-    }
+    message OuterClassNameTest2 {}
   }
 }
diff --git a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
index 74a8ba3..e5ef2f0 100644
--- a/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
+++ b/java/core/src/test/proto/com/google/protobuf/outer_class_name_test3.proto
@@ -38,8 +38,6 @@
     // This enum's name is the same with the default outer class name of this
     // proto file. It's used to test if the compiler can avoid this conflict
     // correctly.
-    enum OuterClassNameTest3 {
-      DUMMY_VALUE = 1;
-    }
+    enum OuterClassNameTest3 { DUMMY_VALUE = 1; }
   }
 }
diff --git a/java/pom.xml b/java/pom.xml
index 070951a..c46e52b 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -86,6 +86,12 @@
         <artifactId>guava</artifactId>
         <version>20.0</version>
       </dependency>
+      <dependency>
+        <groupId>com.google.guava</groupId>
+        <artifactId>guava-testlib</artifactId>
+        <version>26.0-jre</version>
+        <scope>test</scope>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 217ba16..bcf4f19 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -25,6 +25,11 @@
       <artifactId>guava</artifactId>
     </dependency>
     <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava-testlib</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.7</version>
diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java
index 17b41cb..7836ccf 100644
--- a/java/util/src/main/java/com/google/protobuf/util/Durations.java
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf.util;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.math.IntMath.checkedAdd;
 import static com.google.common.math.IntMath.checkedSubtract;
 import static com.google.common.math.LongMath.checkedAdd;
@@ -53,6 +54,10 @@
   static final long DURATION_SECONDS_MIN = -315576000000L;
   static final long DURATION_SECONDS_MAX = 315576000000L;
 
+  private static final long SECONDS_PER_MINUTE = 60L;
+  private static final long SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60;
+  private static final long SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
+
   /** A constant holding the minimum valid {@link Duration}, approximately {@code -10,000} years. */
   public static final Duration MIN_VALUE =
       Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
@@ -118,6 +123,7 @@
    * and a positive or negative {@code nanos} field. For durations of one second or more, a non-zero
    * value for the {@code nanos} field must be of the same sign as the {@code seconds} field.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static boolean isValid(long seconds, int nanos) {
     if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
       return false;
@@ -133,6 +139,39 @@
     return true;
   }
 
+  /** Returns whether the given {@link Duration} is negative or not. */
+  public static boolean isNegative(Duration duration) {
+    checkValid(duration);
+    return (duration.getSeconds() == 0) ? duration.getNanos() < 0 : duration.getSeconds() < 0;
+  }
+
+  /**
+   * Ensures that the given {@link Duration} is not negative.
+   *
+   * @throws IllegalArgumentException if {@code duration} is negative or invalid
+   * @throws NullPointerException if {@code duration} is {@code null}
+   */
+  public static Duration checkNotNegative(Duration duration) {
+    checkValid(duration);
+    checkArgument(!isNegative(duration), "duration (%s) must not be negative", toString(duration));
+    return duration;
+  }
+
+  /**
+   * Ensures that the given {@link Duration} is positive.
+   *
+   * @throws IllegalArgumentException if {@code duration} is negative, {@code ZERO}, or invalid
+   * @throws NullPointerException if {@code duration} is {@code null}
+   */
+  public static Duration checkPositive(Duration duration) {
+    checkValid(duration);
+    checkArgument(
+        !isNegative(duration) && !duration.equals(ZERO),
+        "duration (%s) must be positive",
+        toString(duration));
+    return duration;
+  }
+
   /** Throws an {@link IllegalArgumentException} if the given {@link Duration} is not valid. */
   public static Duration checkValid(Duration duration) {
     long seconds = duration.getSeconds();
@@ -216,30 +255,125 @@
     }
   }
 
+  // Static factories
+
+  /** Create a Duration from the number of days. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static Duration fromDays(long days) {
+    return Duration.newBuilder()
+        .setSeconds(checkedMultiply(days, SECONDS_PER_DAY))
+        .setNanos(0)
+        .build();
+  }
+
+  /** Create a Duration from the number of hours. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static Duration fromHours(long hours) {
+    return Duration.newBuilder()
+        .setSeconds(checkedMultiply(hours, SECONDS_PER_HOUR))
+        .setNanos(0)
+        .build();
+  }
+
+  /** Create a Duration from the number of minutes. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static Duration fromMinutes(long minutes) {
+    return Duration.newBuilder()
+        .setSeconds(checkedMultiply(minutes, SECONDS_PER_MINUTE))
+        .setNanos(0)
+        .build();
+  }
+
   /** Create a Duration from the number of seconds. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Duration fromSeconds(long seconds) {
     return normalizedDuration(seconds, 0);
   }
 
-  /**
-   * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
-   * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
-   */
-  public static long toSeconds(Duration duration) {
-    return checkValid(duration).getSeconds();
-  }
-
   /** Create a Duration from the number of milliseconds. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Duration fromMillis(long milliseconds) {
     return normalizedDuration(
         milliseconds / MILLIS_PER_SECOND,
         (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
   }
 
+  /** Create a Duration from the number of microseconds. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static Duration fromMicros(long microseconds) {
+    return normalizedDuration(
+        microseconds / MICROS_PER_SECOND,
+        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /** Create a Duration from the number of nanoseconds. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static Duration fromNanos(long nanoseconds) {
+    return normalizedDuration(
+        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  // Conversion APIs
+
+  /**
+   * Convert a Duration to the number of days. The result will be rounded towards 0 to the nearest
+   * day.
+   */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static long toDays(Duration duration) {
+    return checkValid(duration).getSeconds() / SECONDS_PER_DAY;
+  }
+
+  /**
+   * Convert a Duration to the number of hours. The result will be rounded towards 0 to the nearest
+   * hour.
+   */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static long toHours(Duration duration) {
+    return checkValid(duration).getSeconds() / SECONDS_PER_HOUR;
+  }
+
+  /**
+   * Convert a Duration to the number of minutes. The result will be rounded towards 0 to the
+   * nearest minute.
+   */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static long toMinutes(Duration duration) {
+    return checkValid(duration).getSeconds() / SECONDS_PER_MINUTE;
+  }
+
+  /**
+   * Convert a Duration to the number of seconds. The result will be rounded towards 0 to the
+   * nearest second. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
+   */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
+  public static long toSeconds(Duration duration) {
+    return checkValid(duration).getSeconds();
+  }
+
+  /**
+   * Returns the number of seconds of the given duration as a {@code double}. This method should be
+   * used to accommodate APIs that <b>only</b> accept durations as {@code double} values.
+   *
+   * <p>This conversion may lose precision.
+   *
+   * <p>If you need the number of seconds in this duration as a {@code long} (not a {@code double}),
+   * simply use {@code duration.getSeconds()} or {@link #toSeconds} (which includes validation).
+   */
+  @SuppressWarnings({
+    "DurationSecondsToDouble", // that's the whole point of this method
+    "GoodTime" // this is a legacy conversion API
+  })
+  public static double toSecondsAsDouble(Duration duration) {
+    checkValid(duration);
+    return duration.getSeconds() + duration.getNanos() / 1e9;
+  }
+
   /**
    * Convert a Duration to the number of milliseconds. The result will be rounded towards 0 to the
    * nearest millisecond. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toMillis(Duration duration) {
     checkValid(duration);
     return checkedAdd(
@@ -247,17 +381,11 @@
         duration.getNanos() / NANOS_PER_MILLISECOND);
   }
 
-  /** Create a Duration from the number of microseconds. */
-  public static Duration fromMicros(long microseconds) {
-    return normalizedDuration(
-        microseconds / MICROS_PER_SECOND,
-        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
-  }
-
   /**
    * Convert a Duration to the number of microseconds. The result will be rounded towards 0 to the
    * nearest microseconds. E.g., if the duration represents -1 nanosecond, it will be rounded to 0.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toMicros(Duration duration) {
     checkValid(duration);
     return checkedAdd(
@@ -265,19 +393,16 @@
         duration.getNanos() / NANOS_PER_MICROSECOND);
   }
 
-  /** Create a Duration from the number of nanoseconds. */
-  public static Duration fromNanos(long nanoseconds) {
-    return normalizedDuration(
-        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
-  }
-
   /** Convert a Duration to the number of nanoseconds. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toNanos(Duration duration) {
     checkValid(duration);
     return checkedAdd(
         checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
   }
 
+  // Math operations
+
   /** Add two durations. */
   public static Duration add(Duration d1, Duration d2) {
     checkValid(d1);
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 46deb5d..3301e02 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
@@ -77,7 +77,9 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.text.ParseException;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -106,7 +108,7 @@
   public static Printer printer() {
     return new Printer(
         TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
-        false, false, false);
+        false, false, false, false);
   }
 
   /**
@@ -127,6 +129,7 @@
     private final boolean preservingProtoFieldNames;
     private final boolean omittingInsignificantWhitespace;
     private final boolean printingEnumsAsInts;
+    private final boolean sortingMapKeys;
 
     private Printer(
         TypeRegistry registry,
@@ -134,13 +137,15 @@
         Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
         boolean omittingInsignificantWhitespace,
-        boolean printingEnumsAsInts) {
+        boolean printingEnumsAsInts,
+        boolean sortingMapKeys) {
       this.registry = registry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
       this.printingEnumsAsInts = printingEnumsAsInts;
+      this.sortingMapKeys = sortingMapKeys;
     }
 
     /**
@@ -159,7 +164,8 @@
           includingDefaultValueFields,
           preservingProtoFieldNames,
           omittingInsignificantWhitespace,
-          printingEnumsAsInts);
+          printingEnumsAsInts,
+          sortingMapKeys);
     }
 
     /**
@@ -176,7 +182,8 @@
           Collections.<FieldDescriptor>emptySet(),
           preservingProtoFieldNames,
           omittingInsignificantWhitespace,
-          printingEnumsAsInts);
+          printingEnumsAsInts,
+          sortingMapKeys);
     }
 
     /**
@@ -193,7 +200,8 @@
           Collections.<FieldDescriptor>emptySet(),
           preservingProtoFieldNames,
           omittingInsignificantWhitespace,
-          true);
+          true,
+          sortingMapKeys);
     }
 
     private void checkUnsetPrintingEnumsAsInts() {
@@ -221,7 +229,8 @@
           fieldsToAlwaysOutput,
           preservingProtoFieldNames,
           omittingInsignificantWhitespace,
-          printingEnumsAsInts);
+          printingEnumsAsInts,
+          sortingMapKeys);
     }
 
     private void checkUnsetIncludingDefaultValueFields() {
@@ -244,7 +253,8 @@
           includingDefaultValueFields,
           true,
           omittingInsignificantWhitespace,
-          printingEnumsAsInts);
+          printingEnumsAsInts,
+          sortingMapKeys);
     }
 
 
@@ -272,7 +282,31 @@
           includingDefaultValueFields,
           preservingProtoFieldNames,
           true,
-          printingEnumsAsInts);
+          printingEnumsAsInts,
+          sortingMapKeys);
+    }
+
+    /**
+     * Create a new {@link Printer} that will sort the map keys in the JSON output.
+     *
+     * Use of this modifier is discouraged, the generated JSON messages are equivalent
+     * with and without this option set, but there are some corner caseuse cases that
+     * demand a stable output, while order of map keys is otherwise arbitrary.
+     *
+     * The generated order is not well-defined and should not be depended on, but
+     * it's stable.
+     *
+     * This new Printer clones all other configurations from the current {@link Printer}.
+     */
+    public Printer sortingMapKeys() {
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          includingDefaultValueFields,
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts,
+          true);
     }
 
     /**
@@ -292,7 +326,8 @@
               preservingProtoFieldNames,
               output,
               omittingInsignificantWhitespace,
-              printingEnumsAsInts)
+              printingEnumsAsInts,
+              sortingMapKeys)
           .print(message);
     }
 
@@ -604,6 +639,7 @@
     private final Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
     private final boolean printingEnumsAsInts;
+    private final boolean sortingMapKeys;
     private final TextGenerator generator;
     // We use Gson to help handle string escapes.
     private final Gson gson;
@@ -621,12 +657,14 @@
         boolean preservingProtoFieldNames,
         Appendable jsonOutput,
         boolean omittingInsignificantWhitespace,
-        boolean printingEnumsAsInts) {
+        boolean printingEnumsAsInts,
+        boolean sortingMapKeys) {
       this.registry = registry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.printingEnumsAsInts = printingEnumsAsInts;
+      this.sortingMapKeys = sortingMapKeys;
       this.gson = GsonHolder.DEFAULT_GSON;
       // json format related properties, determined by printerType
       if (omittingInsignificantWhitespace) {
@@ -957,8 +995,32 @@
       }
       generator.print("{" + blankOrNewLine);
       generator.indent();
+
+      @SuppressWarnings("unchecked") // Object guaranteed to be a List for a map field.
+      Collection<Object> elements = (List<Object>) value;
+      if (sortingMapKeys && !elements.isEmpty()) {
+        Comparator<Object> cmp = null;
+        if (keyField.getType() == FieldDescriptor.Type.STRING) {
+          cmp = new Comparator<Object>() {
+            @Override
+            public int compare(final Object o1, final Object o2) {
+              ByteString s1 = ByteString.copyFromUtf8((String) o1);
+              ByteString s2 = ByteString.copyFromUtf8((String) o2);
+              return ByteString.unsignedLexicographicalComparator().compare(s1, s2);
+            }
+          };
+        }
+        TreeMap<Object, Object> tm = new TreeMap<Object, Object>(cmp);
+        for (Object element : elements) {
+          Message entry = (Message) element;
+          Object entryKey = entry.getField(keyField);
+          tm.put(entryKey, element);
+        }
+        elements = tm.values();
+      }
+
       boolean printedElement = false;
-      for (Object element : (List) value) {
+      for (Object element : elements) {
         Message entry = (Message) element;
         Object entryKey = entry.getField(keyField);
         Object entryValue = entry.getField(valueField);
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
index 0475847..4ffb410 100644
--- a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -325,6 +325,7 @@
   // Multiplications and divisions.
 
   // TODO(kak): Delete this.
+  @SuppressWarnings("DurationSecondsToDouble")
   public static Duration multiply(Duration duration, double times) {
     double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0;
     if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {
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 9e528d4..83f3a9d 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
@@ -150,6 +150,7 @@
    * <p><b>Note:</b> Negative second values with fractional seconds must still have non-negative
    * nanos values that count forward in time.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static boolean isValid(long seconds, int nanos) {
     if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
       return false;
@@ -266,6 +267,7 @@
   }
 
   /** Create a Timestamp from the number of seconds elapsed from the epoch. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Timestamp fromSeconds(long seconds) {
     return normalizedTimestamp(seconds, 0);
   }
@@ -276,11 +278,13 @@
    * <p>The result will be rounded down to the nearest second. E.g., if the timestamp represents
    * "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 second.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toSeconds(Timestamp timestamp) {
     return checkValid(timestamp).getSeconds();
   }
 
   /** Create a Timestamp from the number of milliseconds elapsed from the epoch. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Timestamp fromMillis(long milliseconds) {
     return normalizedTimestamp(
         milliseconds / MILLIS_PER_SECOND,
@@ -293,6 +297,7 @@
    * <p>The result will be rounded down to the nearest millisecond. E.g., if the timestamp
    * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toMillis(Timestamp timestamp) {
     checkValid(timestamp);
     return checkedAdd(
@@ -301,6 +306,7 @@
   }
 
   /** Create a Timestamp from the number of microseconds elapsed from the epoch. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Timestamp fromMicros(long microseconds) {
     return normalizedTimestamp(
         microseconds / MICROS_PER_SECOND,
@@ -313,6 +319,7 @@
    * <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
    * represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond.
    */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toMicros(Timestamp timestamp) {
     checkValid(timestamp);
     return checkedAdd(
@@ -321,12 +328,14 @@
   }
 
   /** Create a Timestamp from the number of nanoseconds elapsed from the epoch. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static Timestamp fromNanos(long nanoseconds) {
     return normalizedTimestamp(
         nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
   }
 
   /** Convert a Timestamp to the number of nanoseconds elapsed from the epoch. */
+  @SuppressWarnings("GoodTime") // this is a legacy conversion API
   public static long toNanos(Timestamp timestamp) {
     checkValid(timestamp);
     return checkedAdd(
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 64413bc..6095068 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
@@ -156,6 +156,9 @@
   private String toCompactJsonString(Message message) throws IOException {
     return JsonFormat.printer().omittingInsignificantWhitespace().print(message);
   }
+  private String toSortedJsonString(Message message) throws IOException {
+    return JsonFormat.printer().sortingMapKeys().print(message);
+  }
 
   private void mergeFromJson(String json, Message.Builder builder) throws IOException {
     JsonFormat.parser().merge(json, builder);
@@ -1635,4 +1638,50 @@
       // Expected.
     }
   }
+
+  public void testSortedMapKeys() throws Exception {
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    mapBuilder.putStringToInt32Map("\ud834\udd20", 3); // utf-8 F0 9D 84 A0
+    mapBuilder.putStringToInt32Map("foo", 99);
+    mapBuilder.putStringToInt32Map("xxx", 123);
+    mapBuilder.putStringToInt32Map("\u20ac", 1);  // utf-8 E2 82 AC
+    mapBuilder.putStringToInt32Map("abc", 20);
+    mapBuilder.putStringToInt32Map("19", 19);
+    mapBuilder.putStringToInt32Map("8", 8);
+    mapBuilder.putStringToInt32Map("\ufb00", 2);  // utf-8 EF AC 80
+    mapBuilder.putInt32ToInt32Map(3, 3);
+    mapBuilder.putInt32ToInt32Map(10, 10);
+    mapBuilder.putInt32ToInt32Map(5, 5);
+    mapBuilder.putInt32ToInt32Map(4, 4);
+    mapBuilder.putInt32ToInt32Map(1, 1);
+    mapBuilder.putInt32ToInt32Map(2, 2);
+    mapBuilder.putInt32ToInt32Map(-3, -3);
+    TestMap mapMessage = mapBuilder.build();
+    assertEquals(
+        "{\n"
+            + "  \"int32ToInt32Map\": {\n"
+            + "    \"-3\": -3,\n"
+            + "    \"1\": 1,\n"
+            + "    \"2\": 2,\n"
+            + "    \"3\": 3,\n"
+            + "    \"4\": 4,\n"
+            + "    \"5\": 5,\n"
+            + "    \"10\": 10\n"
+            + "  },\n"
+            + "  \"stringToInt32Map\": {\n"
+            + "    \"19\": 19,\n"
+            + "    \"8\": 8,\n"
+            + "    \"abc\": 20,\n"
+            + "    \"foo\": 99,\n"
+            + "    \"xxx\": 123,\n"
+            + "    \"\u20ac\": 1,\n"
+            + "    \"\ufb00\": 2,\n"
+            + "    \"\ud834\udd20\": 3\n"
+            + "  }\n"
+            + "}",
+        toSortedJsonString(mapMessage));
+
+    TestMap emptyMap = TestMap.getDefaultInstance();
+    assertEquals("{\n}", toSortedJsonString(emptyMap));
+  }
 }
diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js
index f5e1b6b..1618210 100644
--- a/js/binary/proto_test.js
+++ b/js/binary/proto_test.js
@@ -659,5 +659,6 @@
         'jspb.test.TestAllTypes');
 
     checkAllFields(msg, msg2);
+
   });
 });
diff --git a/js/debug.js b/js/debug.js
index ba51bbe..9655b2e 100644
--- a/js/debug.js
+++ b/js/debug.js
@@ -37,6 +37,7 @@
 goog.require('goog.array');
 goog.require('goog.asserts');
 goog.require('goog.object');
+goog.require('jspb.Map');
 goog.require('jspb.Message');
 
 
@@ -90,6 +91,16 @@
     goog.asserts.assertArray(thing);
     return goog.array.map(thing, jspb.debug.dump_);
   }
+
+  if (message instanceof jspb.Map) {
+    var mapObject = {};
+    var entries = message.entries();
+    for (var entry = entries.next(); !entry.done; entry = entries.next()) {
+      mapObject[entry.value[0]] = jspb.debug.dump_(entry.value[1]);
+    }
+    return mapObject;
+  }
+
   goog.asserts.assert(message instanceof jspb.Message,
       'Only messages expected: ' + thing);
   var ctor = message.constructor;
diff --git a/js/debug_test.js b/js/debug_test.js
index d0d646a..5096869 100644
--- a/js/debug_test.js
+++ b/js/debug_test.js
@@ -38,7 +38,9 @@
 // CommonJS-LoadFromFile: test_pb
 goog.require('proto.jspb.test.HasExtensions');
 goog.require('proto.jspb.test.IsExtension');
+goog.require('proto.jspb.test.MapValueMessageNoBinary');
 goog.require('proto.jspb.test.Simple1');
+goog.require('proto.jspb.test.TestMapFieldsNoBinary');
 
 
 // CommonJS-LoadFromFile: testbinary_pb
@@ -113,4 +115,74 @@
     }, jspb.debug.dump(extendable));
   });
 
+  it('testMapsBasicTypes', function() {
+    if (COMPILED) {
+      return;
+    }
+
+    var message = new proto.jspb.test.TestMapFieldsNoBinary();
+    message.getMapBoolStringMap().set(true, 'bool_string_value1');
+    message.getMapBoolStringMap().set(false, 'bool_string_value2');
+    message.getMapStringInt32Map().set('key', 111);
+
+    assertObjectEquals({
+      '$name': 'proto.jspb.test.TestMapFieldsNoBinary',
+      'mapBoolStringMap': {
+        true: 'bool_string_value1',
+        false: 'bool_string_value2'
+      },
+      'mapInt32StringMap': {},
+      'mapInt64StringMap': {},
+      'mapStringBoolMap': {},
+      'mapStringDoubleMap': {},
+      'mapStringEnumMap': {},
+      'mapStringInt32Map': {
+        'key': 111
+      },
+      'mapStringInt64Map': {},
+      'mapStringMsgMap': {},
+      'mapStringStringMap': {},
+      'mapStringTestmapfieldsMap': {}
+    }, jspb.debug.dump(message));
+  });
+
+  it('testMapsMessageValues', function() {
+    if (COMPILED) {
+      return;
+    }
+
+    var value1 = new proto.jspb.test.MapValueMessageNoBinary();
+    value1.setFoo(1111);
+    var value2 = new proto.jspb.test.MapValueMessageNoBinary();
+    value2.setFoo(2222);
+
+    var message = new proto.jspb.test.TestMapFieldsNoBinary();
+    message.getMapStringMsgMap().set('key1', value1);
+    message.getMapStringMsgMap().set('key2', value2);
+
+    assertObjectEquals({
+      '$name': 'proto.jspb.test.TestMapFieldsNoBinary',
+      'mapBoolStringMap': {},
+      'mapInt32StringMap': {},
+      'mapInt64StringMap': {},
+      'mapStringBoolMap': {},
+      'mapStringDoubleMap': {},
+      'mapStringEnumMap': {},
+      'mapStringInt32Map': {},
+      'mapStringInt64Map': {},
+      'mapStringMsgMap': {
+        'key1': {
+          '$name': 'proto.jspb.test.MapValueMessageNoBinary',
+          'foo': 1111
+        },
+        'key2': {
+          '$name': 'proto.jspb.test.MapValueMessageNoBinary',
+          'foo': 2222
+        }
+      },
+      'mapStringStringMap': {},
+      'mapStringTestmapfieldsMap': {}
+    }, jspb.debug.dump(message));
+  });
+
 });
diff --git a/js/gulpfile.js b/js/gulpfile.js
index 709c5cf..c458da6 100644
--- a/js/gulpfile.js
+++ b/js/gulpfile.js
@@ -29,6 +29,11 @@
   'test5.proto',
   'commonjs/test6/test6.proto',
   'test8.proto',
+  'test11.proto',
+  'test12.proto',
+  'test13.proto',
+  'test14.proto',
+  'test15.proto',
   'testbinary.proto',
   'testempty.proto',
   'test.proto',
diff --git a/js/maps_test.js b/js/maps_test.js
index e496f44..4640c98 100755
--- a/js/maps_test.js
+++ b/js/maps_test.js
@@ -340,11 +340,17 @@
     assertElementsEquals(entryIterator.next().value, ['key2', 'value2']);
     assertEquals(entryIterator.next().done, true);
 
-    if (typeof(Symbol) != 'undefined') {
+    try {
       var entryIterable = m.entries()[Symbol.iterator]();
       assertElementsEquals(entryIterable.next().value, ['key1', 'value1']);
       assertElementsEquals(entryIterable.next().value, ['key2', 'value2']);
       assertEquals(entryIterable.next().done, true);
+    } catch (err) {
+      // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+      // undefined in some environment.
+      if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+        throw err;
+      }
     }
 
     var keyIterator = m.keys();
@@ -352,22 +358,34 @@
     assertEquals(keyIterator.next().value, 'key2');
     assertEquals(keyIterator.next().done, true);
 
-    if (typeof(Symbol) != 'undefined') {
+    try {
       var keyIterable = m.keys()[Symbol.iterator]();
       assertEquals(keyIterable.next().value, 'key1');
       assertEquals(keyIterable.next().value, 'key2');
       assertEquals(keyIterable.next().done, true);
+    } catch (err) {
+      // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+      // undefined in some environment.
+      if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+        throw err;
+      }
     }
     var valueIterator = m.values();
     assertEquals(valueIterator.next().value, 'value1');
     assertEquals(valueIterator.next().value, 'value2');
     assertEquals(valueIterator.next().done, true);
 
-    if (typeof(Symbol) != 'undefined') {
+    try {
       var valueIterable = m.values()[Symbol.iterator]();
       assertEquals(valueIterable.next().value, 'value1');
       assertEquals(valueIterable.next().value, 'value2');
       assertEquals(valueIterable.next().done, true);
+    } catch (err) {
+      // jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] may be
+      // undefined in some environment.
+      if (err.name != 'TypeError' && err.name != 'ReferenceError') {
+        throw err;
+      }
     }
   });
 }
diff --git a/js/message.js b/js/message.js
index 6a37745..17b562e 100644
--- a/js/message.js
+++ b/js/message.js
@@ -427,6 +427,24 @@
                                             goog.isArray(o);
 };
 
+/**
+ * Returns true if the provided argument is an extension object.
+ * @param {*} o The object to classify as array or not.
+ * @return {boolean} True if the provided object is an extension object.
+ * @private
+ */
+jspb.Message.isExtensionObject_ = function(o) {
+  // Normal fields are never objects, so we can be sure that if we find an
+  // object here, then it's the extension object. However, we must ensure that
+  // the object is not an array, since arrays are valid field values (bytes
+  // fields can also be array).
+  // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
+  // in Safari on iOS 8. See the description of CL/86511464 for details.
+  return (o !== null && typeof o == 'object' &&
+      !jspb.Message.isArray_(o) &&
+      !(jspb.Message.SUPPORTS_UINT8ARRAY_ && o instanceof Uint8Array));
+};
+
 
 /**
  * If the array contains an extension object in its last position, then the
@@ -452,13 +470,7 @@
   if (msgLength) {
     lastIndex = msgLength - 1;
     var obj = msg.array[lastIndex];
-    // Normal fields are never objects, so we can be sure that if we find an
-    // object here, then it's the extension object. However, we must ensure that
-    // the object is not an array, since arrays are valid field values.
-    // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
-    // in Safari on iOS 8. See the description of CL/86511464 for details.
-    if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
-        !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
+    if (jspb.Message.isExtensionObject_(obj)) {
       msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
       msg.extensionObject_ = obj;
       return;
diff --git a/js/message_test.js b/js/message_test.js
index 2bfec62..c237d06 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -33,7 +33,6 @@
 goog.setTestOnly();
 
 goog.require('goog.json');
-goog.require('goog.string');
 goog.require('goog.testing.PropertyReplacer');
 goog.require('goog.testing.asserts');
 goog.require('goog.userAgent');
@@ -41,6 +40,38 @@
 // CommonJS-LoadFromFile: google-protobuf jspb
 goog.require('jspb.Message');
 
+// CommonJS-LoadFromFile: test15_pb proto.jspb.filenametest.package1
+goog.require('proto.jspb.filenametest.package1.b');
+
+// CommonJS-LoadFromFile: test14_pb proto.jspb.filenametest.package2
+goog.require('proto.jspb.filenametest.package2.TestMessage');
+
+// CommonJS-LoadFromFile: test13_pb proto.jspb.filenametest.package1
+goog.require('proto.jspb.filenametest.package1.a');
+goog.require('proto.jspb.filenametest.package1.TestMessage');
+
+// CommonJS-LoadFromFile: test12_pb proto.jspb.circulartest
+goog.require('proto.jspb.circulartest.ExtensionContainingType1');
+goog.require('proto.jspb.circulartest.ExtensionContainingType2');
+goog.require('proto.jspb.circulartest.ExtensionField1');
+goog.require('proto.jspb.circulartest.ExtensionField2');
+goog.require('proto.jspb.circulartest.ExtensionField3');
+goog.require('proto.jspb.circulartest.MapField1');
+goog.require('proto.jspb.circulartest.MapField2');
+goog.require('proto.jspb.circulartest.MessageField1');
+goog.require('proto.jspb.circulartest.MessageField2');
+goog.require('proto.jspb.circulartest.NestedEnum1');
+goog.require('proto.jspb.circulartest.NestedEnum2');
+goog.require('proto.jspb.circulartest.NestedMessage1');
+goog.require('proto.jspb.circulartest.NestedMessage2');
+goog.require('proto.jspb.circulartest.RepeatedMessageField1');
+goog.require('proto.jspb.circulartest.RepeatedMessageField2');
+
+// CommonJS-LoadFromFile: test11_pb proto.jspb.exttest.reverse
+goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1');
+goog.require('proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2');
+goog.require('proto.jspb.exttest.reverse.c');
+
 // CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested
 goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage');
 goog.require('proto.jspb.exttest.nested.TestOuterMessage');
@@ -77,6 +108,7 @@
 goog.require('proto.jspb.test.TestEndsWithBytes');
 goog.require('proto.jspb.test.TestGroup');
 goog.require('proto.jspb.test.TestGroup1');
+goog.require('proto.jspb.test.TestLastFieldBeforePivot');
 goog.require('proto.jspb.test.TestMessageWithOneof');
 goog.require('proto.jspb.test.TestReservedNames');
 goog.require('proto.jspb.test.TestReservedNamesExtension');
@@ -284,42 +316,6 @@
     assertFalse(response.hasEnumField());
   });
 
-  it('testClearFields', function() {
-    var data = ['str', true, [11], [[22], [33]], ['s1', 's2']];
-    var foo = new proto.jspb.test.OptionalFields(data);
-    foo.clearAString();
-    foo.clearABool();
-    foo.clearANestedMessage();
-    foo.clearARepeatedMessageList();
-    foo.clearARepeatedStringList();
-    assertEquals('', foo.getAString());
-    assertEquals(false, foo.getABool());
-    assertUndefined(foo.getANestedMessage());
-    assertFalse(foo.hasAString());
-    assertFalse(foo.hasABool());
-    assertObjectEquals([], foo.getARepeatedMessageList());
-    assertObjectEquals([], foo.getARepeatedStringList());
-    // NOTE: We want the missing fields in 'expected' to be undefined,
-    // but we actually get a sparse array instead. We could use something
-    // like [1,undefined,2] to avoid this, except that this is still
-    // sparse on IE. No comment...
-    var expected = [,,, [], []];
-    expected[0] = expected[1] = expected[2] = undefined;
-    assertObjectEquals(expected, foo.toArray());
-  });
-
-  it('testDifferenceRawObject', /** @suppress {visibility} */ function() {
-    var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]);
-    var p2 = new proto.jspb.test.HasExtensions(['hi', 'what',
-                                               {1000: 'unique'}]);
-    var diff = /** @type {proto.jspb.test.HasExtensions} */
-        (jspb.Message.difference(p1, p2));
-    assertEquals('', diff.getStr1());
-    assertEquals('what', diff.getStr2());
-    assertEquals('', diff.getStr3());
-    assertEquals('unique', diff.extensionObject_[1000]);
-  });
-
   it('testEqualsSimple', function() {
     var s1 = new proto.jspb.test.Simple1(['hi']);
     assertTrue(jspb.Message.equals(s1, new proto.jspb.test.Simple1(['hi'])));
@@ -419,6 +415,12 @@
         ['hi',,, {100: [{200: 'a'}]}], ['hi', {100: [{200: 'a'}]}]));
   });
 
+  it('testInitializeMessageWithLastFieldNull', function() {
+    // This tests for regression to bug http://b/117298778
+    var msg = new proto.jspb.test.TestLastFieldBeforePivot([null]);
+    assertNotUndefined(msg.getLastFieldBeforePivot());
+  });
+
   it('testEqualsNonFinite', function() {
     assertTrue(jspb.Message.compareFields(NaN, NaN));
     assertTrue(jspb.Message.compareFields(NaN, 'NaN'));
@@ -787,71 +789,6 @@
         message.getRecursiveOneofCase());
   });
 
-  it('testInitializeMessageWithSingleValueSetInOneof', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x']);
-
-    assertEquals('x', message.getPone());
-    assertEquals('', message.getPthree());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
-        message.getPartialOneofCase());
-  });
-
-  it('testKeepsLastWireValueSetInUnion_multipleValues', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof([,, 'x',, 'y']);
-
-    assertEquals('', message.getPone());
-    assertEquals('y', message.getPthree());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
-        message.getPartialOneofCase());
-  });
-
-  it('testSettingOneofFieldClearsOthers', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    assertEquals('', message.getPone());
-    assertEquals('', message.getPthree());
-    assertFalse(message.hasPone());
-    assertFalse(message.hasPthree());
-
-    message.setPone('hi');
-    assertEquals('hi', message.getPone());
-    assertEquals('', message.getPthree());
-    assertTrue(message.hasPone());
-    assertFalse(message.hasPthree());
-
-    message.setPthree('bye');
-    assertEquals('', message.getPone());
-    assertEquals('bye', message.getPthree());
-    assertFalse(message.hasPone());
-    assertTrue(message.hasPthree());
-  });
-
-  it('testSettingOneofFieldDoesNotClearFieldsFromOtherUnions', function() {
-    var other = new proto.jspb.test.TestMessageWithOneof;
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    assertEquals('', message.getPone());
-    assertEquals('', message.getPthree());
-    assertUndefined(message.getRone());
-    assertFalse(message.hasPone());
-    assertFalse(message.hasPthree());
-
-    message.setPone('hi');
-    message.setRone(other);
-    assertEquals('hi', message.getPone());
-    assertEquals('', message.getPthree());
-    assertEquals(other, message.getRone());
-    assertTrue(message.hasPone());
-    assertFalse(message.hasPthree());
-
-    message.setPthree('bye');
-    assertEquals('', message.getPone());
-    assertEquals('bye', message.getPthree());
-    assertEquals(other, message.getRone());
-    assertFalse(message.hasPone());
-    assertTrue(message.hasPthree());
-  });
-
   it('testUnsetsOneofCaseWhenFieldIsCleared', function() {
     var message = new proto.jspb.test.TestMessageWithOneof;
     assertEquals(
@@ -871,178 +808,6 @@
         message.getPartialOneofCase());
   });
 
-  it('testMessageWithDefaultOneofValues', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    assertEquals(1234, message.getAone());
-    assertEquals(0, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
-            .DEFAULT_ONEOF_A_NOT_SET,
-        message.getDefaultOneofACase());
-
-    message.setAone(567);
-    assertEquals(567, message.getAone());
-    assertEquals(0, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
-        message.getDefaultOneofACase());
-
-    message.setAtwo(890);
-    assertEquals(1234, message.getAone());
-    assertEquals(890, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
-        message.getDefaultOneofACase());
-
-    message.clearAtwo();
-    assertEquals(1234, message.getAone());
-    assertEquals(0, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase
-            .DEFAULT_ONEOF_A_NOT_SET,
-        message.getDefaultOneofACase());
-  });
-
-  it('testMessageWithDefaultOneofValues_defaultNotOnFirstField', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    assertEquals(0, message.getBone());
-    assertEquals(1234, message.getBtwo());
-    assertFalse(message.hasBone());
-    assertFalse(message.hasBtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
-            .DEFAULT_ONEOF_B_NOT_SET,
-        message.getDefaultOneofBCase());
-
-    message.setBone(2);
-    assertEquals(2, message.getBone());
-    assertEquals(1234, message.getBtwo());
-    assertTrue(message.hasBone());
-    assertFalse(message.hasBtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
-        message.getDefaultOneofBCase());
-
-    message.setBtwo(3);
-    assertEquals(0, message.getBone());
-    assertFalse(message.hasBone());
-    assertTrue(message.hasBtwo());
-    assertEquals(3, message.getBtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
-        message.getDefaultOneofBCase());
-
-    message.clearBtwo();
-    assertEquals(0, message.getBone());
-    assertFalse(message.hasBone());
-    assertFalse(message.hasBtwo());
-    assertEquals(1234, message.getBtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase
-            .DEFAULT_ONEOF_B_NOT_SET,
-        message.getDefaultOneofBCase());
-  });
-
-  it('testInitializeMessageWithOneofDefaults', function() {
-    var message =
-        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567));
-    assertEquals(567, message.getAone());
-    assertEquals(0, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.AONE,
-        message.getDefaultOneofACase());
-
-    message =
-        new proto.jspb.test.TestMessageWithOneof(new Array(10).concat(890));
-    assertEquals(1234, message.getAone());
-    assertEquals(890, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
-        message.getDefaultOneofACase());
-
-    message =
-        new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567, 890));
-    assertEquals(1234, message.getAone());
-    assertEquals(890, message.getAtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.DefaultOneofACase.ATWO,
-        message.getDefaultOneofACase());
-  });
-
-  it('testInitializeMessageWithOneofDefaults_defaultNotSetOnFirstField',
-      function() {
-        var message;
-
-        message =
-            new proto.jspb.test.TestMessageWithOneof(new Array(11).concat(567));
-        assertEquals(567, message.getBone());
-        assertEquals(1234, message.getBtwo());
-        assertEquals(
-            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BONE,
-            message.getDefaultOneofBCase());
-
-        message =
-            new proto.jspb.test.TestMessageWithOneof(new Array(12).concat(890));
-        assertEquals(0, message.getBone());
-        assertEquals(890, message.getBtwo());
-        assertEquals(
-            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
-            message.getDefaultOneofBCase());
-
-        message = new proto.jspb.test.TestMessageWithOneof(
-            new Array(11).concat(567, 890));
-        assertEquals(0, message.getBone());
-        assertEquals(890, message.getBtwo());
-        assertEquals(
-            proto.jspb.test.TestMessageWithOneof.DefaultOneofBCase.BTWO,
-            message.getDefaultOneofBCase());
-      });
-
-  it('testOneofContainingAnotherMessage', function() {
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.
-            RECURSIVE_ONEOF_NOT_SET,
-        message.getRecursiveOneofCase());
-
-    var other = new proto.jspb.test.TestMessageWithOneof;
-    message.setRone(other);
-    assertEquals(other, message.getRone());
-    assertEquals('', message.getRtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RONE,
-        message.getRecursiveOneofCase());
-
-    message.setRtwo('hi');
-    assertUndefined(message.getRone());
-    assertEquals('hi', message.getRtwo());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.RecursiveOneofCase.RTWO,
-        message.getRecursiveOneofCase());
-  });
-
-  it('testQueryingOneofCaseEnsuresOnlyOneFieldIsSetInUnderlyingArray',
-     function() {
-    var message = new proto.jspb.test.TestMessageWithOneof;
-    message.setPone('x');
-    assertEquals('x', message.getPone());
-    assertEquals('', message.getPthree());
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PONE,
-        message.getPartialOneofCase());
-
-    var array = message.toArray();
-    assertEquals('x', array[2]);
-    assertUndefined(array[4]);
-    array[4] = 'y';
-
-    assertEquals(
-        proto.jspb.test.TestMessageWithOneof.PartialOneofCase.PTHREE,
-        message.getPartialOneofCase());
-    assertUndefined(array[2]);
-    assertEquals('y', array[4]);
-  });
-
   it('testFloatingPointFieldsSupportNan', function() {
     var assertNan = function(x) {
       assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.',
@@ -1065,4 +830,170 @@
     assertNan(message.getDefaultDoubleField());
   });
 
+  it('testExtensionReverseOrder', function() {
+    var message2 =
+        new proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage2;
+
+    message2.setExtension(
+        proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a, 233);
+    message2.setExtension(
+        proto
+            .jspb
+            .exttest
+            .reverse
+            .TestExtensionReverseOrderMessage1
+            .TestExtensionReverseOrderNestedMessage1.b, 2333);
+    message2.setExtension(proto.jspb.exttest.reverse.c, 23333);
+
+    assertEquals(
+        233,
+        message2.getExtension(
+            proto.jspb.exttest.reverse.TestExtensionReverseOrderMessage1.a));
+    assertEquals(
+        2333,
+        message2.getExtension(
+            proto
+                .jspb
+                .exttest
+                .reverse
+                .TestExtensionReverseOrderMessage1
+                .TestExtensionReverseOrderNestedMessage1.b));
+    assertEquals(
+        23333,
+        message2.getExtension(proto.jspb.exttest.reverse.c));
+  });
+
+  it('testCircularDepsBaseOnMessageField', function() {
+    var nestMessage1 = new proto.jspb.circulartest.MessageField1;
+    var nestMessage2 = new proto.jspb.circulartest.MessageField2;
+    var message1 = new proto.jspb.circulartest.MessageField1;
+    var message2 = new proto.jspb.circulartest.MessageField2;
+
+    nestMessage1.setA(1);
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message2.setB(nestMessage1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(1, message2.getB().getA());
+  });
+
+
+  it('testCircularDepsBaseOnRepeatedMessageField', function() {
+    var nestMessage1 = new proto.jspb.circulartest.RepeatedMessageField1;
+    var nestMessage2 = new proto.jspb.circulartest.RepeatedMessageField2;
+    var message1 = new proto.jspb.circulartest.RepeatedMessageField1;
+    var message2 = new proto.jspb.circulartest.RepeatedMessageField2;
+
+    nestMessage1.setA(1);
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message2.addB(nestMessage1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(1, message2.getBList()[0].getA());
+  });
+
+  it('testCircularDepsBaseOnMapField', function() {
+    var nestMessage1 = new proto.jspb.circulartest.MapField1;
+    var nestMessage2 = new proto.jspb.circulartest.MapField2;
+    var message1 = new proto.jspb.circulartest.MapField1;
+    var message2 = new proto.jspb.circulartest.MapField2;
+
+    nestMessage1.setA(1);
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message2.getBMap().set(1, nestMessage1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(1, message2.getBMap().get(1).getA());
+  });
+
+  it('testCircularDepsBaseOnNestedMessage', function() {
+    var nestMessage1 =
+        new proto.jspb.circulartest.NestedMessage1.NestedNestedMessage;
+    var nestMessage2 = new proto.jspb.circulartest.NestedMessage2;
+    var message1 = new proto.jspb.circulartest.NestedMessage1;
+    var message2 = new proto.jspb.circulartest.NestedMessage2;
+
+    nestMessage1.setA(1);
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message2.setB(nestMessage1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(1, message2.getB().getA());
+  });
+
+  it('testCircularDepsBaseOnNestedEnum', function() {
+    var nestMessage2 = new proto.jspb.circulartest.NestedEnum2;
+    var message1 = new proto.jspb.circulartest.NestedEnum1;
+    var message2 = new proto.jspb.circulartest.NestedEnum2;
+
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message2.setB(proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(
+        proto.jspb.circulartest.NestedEnum1.NestedNestedEnum.VALUE_1,
+        message2.getB());
+  });
+
+  it('testCircularDepsBaseOnExtensionContainingType', function() {
+    var nestMessage2 = new proto.jspb.circulartest.ExtensionContainingType2;
+    var message1 = new proto.jspb.circulartest.ExtensionContainingType1;
+
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message1.setExtension(
+        proto.jspb.circulartest.ExtensionContainingType2.c, 1);
+
+
+    assertEquals(2, message1.getB().getA());
+    assertEquals(
+        1,
+        message1.getExtension(
+            proto.jspb.circulartest.ExtensionContainingType2.c));
+  });
+
+  it('testCircularDepsBaseOnExtensionField', function() {
+    var nestMessage2 = new proto.jspb.circulartest.ExtensionField2;
+    var message1 = new proto.jspb.circulartest.ExtensionField1;
+    var message3 = new proto.jspb.circulartest.ExtensionField3;
+
+    nestMessage2.setA(2);
+    message1.setB(nestMessage2);
+    message3.setExtension(proto.jspb.circulartest.ExtensionField2.c, message1);
+
+
+    assertEquals(
+        2,
+        message3.getExtension(proto.jspb.circulartest.ExtensionField2.c)
+            .getB()
+            .getA());
+  });
+
+  it('testSameMessageNameOuputs', function() {
+    var package1Message = new proto.jspb.filenametest.package1.TestMessage;
+    var package2Message = new proto.jspb.filenametest.package2.TestMessage;
+
+    package1Message.setExtension(
+        proto.jspb.filenametest.package1.a, 10);
+    package1Message.setExtension(
+        proto.jspb.filenametest.package1.b, 11);
+    package2Message.setA(12);
+
+    assertEquals(10,
+        package1Message.getExtension(proto.jspb.filenametest.package1.a));
+    assertEquals(11,
+        package1Message.getExtension(proto.jspb.filenametest.package1.b));
+    assertEquals(12, package2Message.getA());
+  });
+
 });
diff --git a/js/proto3_test.js b/js/proto3_test.js
index 4aed88b..7f9d71d 100644
--- a/js/proto3_test.js
+++ b/js/proto3_test.js
@@ -30,17 +30,15 @@
 
 goog.require('goog.crypt.base64');
 goog.require('goog.testing.asserts');
-
 // CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
 goog.require('proto.jspb.test.ForeignMessage');
-
 // CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
 goog.require('proto.jspb.test.Proto3Enum');
 goog.require('proto.jspb.test.TestProto3');
-
+// CommonJS-LoadFromFile: google/protobuf/any_pb proto.google.protobuf
+goog.require('proto.google.protobuf.Any');
 // CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf
 goog.require('proto.google.protobuf.Timestamp');
-
 // CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf
 goog.require('proto.google.protobuf.Struct');
 
@@ -377,6 +375,7 @@
 
   });
 
+
   it('testTimestampWellKnownType', function() {
     var msg = new proto.google.protobuf.Timestamp();
     msg.fromDate(new Date(123456789));
@@ -384,6 +383,9 @@
     assertEquals(789000000, msg.getNanos());
     var date = msg.toDate();
     assertEquals(123456789, date.getTime());
+    var anotherMsg = proto.google.protobuf.Timestamp.fromDate(date);
+    assertEquals(msg.getSeconds(), anotherMsg.getSeconds());
+    assertEquals(msg.getNanos(), anotherMsg.getNanos());
   });
 
   it('testStructWellKnownType', function() {
diff --git a/js/test.proto b/js/test.proto
index 3b538b5..454fd83 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -241,6 +241,17 @@
   optional bytes data = 2;
 }
 
+// This message is for testing extension handling doesn't affect fields before
+// pivot. Don't add new field to this message. See b/117298778 for more detail.
+message TestLastFieldBeforePivot {
+  optional int32 last_field_before_pivot = 1;
+  extensions 100 to max;
+}
+
+extend TestLastFieldBeforePivot {
+  optional int32 extend_test_last_field_before_pivot_field = 101;
+}
+
 
 message Int64Types {
   optional int64 int64_normal = 1 [jstype=JS_NORMAL];
diff --git a/js/test11.proto b/js/test11.proto
new file mode 100644
index 0000000..ae65a46
--- /dev/null
+++ b/js/test11.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package jspb.exttest.reverse;
+
+message TestExtensionReverseOrderMessage1 {
+  extend TestExtensionReverseOrderMessage2 {
+    optional int32 a = 1;
+  }
+  message TestExtensionReverseOrderNestedMessage1 {
+    extend TestExtensionReverseOrderMessage2 {
+      optional int32 b = 2;
+    }
+  }
+}
+
+extend TestExtensionReverseOrderMessage2 {
+  optional int32 c = 3;
+}
+
+message TestExtensionReverseOrderMessage2 {
+  extensions 1 to 100;
+}
diff --git a/js/test12.proto b/js/test12.proto
new file mode 100644
index 0000000..4ece1d0
--- /dev/null
+++ b/js/test12.proto
@@ -0,0 +1,119 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+
+package jspb.circulartest;
+
+message MessageField1 {
+  optional int32 a = 1;
+  optional MessageField2 b = 2;
+}
+
+message MessageField2 {
+  optional int32 a = 1;
+  optional MessageField1 b = 2;
+}
+
+
+message RepeatedMessageField1 {
+  optional int32 a = 1;
+  optional RepeatedMessageField2 b = 2;
+}
+
+message RepeatedMessageField2 {
+  optional int32 a = 1;
+  repeated RepeatedMessageField1 b = 2;
+}
+
+message MapField1 {
+  optional int32 a = 1;
+  optional MapField2 b = 2;
+}
+
+message MapField2 {
+  optional int32 a = 1;
+  map<int32, MapField1> b = 2;
+}
+
+message NestedMessage1 {
+  optional NestedMessage2 b = 2;
+  message NestedNestedMessage {
+    optional int32 a = 1;
+  }
+}
+
+message NestedMessage2 {
+  optional int32 a = 1;
+  optional NestedMessage1.NestedNestedMessage b = 2;
+}
+
+message NestedEnum1 {
+  optional NestedEnum2 b = 2;
+  enum NestedNestedEnum {
+    UNDEFINED = 0;
+    VALUE_1 = 1;
+  }
+}
+
+message NestedEnum2 {
+  optional int32 a = 1;
+  optional NestedEnum1.NestedNestedEnum b = 2;
+}
+
+message ExtensionContainingType1 {
+  optional int32 a = 1;
+  optional ExtensionContainingType2 b = 2;
+  extensions 99 to 100;
+}
+
+message ExtensionContainingType2 {
+  optional int32 a = 1;
+  extend ExtensionContainingType1 {
+    optional int32 c = 99;
+  }
+}
+
+message ExtensionField1 {
+  optional int32 a = 1;
+  optional ExtensionField2 b = 2;
+}
+
+message ExtensionField2 {
+  optional int32 a = 1;
+  extend ExtensionField3 {
+    optional ExtensionField1 c = 99;
+  }
+}
+
+message ExtensionField3 {
+  extensions 99 to 100;
+}
diff --git a/js/test13.proto b/js/test13.proto
new file mode 100644
index 0000000..4f9d272
--- /dev/null
+++ b/js/test13.proto
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package jspb.filenametest.package1;
+
+message TestMessage {
+  extensions 1 to 100;
+}
+
+extend TestMessage {
+  optional int32 a = 1;
+}
+
+enum TestEnum {
+  VALUE_0 = 0;
+  VALUE_1 = 1;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1 {
+  optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2
+    a = 1;
+  optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName2 {
+  optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3
+    a = 1;
+  optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName3 {
+  optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4
+    a = 1;
+  optional int32 b = 2;
+}
+
+message TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName4 {
+  optional TestLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName1
+    a = 1;
+  optional int32 b = 2;
+}
diff --git a/js/test14.proto b/js/test14.proto
new file mode 100644
index 0000000..2447eb1
--- /dev/null
+++ b/js/test14.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+package jspb.filenametest.package2;
+
+message TestMessage {
+  optional int32 a = 1;
+}
+
+enum TestEnum {
+  VALUE_0 = 0;
+  VALUE_1 = 1;
+  VALUE_2 = 2;
+}
diff --git a/js/test15.proto b/js/test15.proto
new file mode 100644
index 0000000..602cc2d
--- /dev/null
+++ b/js/test15.proto
@@ -0,0 +1,39 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto2";
+
+import "test13.proto";
+
+package jspb.filenametest.package1;
+
+extend TestMessage {
+  optional int32 b = 2;
+}
diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h
index 19ca686..f6ea25c 100644
--- a/objectivec/google/protobuf/Timestamp.pbobjc.h
+++ b/objectivec/google/protobuf/Timestamp.pbobjc.h
@@ -129,7 +129,7 @@
  * 01:30 UTC on January 15, 2017.
  *
  * In JavaScript, one can convert a Date object to this format using the
- * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+ * standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
  * method. In Python, a standard `datetime.datetime` object can be converted
  * to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
  * with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto.php b/php/src/Google/Protobuf/Internal/DescriptorProto.php
index 3b215d5..40ea19a 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a message type.
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
index c06a0a6..85d0f28 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto/ExtensionRange.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.DescriptorProto.ExtensionRange</code>
diff --git a/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php b/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
index 73c964f..e3c6e54 100644
--- a/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
+++ b/php/src/Google/Protobuf/Internal/DescriptorProto/ReservedRange.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Range of reserved tag numbers. Reserved tag numbers may not be used by
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
index da30fa9..25f4933 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes an enum type.
diff --git a/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php b/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
index e107958..d84e2af 100644
--- a/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
+++ b/php/src/Google/Protobuf/Internal/EnumDescriptorProto/EnumReservedRange.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Range of reserved numeric values. Reserved values may not be used by
diff --git a/php/src/Google/Protobuf/Internal/EnumOptions.php b/php/src/Google/Protobuf/Internal/EnumOptions.php
index 3d74c81..6af31af 100644
--- a/php/src/Google/Protobuf/Internal/EnumOptions.php
+++ b/php/src/Google/Protobuf/Internal/EnumOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.EnumOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
index 50bda00..8601c2b 100644
--- a/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/EnumValueDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a value within an enum.
diff --git a/php/src/Google/Protobuf/Internal/EnumValueOptions.php b/php/src/Google/Protobuf/Internal/EnumValueOptions.php
index a267c6d..d1f5edd 100644
--- a/php/src/Google/Protobuf/Internal/EnumValueOptions.php
+++ b/php/src/Google/Protobuf/Internal/EnumValueOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.EnumValueOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php b/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
index 00fbebe..caeb802 100644
--- a/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
+++ b/php/src/Google/Protobuf/Internal/ExtensionRangeOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.ExtensionRangeOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
index e578197..1dd6523 100644
--- a/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FieldDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a field within a message.
diff --git a/php/src/Google/Protobuf/Internal/FieldOptions.php b/php/src/Google/Protobuf/Internal/FieldOptions.php
index 751c278..c709564 100644
--- a/php/src/Google/Protobuf/Internal/FieldOptions.php
+++ b/php/src/Google/Protobuf/Internal/FieldOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.FieldOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
index cb10aa7..8eee320 100644
--- a/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/FileDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a complete .proto file.
diff --git a/php/src/Google/Protobuf/Internal/FileDescriptorSet.php b/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
index 9907b17..b5cc1f1 100644
--- a/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
+++ b/php/src/Google/Protobuf/Internal/FileDescriptorSet.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * The protocol compiler can output a FileDescriptorSet containing the .proto
diff --git a/php/src/Google/Protobuf/Internal/FileOptions.php b/php/src/Google/Protobuf/Internal/FileOptions.php
index c6b36bb..c606496 100644
--- a/php/src/Google/Protobuf/Internal/FileOptions.php
+++ b/php/src/Google/Protobuf/Internal/FileOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.FileOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
index f5a65be..2d6fe00 100644
--- a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
+++ b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes the relationship between generated code and its original source
diff --git a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
index 09f958d..74e089c 100644
--- a/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
+++ b/php/src/Google/Protobuf/Internal/GeneratedCodeInfo/Annotation.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.GeneratedCodeInfo.Annotation</code>
diff --git a/php/src/Google/Protobuf/Internal/MessageOptions.php b/php/src/Google/Protobuf/Internal/MessageOptions.php
index bf490de..ccf0919 100644
--- a/php/src/Google/Protobuf/Internal/MessageOptions.php
+++ b/php/src/Google/Protobuf/Internal/MessageOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.MessageOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
index 1bd5dd3..fba0c99 100644
--- a/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/MethodDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a method of a service.
diff --git a/php/src/Google/Protobuf/Internal/MethodOptions.php b/php/src/Google/Protobuf/Internal/MethodOptions.php
index a2c729a..21c07f5 100644
--- a/php/src/Google/Protobuf/Internal/MethodOptions.php
+++ b/php/src/Google/Protobuf/Internal/MethodOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.MethodOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
index 9ecfe5c..c471c80 100644
--- a/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/OneofDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a oneof.
diff --git a/php/src/Google/Protobuf/Internal/OneofOptions.php b/php/src/Google/Protobuf/Internal/OneofOptions.php
index 46b516f..dab1db4 100644
--- a/php/src/Google/Protobuf/Internal/OneofOptions.php
+++ b/php/src/Google/Protobuf/Internal/OneofOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.OneofOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
index 8de7afd..a717371 100644
--- a/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
+++ b/php/src/Google/Protobuf/Internal/ServiceDescriptorProto.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Describes a service.
diff --git a/php/src/Google/Protobuf/Internal/ServiceOptions.php b/php/src/Google/Protobuf/Internal/ServiceOptions.php
index 67162f3..d59d9c3 100644
--- a/php/src/Google/Protobuf/Internal/ServiceOptions.php
+++ b/php/src/Google/Protobuf/Internal/ServiceOptions.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.ServiceOptions</code>
diff --git a/php/src/Google/Protobuf/Internal/SourceCodeInfo.php b/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
index 6e413f7..75cc3dd 100644
--- a/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
+++ b/php/src/Google/Protobuf/Internal/SourceCodeInfo.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Encapsulates information about the original source file from which a
diff --git a/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php b/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
index bad247a..dd39e5b 100644
--- a/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
+++ b/php/src/Google/Protobuf/Internal/SourceCodeInfo/Location.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * Generated from protobuf message <code>google.protobuf.SourceCodeInfo.Location</code>
diff --git a/php/src/Google/Protobuf/Internal/UninterpretedOption.php b/php/src/Google/Protobuf/Internal/UninterpretedOption.php
index 3b517ec..2a13d98 100644
--- a/php/src/Google/Protobuf/Internal/UninterpretedOption.php
+++ b/php/src/Google/Protobuf/Internal/UninterpretedOption.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * A message representing a option the parser does not recognize. This only
diff --git a/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php b/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
index 92ee4b4..f40c485 100644
--- a/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
+++ b/php/src/Google/Protobuf/Internal/UninterpretedOption/NamePart.php
@@ -9,6 +9,7 @@
 use Google\Protobuf\Internal\RepeatedField;
 use Google\Protobuf\Internal\InputStream;
 use Google\Protobuf\Internal\GPBUtil;
+use Google\Protobuf\Internal\GPBWrapperUtils;
 
 /**
  * The name of the uninterpreted option.  Each string represents a segment in
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index ef96196..b82936b 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -41,12 +41,12 @@
 
 __author__ = 'petar@google.com (Petar Petrov)'
 
-try:
-    # This fallback applies for all versions of Python before 3.3
-    import collections.abc as collections_abc
-except ImportError:
-    import collections as collections_abc
 import sys
+try:
+  # This fallback applies for all versions of Python before 3.3
+  import collections.abc as collections_abc
+except ImportError:
+  import collections as collections_abc
 
 if sys.version_info[0] < 3:
   # We would use collections_abc.MutableMapping all the time, but in Python 2
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 1b72b0b..3244251 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -529,10 +529,6 @@
     conflict_fd = copy.deepcopy(unittest_fd)
     conflict_fd.name = 'other_file'
     if api_implementation.Type() == 'cpp':
-      try:
-        self.pool.Add(unittest_fd)
-        self.pool.Add(conflict_fd)
-      except TypeError:
         pass
     else:
       with warnings.catch_warnings(record=True) as w:
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index af6bece..e753cba 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -192,6 +192,14 @@
     self.assertTrue(enum_value_descriptor.has_options)
     self.assertFalse(other_enum_value_descriptor.has_options)
 
+  def testCustomOptionsCopyTo(self):
+    message_descriptor = (unittest_custom_options_pb2.
+                          TestMessageWithCustomOptions.DESCRIPTOR)
+    message_proto = descriptor_pb2.DescriptorProto()
+    message_descriptor.CopyToProto(message_proto)
+    self.assertEqual(len(message_proto.options.ListFields()),
+                     2)
+
   def testDifferentCustomOptionTypes(self):
     kint32min = -2**31
     kint64min = -2**63
diff --git a/python/google/protobuf/internal/enum_type_wrapper.py b/python/google/protobuf/internal/enum_type_wrapper.py
index 1cffe35..77e4be0 100644
--- a/python/google/protobuf/internal/enum_type_wrapper.py
+++ b/python/google/protobuf/internal/enum_type_wrapper.py
@@ -46,7 +46,7 @@
   def __init__(self, enum_type):
     """Inits EnumTypeWrapper with an EnumDescriptor."""
     self._enum_type = enum_type
-    self.DESCRIPTOR = enum_type;
+    self.DESCRIPTOR = enum_type
 
   def Name(self, number):
     """Returns a string containing the name of an enum value."""
@@ -56,7 +56,7 @@
         self._enum_type.name, number))
 
   def Value(self, name):
-    """Returns the value coresponding to the given enum name."""
+    """Returns the value corresponding to the given enum name."""
     if name in self._enum_type.values_by_name:
       return self._enum_type.values_by_name[name].number
     raise ValueError('Enum %s has no value defined for name %s' % (
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index bd85ce8..db34c93 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -523,7 +523,8 @@
             '}'))
     parsed_message = json_format_proto3_pb2.TestStruct()
     self.CheckParseBack(message, parsed_message)
-    parsed_message.value['empty_struct']  # check for regression; this used to raise
+    # check for regression; this used to raise
+    parsed_message.value['empty_struct']
     parsed_message.value['empty_list']
 
   def testValueMessage(self):
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index d733dc8..137420d 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -159,15 +159,6 @@
       with self.assertRaises(message.DecodeError) as context:
         msg.FromString(end_tag)
       self.assertEqual('Unexpected end-group tag.', str(context.exception))
-    else:
-      with warnings.catch_warnings(record=True) as w:
-        # Cause all warnings to always be triggered.
-        warnings.simplefilter('always')
-        msg.FromString(end_tag)
-        assert len(w) == 1
-        assert issubclass(w[-1].category, RuntimeWarning)
-        self.assertEqual('Unexpected end-group tag: Not all data was converted',
-                         str(w[-1].message))
 
   def testDeterminismParameters(self, message_module):
     # This message is always deterministically serialized, even if determinism
@@ -1791,6 +1782,13 @@
     old_map_value = msg2.map_int32_foreign_message[222]
 
     msg2.MergeFrom(msg)
+    # Compare with expected message instead of call
+    # msg2.map_int32_foreign_message[222] to make sure MergeFrom does not
+    # sync with repeated field and there is no duplicated keys.
+    expected_msg = map_unittest_pb2.TestMap()
+    expected_msg.CopyFrom(msg)
+    expected_msg.map_int64_int64[88] = 99
+    self.assertEqual(msg2, expected_msg)
 
     self.assertEqual(34, msg2.map_int32_int32[12])
     self.assertEqual(78, msg2.map_int32_int32[56])
@@ -1854,9 +1852,13 @@
     self.assertEqual(99, msg2.map_int64_int64[88])
 
     msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message)
-    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
-    self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
-    self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
+    # Compare with expected message instead of call
+    # msg.map_int32_foreign_message[222] to make sure MergeFrom does not
+    # sync with repeated field and no duplicated keys.
+    expected_msg = map_unittest_pb2.TestMap()
+    expected_msg.CopyFrom(msg)
+    expected_msg.map_int64_int64[88] = 99
+    self.assertEqual(msg2, expected_msg)
 
     # Test when cpp extension cache a map.
     m1 = map_unittest_pb2.TestMap()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 4e0f545..f77c44b 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -294,7 +294,7 @@
 
 
 def _IsMessageMapField(field):
-  value_type = field.message_type.fields_by_name["value"]
+  value_type = field.message_type.fields_by_name['value']
   return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
 
 
@@ -311,12 +311,12 @@
                  wire_format.IsTypePackable(field_descriptor.type))
   if not is_packable:
     is_packed = False
-  elif field_descriptor.containing_type.syntax == "proto2":
+  elif field_descriptor.containing_type.syntax == 'proto2':
     is_packed = (field_descriptor.has_options and
                 field_descriptor.GetOptions().packed)
   else:
     has_packed_false = (field_descriptor.has_options and
-                        field_descriptor.GetOptions().HasField("packed") and
+                        field_descriptor.GetOptions().HasField('packed') and
                         field_descriptor.GetOptions().packed == False)
     is_packed = not has_packed_false
   is_map_entry = _IsMapField(field_descriptor)
@@ -529,7 +529,7 @@
     for field_name, field_value in kwargs.items():
       field = _GetFieldByName(message_descriptor, field_name)
       if field is None:
-        raise TypeError("%s() got an unexpected keyword argument '%s'" %
+        raise TypeError('%s() got an unexpected keyword argument "%s"' %
                         (message_descriptor.name, field_name))
       if field_value is None:
         # field=None is the same as no field at all.
@@ -619,7 +619,7 @@
   # handle specially here.
   assert _FieldDescriptor.MAX_CPPTYPE == 10
 
-  constant_name = field.name.upper() + "_FIELD_NUMBER"
+  constant_name = field.name.upper() + '_FIELD_NUMBER'
   setattr(cls, constant_name, field.number)
 
   if field.label == _FieldDescriptor.LABEL_REPEATED:
@@ -698,7 +698,7 @@
   type_checker = type_checkers.GetTypeChecker(field)
   default_value = field.default_value
   valid_values = set()
-  is_proto3 = field.containing_type.syntax == "proto3"
+  is_proto3 = field.containing_type.syntax == 'proto3'
 
   def getter(self):
     # TODO(protobuf-team): This may be broken since there may not be
@@ -786,7 +786,7 @@
   """Adds properties for all fields in this protocol message type."""
   extension_dict = descriptor.extensions_by_name
   for extension_name, extension_field in extension_dict.items():
-    constant_name = extension_name.upper() + "_FIELD_NUMBER"
+    constant_name = extension_name.upper() + '_FIELD_NUMBER'
     setattr(cls, constant_name, extension_field.number)
 
   # TODO(amauryfa): Migrate all users of these attributes to functions like
@@ -835,14 +835,15 @@
 
   cls.ListFields = ListFields
 
-_Proto3HasError = 'Protocol message has no non-repeated submessage field "%s"'
-_Proto2HasError = 'Protocol message has no non-repeated field "%s"'
+_PROTO3_ERROR_TEMPLATE = \
+  'Protocol message %s has no non-repeated submessage field "%s"'
+_PROTO2_ERROR_TEMPLATE = 'Protocol message %s has no non-repeated field "%s"'
 
 def _AddHasFieldMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
 
   is_proto3 = (message_descriptor.syntax == "proto3")
-  error_msg = _Proto3HasError if is_proto3 else _Proto2HasError
+  error_msg = _PROTO3_ERROR_TEMPLATE if is_proto3 else _PROTO2_ERROR_TEMPLATE
 
   hassable_fields = {}
   for field in message_descriptor.fields:
@@ -863,7 +864,7 @@
     try:
       field = hassable_fields[field_name]
     except KeyError:
-      raise ValueError(error_msg % field_name)
+      raise ValueError(error_msg % (message_descriptor.full_name, field_name))
 
     if isinstance(field, descriptor_mod.OneofDescriptor):
       try:
@@ -893,7 +894,7 @@
         else:
           return
       except KeyError:
-        raise ValueError('Protocol message %s() has no "%s" field.' %
+        raise ValueError('Protocol message %s has no "%s" field.' %
                          (message_descriptor.name, field_name))
 
     if field in self._fields:
@@ -1278,7 +1279,7 @@
     for field, value in self.ListFields():
       if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
         if field.is_extension:
-          name = "(%s)" % field.full_name
+          name = '(%s)' % field.full_name
         else:
           name = field.name
 
@@ -1286,7 +1287,7 @@
           if _IsMessageMapField(field):
             for key in value:
               element = value[key]
-              prefix = "%s[%s]." % (name, key)
+              prefix = '%s[%s].' % (name, key)
               sub_errors = element.FindInitializationErrors()
               errors += [prefix + error for error in sub_errors]
           else:
@@ -1295,11 +1296,11 @@
         elif field.label == _FieldDescriptor.LABEL_REPEATED:
           for i in range(len(value)):
             element = value[i]
-            prefix = "%s[%d]." % (name, i)
+            prefix = '%s[%d].' % (name, i)
             sub_errors = element.FindInitializationErrors()
             errors += [prefix + error for error in sub_errors]
         else:
-          prefix = name + "."
+          prefix = name + '.'
           sub_errors = value.FindInitializationErrors()
           errors += [prefix + error for error in sub_errors]
 
@@ -1315,7 +1316,7 @@
   def MergeFrom(self, msg):
     if not isinstance(msg, cls):
       raise TypeError(
-          "Parameter to MergeFrom() must be instance of same class: "
+          'Parameter to MergeFrom() must be instance of same class: '
           'expected %s got %s.' % (cls.__name__, msg.__class__.__name__))
 
     assert msg is not self
@@ -1611,8 +1612,8 @@
     other_fields = other._extended_message.ListFields()
 
     # Get rid of non-extension fields.
-    my_fields    = [ field for field in my_fields    if field.is_extension ]
-    other_fields = [ field for field in other_fields if field.is_extension ]
+    my_fields = [field for field in my_fields if field.is_extension]
+    other_fields = [field for field in other_fields if field.is_extension]
 
     return my_fields == other_fields
 
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index ccf8ac1..3580677 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -50,9 +50,11 @@
 from google.protobuf import any_pb2
 from google.protobuf import any_test_pb2
 from google.protobuf import map_unittest_pb2
+from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
+from google.protobuf import descriptor_pb2
 from google.protobuf.internal import any_test_pb2 as test_extend_any
 from google.protobuf.internal import message_set_extensions_pb2
 from google.protobuf.internal import test_util
@@ -175,7 +177,10 @@
         'repeated_nested_message {\n  bb: 32\n}\n'
         'repeated_foreign_enum: [FOREIGN_FOO, FOREIGN_BAR, FOREIGN_BAZ]\n')
     if as_one_line:
-      expected_ascii = expected_ascii.replace('\n ', '').replace('\n', '')
+      expected_ascii = expected_ascii.replace('\n', ' ')
+      expected_ascii = re.sub(r'\s+', ' ', expected_ascii)
+      expected_ascii = re.sub(r'\s$', '', expected_ascii)
+
     actual_ascii = text_format.MessageToString(
         message, use_short_repeated_primitives=True,
         as_one_line=as_one_line)
@@ -184,7 +189,7 @@
     text_format.Parse(actual_ascii, parsed_message)
     self.assertEqual(parsed_message, message)
 
-  def tesPrintShortFormatRepeatedFields(self, message_module, as_one_line):
+  def testPrintShortFormatRepeatedFields(self, message_module):
     self.VerifyPrintShortFormatRepeatedFields(message_module, False)
     self.VerifyPrintShortFormatRepeatedFields(message_module, True)
 
@@ -358,6 +363,63 @@
     self.assertEqual('0.0', out.getvalue())
     out.close()
 
+  def testCustomOptions(self, message_module):
+    message_descriptor = (unittest_custom_options_pb2.
+                          TestMessageWithCustomOptions.DESCRIPTOR)
+    message_proto = descriptor_pb2.DescriptorProto()
+    message_descriptor.CopyToProto(message_proto)
+    expected_text = (
+        'name: "TestMessageWithCustomOptions"\n'
+        'field {\n'
+        '  name: "field1"\n'
+        '  number: 1\n'
+        '  label: LABEL_OPTIONAL\n'
+        '  type: TYPE_STRING\n'
+        '  options {\n'
+        '    ctype: CORD\n'
+        '    [protobuf_unittest.field_opt1]: 8765432109\n'
+        '  }\n'
+        '}\n'
+        'field {\n'
+        '  name: "oneof_field"\n'
+        '  number: 2\n'
+        '  label: LABEL_OPTIONAL\n'
+        '  type: TYPE_INT32\n'
+        '  oneof_index: 0\n'
+        '}\n'
+        'enum_type {\n'
+        '  name: "AnEnum"\n'
+        '  value {\n'
+        '    name: "ANENUM_VAL1"\n'
+        '    number: 1\n'
+        '  }\n'
+        '  value {\n'
+        '    name: "ANENUM_VAL2"\n'
+        '    number: 2\n'
+        '    options {\n'
+        '      [protobuf_unittest.enum_value_opt1]: 123\n'
+        '    }\n'
+        '  }\n'
+        '  options {\n'
+        '    [protobuf_unittest.enum_opt1]: -789\n'
+        '  }\n'
+        '}\n'
+        'options {\n'
+        '  message_set_wire_format: false\n'
+        '  [protobuf_unittest.message_opt1]: -56\n'
+        '}\n'
+        'oneof_decl {\n'
+        '  name: "AnOneof"\n'
+        '  options {\n'
+        '    [protobuf_unittest.oneof_opt1]: -99\n'
+        '  }\n'
+        '}\n')
+    self.assertEqual(expected_text,
+                     text_format.MessageToString(message_proto))
+    parsed_proto = descriptor_pb2.DescriptorProto()
+    text_format.Parse(expected_text, parsed_proto)
+    self.assertEqual(message_proto, parsed_proto)
+
 
 @_parameterized.parameters(unittest_pb2, unittest_proto3_arena_pb2)
 class TextFormatMessageToTextBytesTests(TextFormatBase):
@@ -1907,6 +1969,30 @@
          'repeated_nested_message { My lucky number is 42 } '
          'repeated_nested_message { My lucky number is 99 }'))
 
+    out = text_format.TextWriter(False)
+    text_format.PrintField(
+        message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+            'optional_nested_message'],
+        message.optional_nested_message,
+        out,
+        message_formatter=printer)
+    self.assertEqual(
+        'optional_nested_message {\n  My lucky number is 1\n}\n',
+        out.getvalue())
+    out.close()
+
+    out = text_format.TextWriter(False)
+    text_format.PrintFieldValue(
+        message_module.TestAllTypes.DESCRIPTOR.fields_by_name[
+            'optional_nested_message'],
+        message.optional_nested_message,
+        out,
+        message_formatter=printer)
+    self.assertEqual(
+        '{\n  My lucky number is 1\n}',
+        out.getvalue())
+    out.close()
+
 
 class WhitespaceTest(TextFormatBase):
 
diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py
index 95c5615..92df148 100644
--- a/python/google/protobuf/internal/well_known_types.py
+++ b/python/google/protobuf/internal/well_known_types.py
@@ -669,11 +669,7 @@
         destination.ClearField(_StrConvert(name))
       repeated_source = getattr(source, name)
       repeated_destination = getattr(destination, name)
-      if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
-        for item in repeated_source:
-          repeated_destination.add().MergeFrom(item)
-      else:
-        repeated_destination.extend(repeated_source)
+      repeated_destination.MergeFrom(repeated_source)
     else:
       if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE:
         if replace_message:
diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py
index 4dc2ae4..bf304b6 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -47,6 +47,7 @@
 from google.protobuf import field_mask_pb2
 from google.protobuf import struct_pb2
 from google.protobuf import timestamp_pb2
+from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf.internal import any_test_pb2
 from google.protobuf.internal import test_util
@@ -526,7 +527,7 @@
     out_mask.Intersect(mask1, mask2)
     self.assertEqual('foo.bar.baz', out_mask.ToJsonString())
 
-  def testMergeMessage(self):
+  def testMergeMessageWithoutMapFields(self):
     # Test merge one field.
     src = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(src)
@@ -635,6 +636,29 @@
     self.assertTrue(dst.HasField('foo_message'))
     self.assertFalse(dst.HasField('foo_lazy_message'))
 
+  def testMergeMessageWithMapField(self):
+    empty_map = map_unittest_pb2.TestRecursiveMapMessage()
+    src_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+    src_level_2.a['src level 2'].CopyFrom(empty_map)
+    src = map_unittest_pb2.TestRecursiveMapMessage()
+    src.a['common key'].CopyFrom(src_level_2)
+    src.a['src level 1'].CopyFrom(src_level_2)
+
+    dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage()
+    dst_level_2.a['dst level 2'].CopyFrom(empty_map)
+    dst = map_unittest_pb2.TestRecursiveMapMessage()
+    dst.a['common key'].CopyFrom(dst_level_2)
+    dst.a['dst level 1'].CopyFrom(empty_map)
+
+    mask = field_mask_pb2.FieldMask()
+    mask.FromJsonString('a')
+    mask.MergeMessage(src, dst)
+
+    # map from dst is replaced with map from src.
+    self.assertEqual(dst.a['common key'], src_level_2)
+    self.assertEqual(dst.a['src level 1'], src_level_2)
+    self.assertEqual(dst.a['dst level 1'], empty_map)
+
   def testMergeErrors(self):
     src = unittest_pb2.TestAllTypes()
     dst = unittest_pb2.TestAllTypes()
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 3cb16b7..d5813d8 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -189,6 +189,21 @@
   return descriptor->service()->file();
 }
 
+bool Reparse(
+    PyMessageFactory* message_factory, const Message& from, Message* to) {
+  // Reparse message.
+  string serialized;
+  from.SerializeToString(&serialized);
+  io::CodedInputStream input(
+      reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
+  input.SetExtensionRegistry(message_factory->pool->pool,
+                             message_factory->message_factory);
+  bool success = to->ParseFromCodedStream(&input);
+  if (!success) {
+    return false;
+  }
+  return true;
+}
 // Converts options into a Python protobuf, and cache the result.
 //
 // This is a bit tricky because options can contain extension fields defined in
@@ -251,15 +266,8 @@
     cmsg->message->CopyFrom(options);
   } else {
     // Reparse options string!  XXX call cmessage::MergeFromString
-    string serialized;
-    options.SerializeToString(&serialized);
-    io::CodedInputStream input(
-        reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
-    input.SetExtensionRegistry(message_factory->pool->pool,
-                               message_factory->message_factory);
-    bool success = cmsg->message->MergePartialFromCodedStream(&input);
-    if (!success) {
-      PyErr_Format(PyExc_ValueError, "Error parsing Options message");
+    if (!Reparse(message_factory, options, cmsg->message)) {
+      PyErr_Format(PyExc_ValueError, "Error reparsing Options message");
       return NULL;
     }
   }
@@ -290,6 +298,16 @@
   DescriptorProtoClass* descriptor_message =
       static_cast<DescriptorProtoClass*>(message->message);
   descriptor->CopyTo(descriptor_message);
+  // Custom options might in unknown extensions. Reparse
+  // the descriptor_message. Can't skip reparse when options unknown
+  // fields is empty, because they might in sub descriptors' options.
+  PyMessageFactory* message_factory =
+      GetDefaultDescriptorPool()->py_message_factory;
+  if (!Reparse(message_factory, *descriptor_message, descriptor_message)) {
+    PyErr_Format(PyExc_ValueError, "Error reparsing descriptor message");
+    return nullptr;
+  }
+
   Py_RETURN_NONE;
 }
 
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 77c6170..9f74e2a 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -62,6 +62,7 @@
   static Py_ssize_t Length(PyObject* _self);
   static PyObject* GetIterator(PyObject *_self);
   static PyObject* IterNext(PyObject* _self);
+  static PyObject* MergeFrom(PyObject* _self, PyObject* arg);
 
   // Methods that differ between the map types.
   static PyObject* ScalarMapGetItem(PyObject* _self, PyObject* key);
@@ -338,20 +339,19 @@
   return reinterpret_cast<PyObject*>(message_class);
 }
 
-PyObject* MergeFrom(PyObject* _self, PyObject* arg) {
+PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
   MapContainer* self = GetMap(_self);
   MapContainer* other_map = GetMap(arg);
   Message* message = self->GetMutableMessage();
   const Message* other_message = other_map->message;
   const Reflection* reflection = message->GetReflection();
   const Reflection* other_reflection = other_message->GetReflection();
-  int count = other_reflection->FieldSize(
-      *other_message, other_map->parent_field_descriptor);
-  for (int i = 0 ; i < count; i ++) {
-    reflection->AddMessage(message, self->parent_field_descriptor)->MergeFrom(
-        other_reflection->GetRepeatedMessage(
-            *other_message, other_map->parent_field_descriptor, i));
-  }
+  internal::MapFieldBase* field = reflection->MapData(
+      message, self->parent_field_descriptor);
+  internal::MapFieldBase* other_field =
+      other_reflection->MapData(const_cast<Message*>(other_message),
+                                self->parent_field_descriptor);
+  field->MergeFrom(*other_field);
   self->version++;
   Py_RETURN_NONE;
 }
@@ -589,7 +589,7 @@
     "Gets the value for the given key if present, or otherwise a default" },
   { "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
     "Return the class used to build Entries of (key, value) pairs." },
-  { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
+  { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
     "Merges a map into the current map." },
   /*
   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
@@ -908,7 +908,7 @@
     "Alias for getitem, useful to make explicit that the map is mutated." },
   { "GetEntryClass", (PyCFunction)GetEntryClass, METH_NOARGS,
     "Return the class used to build Entries of (key, value) pairs." },
-  { "MergeFrom", (PyCFunction)MergeFrom, METH_O,
+  { "MergeFrom", (PyCFunction)MapReflectionFriend::MergeFrom, METH_O,
     "Merges a map into the current map." },
   /*
   { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index fecb936..44df9fb 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -585,10 +585,6 @@
 // Returns -1 on error and 0 on success.
 template<class Visitor>
 int ForEachCompositeField(CMessage* self, Visitor visitor) {
-  Py_ssize_t pos = 0;
-  PyObject* key;
-  PyObject* field;
-
   // Visit normal fields.
   if (self->composite_fields) {
     for (CMessage::CompositeFieldsMap::iterator it =
@@ -1554,10 +1550,11 @@
 }
 
 bool CheckHasPresence(const FieldDescriptor* field_descriptor, bool in_oneof) {
+  auto message_name = field_descriptor->containing_type()->name();
   if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     PyErr_Format(PyExc_ValueError,
-                 "Protocol message has no singular \"%s\" field.",
-                 field_descriptor->name().c_str());
+                 "Protocol message %s has no singular \"%s\" field.",
+                 message_name.c_str(), field_descriptor->name().c_str());
     return false;
   }
 
@@ -1565,8 +1562,8 @@
     // HasField() for a oneof *itself* isn't supported.
     if (in_oneof) {
       PyErr_Format(PyExc_ValueError,
-                   "Can't test oneof field \"%s\" for presence in proto3, use "
-                   "WhichOneof instead.",
+                   "Can't test oneof field \"%s.%s\" for presence in proto3, "
+                   "use WhichOneof instead.", message_name.c_str(),
                    field_descriptor->containing_oneof()->name().c_str());
       return false;
     }
@@ -1579,8 +1576,8 @@
     if (field_descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
       PyErr_Format(
           PyExc_ValueError,
-          "Can't test non-submessage field \"%s\" for presence in proto3.",
-          field_descriptor->name().c_str());
+          "Can't test non-submessage field \"%s.%s\" for presence in proto3.",
+          message_name.c_str(), field_descriptor->name().c_str());
       return false;
     }
   }
@@ -1608,7 +1605,8 @@
       FindFieldWithOneofs(message, string(field_name, size), &is_in_oneof);
   if (field_descriptor == NULL) {
     if (!is_in_oneof) {
-      PyErr_Format(PyExc_ValueError, "Unknown field %s.", field_name);
+      PyErr_Format(PyExc_ValueError, "Protocol message %s has no field %s.",
+                   message->GetDescriptor()->name().c_str(), field_name);
       return NULL;
     } else {
       Py_RETURN_FALSE;
@@ -2140,6 +2138,7 @@
       reinterpret_cast<const uint8*>(data), data_length);
   if (allow_oversize_protos) {
     input.SetTotalBytesLimit(INT_MAX, INT_MAX);
+    input.SetRecursionLimit(INT_MAX);
   }
   PyMessageFactory* factory = GetFactoryForMessage(self);
   input.SetExtensionRegistry(factory->pool->pool, factory->message_factory);
@@ -2822,8 +2821,6 @@
     }
   }
 
-  const Descriptor* message_descriptor =
-      (reinterpret_cast<CMessageClass*>(Py_TYPE(self)))->message_descriptor;
   if (self->message->GetDescriptor() != field_descriptor->containing_type()) {
     PyErr_Format(PyExc_TypeError,
                  "descriptor to field '%s' doesn't apply to '%s' object",
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 998cd68..f7053c6 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -225,7 +225,8 @@
   """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)
+                     use_index_order, float_format,
+                     message_formatter=message_formatter)
   printer.PrintField(field, value)
 
 
@@ -243,7 +244,8 @@
   """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)
+                     use_index_order, float_format,
+                     message_formatter=message_formatter)
   printer.PrintFieldValue(field, value)
 
 
@@ -427,8 +429,8 @@
   def _PrintShortRepeatedPrimitivesValue(self, field, value):
     # Note: this is called only when value has at least one element.
     self._PrintFieldName(field)
-    self.out.write('[')
-    for i in xrange(len(value) - 1):
+    self.out.write(' [')
+    for i in six.moves.range(len(value) - 1):
       self.PrintFieldValue(field, value[i])
       self.out.write(', ')
     self.PrintFieldValue(field, value[-1])
diff --git a/src/Makefile.am b/src/Makefile.am
index fc0df47..76250d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,7 +74,6 @@
   google/protobuf/stubs/once.h                                   \
   google/protobuf/stubs/platform_macros.h                        \
   google/protobuf/stubs/port.h                                   \
-  google/protobuf/stubs/singleton.h                              \
   google/protobuf/stubs/status.h                                 \
   google/protobuf/stubs/stl_util.h                               \
   google/protobuf/stubs/stringpiece.h                            \
@@ -92,6 +91,7 @@
   google/protobuf/dynamic_message.h                              \
   google/protobuf/empty.pb.h                                     \
   google/protobuf/extension_set.h                                \
+  google/protobuf/extension_set_inl.h                            \
   google/protobuf/field_mask.pb.h                                \
   google/protobuf/generated_enum_reflection.h                    \
   google/protobuf/generated_enum_util.h                          \
@@ -112,6 +112,7 @@
   google/protobuf/message_lite.h                                 \
   google/protobuf/metadata.h                                     \
   google/protobuf/metadata_lite.h                                \
+  google/protobuf/parse_context.h                                \
   google/protobuf/port.h                                         \
   google/protobuf/port_def.inc                                   \
   google/protobuf/port_undef.inc                                 \
@@ -314,7 +315,6 @@
   google/protobuf/compiler/command_line_interface.cc           \
   google/protobuf/compiler/plugin.cc                           \
   google/protobuf/compiler/plugin.pb.cc                        \
-  google/protobuf/compiler/scc.cc                              \
   google/protobuf/compiler/scc.h                               \
   google/protobuf/compiler/subprocess.cc                       \
   google/protobuf/compiler/subprocess.h                        \
@@ -528,7 +528,6 @@
 
 EXTRA_DIST =                                                   \
   $(protoc_inputs)                                             \
-  $(js_well_known_types_sources)                               \
   solaris/libstdc++.la                                         \
   google/protobuf/test_messages_proto3.proto                   \
   google/protobuf/test_messages_proto2.proto                   \
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index a45f658..156ac47 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -69,15 +69,17 @@
   file_level_metadata_google_2fprotobuf_2fany_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fany_2eproto, file_level_service_descriptors_google_2fprotobuf_2fany_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fany_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fany_2eproto[] =
   "\n\031google/protobuf/any.proto\022\017google.prot"
   "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002"
   " \001(\014Bo\n\023com.google.protobufB\010AnyProtoP\001Z"
   "%github.com/golang/protobuf/ptypes/any\242\002"
   "\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006p"
   "roto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fany_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fany_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fany_2eproto,
   "google/protobuf/any.proto", &assign_descriptors_table_google_2fprotobuf_2fany_2eproto, 205,
 };
 
@@ -195,10 +197,10 @@
   auto msg = static_cast<Any*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -208,14 +210,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Any.type_url");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_type_url();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_type_url();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // bytes value = 2;
@@ -223,25 +228,29 @@
         if (static_cast<::google::protobuf::uint8>(tag) != 18) goto handle_unusual;
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::internal::StringParser;
-        ::std::string* str = msg->mutable_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        str->append(ptr, size);
+        auto str = msg->mutable_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
         ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -252,7 +261,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index c931d50..57b7df8 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -134,7 +134,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Any& from);
   void MergeFrom(const Any& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 1734dfd..7ecd8ef 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -144,8 +144,7 @@
   file_level_metadata_google_2fprotobuf_2fapi_2eproto, 3, file_level_enum_descriptors_google_2fprotobuf_2fapi_2eproto, file_level_service_descriptors_google_2fprotobuf_2fapi_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fapi_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto[] =
   "\n\031google/protobuf/api.proto\022\017google.prot"
   "obuf\032$google/protobuf/source_context.pro"
   "to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014"
@@ -165,7 +164,10 @@
   "otobufB\010ApiProtoP\001Z+google.golang.org/ge"
   "nproto/protobuf/api;api\242\002\003GPB\252\002\036Google.P"
   "rotobuf.WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fapi_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fapi_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fapi_2eproto,
   "google/protobuf/api.proto", &assign_descriptors_table_google_2fprotobuf_2fapi_2eproto, 750,
 };
 
@@ -301,10 +303,10 @@
   auto msg = static_cast<Api*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -314,14 +316,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Api.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.Method methods = 2;
@@ -366,14 +371,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Api.version");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_version();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_version();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // .google.protobuf.SourceContext source_context = 5;
@@ -422,13 +430,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -439,7 +447,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -971,10 +979,10 @@
   auto msg = static_cast<Method*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -984,14 +992,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Method.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // string request_type_url = 2;
@@ -1000,14 +1011,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Method.request_type_url");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_request_type_url();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_request_type_url();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // bool request_streaming = 3;
@@ -1026,14 +1040,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Method.response_type_url");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_response_type_url();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_response_type_url();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // bool response_streaming = 5;
@@ -1077,13 +1094,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1094,7 +1111,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1596,10 +1613,10 @@
   auto msg = static_cast<Mixin*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1609,14 +1626,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // string root = 2;
@@ -1625,26 +1645,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Mixin.root");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_root();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_root();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1655,7 +1678,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index 40a609b..baa725f 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -128,7 +128,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Api& from);
   void MergeFrom(const Api& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -318,7 +318,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Method& from);
   void MergeFrom(const Method& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -501,7 +501,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Mixin& from);
   void MergeFrom(const Mixin& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 26c291c..eb3a1dd 100644
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -33,6 +33,7 @@
 #include <algorithm>
 #include <limits>
 
+#include <google/protobuf/stubs/mutex.h>
 
 #ifdef ADDRESS_SANITIZER
 #include <sanitizer/asan_interface.h>
@@ -323,24 +324,22 @@
 }
 
 void ArenaImpl::SerialArena::CleanupListFallback() {
-  // Cleanup newest chunk: ptrs give us length.
+  // The first chunk might be only partially full, so calculate its size
+  // from cleanup_ptr_. Subsequent chunks are always full, so use list->size.
   size_t n = cleanup_ptr_ - &cleanup_->nodes[0];
-  CleanupNode* node = cleanup_ptr_;
-  for (size_t i = 0; i < n; i++) {
-    --node;
-    node->cleanup(node->elem);
-  }
-
-  // Cleanup older chunks, which are known to be full.
-  CleanupChunk* list = cleanup_->next;
-  while (list) {
-    size_t n = list->size;
-    CleanupNode* node = &list->nodes[list->size];
-    for (size_t i = 0; i < n; i++) {
-      --node;
-      node->cleanup(node->elem);
+  CleanupChunk* list = cleanup_;
+  while (true) {
+    CleanupNode* node = &list->nodes[0];
+    // Cleanup newest elements first (allocated last).
+    for (size_t i = n; i > 0; i--) {
+      node[i - 1].cleanup(node[i - 1].elem);
     }
     list = list->next;
+    if (list == nullptr) {
+      break;
+    }
+    // All but the first chunk are always full.
+    n = list->size;
   }
 }
 
diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h
index cab3d86..4ba5954 100644
--- a/src/google/protobuf/arena_impl.h
+++ b/src/google/protobuf/arena_impl.h
@@ -306,8 +306,10 @@
  public:
   // kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
   // to protect the invariant that pos is always at a multiple of 8.
-  static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & static_cast<size_t>(-8);
-  static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
+  static const size_t kBlockHeaderSize =
+      (sizeof(Block) + 7) & static_cast<size_t>(-8);
+  static const size_t kSerialArenaSize =
+      (sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
   static_assert(kBlockHeaderSize % 8 == 0,
                 "kBlockHeaderSize must be a multiple of 8.");
   static_assert(kSerialArenaSize % 8 == 0,
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 361b83e..a942cff 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -55,7 +55,7 @@
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <gtest/gtest.h>
-
+#include <google/protobuf/stubs/strutil.h>
 
 
 using proto2_arena_unittest::ArenaMessage;
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 4d1ef09..5da9176 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -834,35 +834,51 @@
   }
 
   std::vector<const FileDescriptor*> parsed_files;
-  // null unless descriptor_set_in_names_.empty()
   std::unique_ptr<DiskSourceTree> disk_source_tree;
   std::unique_ptr<ErrorPrinter> error_collector;
   std::unique_ptr<DescriptorPool> descriptor_pool;
-  std::unique_ptr<DescriptorDatabase> descriptor_database;
-  if (descriptor_set_in_names_.empty()) {
-    disk_source_tree.reset(new DiskSourceTree());
-    if (!InitializeDiskSourceTree(disk_source_tree.get())) {
+  std::unique_ptr<SimpleDescriptorDatabase> descriptor_set_in_database;
+  std::unique_ptr<SourceTreeDescriptorDatabase> source_tree_database;
+
+  // Any --descriptor_set_in FileDescriptorSet objects will be used as a
+  // fallback to input_files on command line, so create that db first.
+  if (!descriptor_set_in_names_.empty()) {
+    descriptor_set_in_database.reset(new SimpleDescriptorDatabase());
+    if (!PopulateSimpleDescriptorDatabase(descriptor_set_in_database.get())) {
       return 1;
     }
+  }
+
+  if (proto_path_.empty()) {
+    // If there are no --proto_path flags, then just look in the specified
+    // --descriptor_set_in files.  But first, verify that the input files are
+    // there.
+    if (!VerifyInputFilesInDescriptors(descriptor_set_in_database.get())) {
+      return 1;
+    }
+
+    error_collector.reset(new ErrorPrinter(error_format_));
+    descriptor_pool.reset(new DescriptorPool(descriptor_set_in_database.get(),
+                                             error_collector.get()));
+  } else {
+    disk_source_tree.reset(new DiskSourceTree());
+    if (!InitializeDiskSourceTree(disk_source_tree.get(),
+                                  descriptor_set_in_database.get())) {
+      return 1;
+    }
+
     error_collector.reset(
         new ErrorPrinter(error_format_, disk_source_tree.get()));
 
-    SourceTreeDescriptorDatabase* database =
-        new SourceTreeDescriptorDatabase(disk_source_tree.get());
-    database->RecordErrorsTo(error_collector.get());
-    descriptor_database.reset(database);
-    descriptor_pool.reset(new DescriptorPool(
-        descriptor_database.get(), database->GetValidationErrorCollector()));
-  } else {
-    error_collector.reset(new ErrorPrinter(error_format_));
+    source_tree_database.reset(new SourceTreeDescriptorDatabase(
+        disk_source_tree.get(), descriptor_set_in_database.get()));
+    source_tree_database->RecordErrorsTo(error_collector.get());
 
-    SimpleDescriptorDatabase* database = new SimpleDescriptorDatabase();
-    descriptor_database.reset(database);
-    if (!PopulateSimpleDescriptorDatabase(database)) {
-      return 1;
-    }
-    descriptor_pool.reset(new DescriptorPool(database, error_collector.get()));
+    descriptor_pool.reset(new DescriptorPool(
+        source_tree_database.get(),
+        source_tree_database->GetValidationErrorCollector()));
   }
+
   descriptor_pool->EnforceWeakDependencies(true);
   if (!ParseInputFiles(descriptor_pool.get(), &parsed_files)) {
     return 1;
@@ -980,7 +996,7 @@
 }
 
 bool CommandLineInterface::InitializeDiskSourceTree(
-    DiskSourceTree* source_tree) {
+    DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
   AddDefaultProtoPaths(&proto_path_);
 
   // Set up the source tree.
@@ -989,7 +1005,7 @@
   }
 
   // Map input files to virtual paths if possible.
-  if (!MakeInputsBeProtoPathRelative(source_tree)) {
+  if (!MakeInputsBeProtoPathRelative(source_tree, fallback_database)) {
     return false;
   }
 
@@ -1039,6 +1055,27 @@
   return true;
 }
 
+bool CommandLineInterface::VerifyInputFilesInDescriptors(
+    DescriptorDatabase* database) {
+  for (const auto& input_file : input_files_) {
+    FileDescriptorProto file_descriptor;
+    if (!database->FindFileByName(input_file, &file_descriptor)) {
+      std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
+      return false;
+    }
+
+    // Enforce --disallow_services.
+    if (disallow_services_ && file_descriptor.service_size() > 0) {
+      std::cerr << file_descriptor.name()
+                << ": This file contains services, but "
+                   "--disallow_services was used."
+                << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
 bool CommandLineInterface::ParseInputFiles(
     DescriptorPool* descriptor_pool,
     std::vector<const FileDescriptor*>* parsed_files) {
@@ -1051,9 +1088,6 @@
         descriptor_pool->FindFileByName(input_file);
     descriptor_pool->ClearUnusedImportTrackFiles();
     if (parsed_file == NULL) {
-      if (!descriptor_set_in_names_.empty()) {
-        std::cerr << input_file << ": " << strerror(ENOENT) << std::endl;
-      }
       return false;
     }
     parsed_files->push_back(parsed_file);
@@ -1111,18 +1145,27 @@
 }
 
 bool CommandLineInterface::MakeProtoProtoPathRelative(
-    DiskSourceTree* source_tree, string* proto) {
+    DiskSourceTree* source_tree, string* proto,
+    DescriptorDatabase* fallback_database) {
+  // If it's in the fallback db, don't report non-existent file errors.
+  FileDescriptorProto fallback_file;
+  bool in_fallback_database =
+      fallback_database != nullptr &&
+      fallback_database->FindFileByName(*proto, &fallback_file);
+
   // If the input file path is not a physical file path, it must be a virtual
   // path.
   if (access(proto->c_str(), F_OK) < 0) {
     string disk_file;
-    if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) {
+    if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+        in_fallback_database) {
       return true;
     } else {
       std::cerr << *proto << ": " << strerror(ENOENT) << std::endl;
       return false;
     }
   }
+
   string virtual_file, shadowing_disk_file;
   switch (source_tree->DiskFileToVirtualFile(
       *proto, &virtual_file, &shadowing_disk_file)) {
@@ -1138,13 +1181,17 @@
                    "comes first." << std::endl;
       return false;
     case DiskSourceTree::CANNOT_OPEN:
+      if (in_fallback_database) {
+        return true;
+      }
       std::cerr << *proto << ": " << strerror(errno) << std::endl;
       return false;
     case DiskSourceTree::NO_MAPPING: {
       // Try to interpret the path as a virtual path.
       string disk_file;
-      if (source_tree->VirtualFileToDiskFile(*proto, &disk_file)) {
-       return true;
+      if (source_tree->VirtualFileToDiskFile(*proto, &disk_file) ||
+          in_fallback_database) {
+        return true;
       } else {
         // The input file path can't be mapped to any --proto_path and it also
         // can't be interpreted as a virtual path.
@@ -1166,9 +1213,10 @@
 }
 
 bool CommandLineInterface::MakeInputsBeProtoPathRelative(
-    DiskSourceTree* source_tree) {
+    DiskSourceTree* source_tree, DescriptorDatabase* fallback_database) {
   for (auto& input_file : input_files_) {
-    if (!MakeProtoProtoPathRelative(source_tree, &input_file)) {
+    if (!MakeProtoProtoPathRelative(source_tree, &input_file,
+                                    fallback_database)) {
       return false;
     }
   }
@@ -1270,15 +1318,16 @@
     return PARSE_ARGUMENT_FAIL;
   }
 
-  // If no --proto_path was given, use the current working directory.
-  if (proto_path_.empty()) {
+  // The --proto_path & --descriptor_set_in flags both specify places to look
+  // for proto files. If neither were given, use the current working directory.
+  if (proto_path_.empty() && descriptor_set_in_names_.empty()) {
     // Don't use make_pair as the old/default standard library on Solaris
     // doesn't support it without explicit template parameters, which are
     // incompatible with C++0x's make_pair.
     proto_path_.push_back(std::pair<string, string>("", "."));
   }
 
-  // Check some errror cases.
+  // Check some error cases.
   bool decoding_raw = (mode_ == MODE_DECODE) && codec_type_.empty();
   if (decoding_raw && !input_files_.empty()) {
     std::cerr << "When using --decode_raw, no input files should be given."
@@ -1395,13 +1444,6 @@
     input_files_.push_back(value);
 
   } else if (name == "-I" || name == "--proto_path") {
-    if (!descriptor_set_in_names_.empty()) {
-      std::cerr << "Only one of " << name
-                << " and --descriptor_set_in can be specified."
-                << std::endl;
-      return PARSE_ARGUMENT_FAIL;
-    }
-
     // Java's -classpath (and some other languages) delimits path components
     // with colons.  Let's accept that syntax too just to make things more
     // intuitive.
@@ -1477,12 +1519,6 @@
       std::cerr << name << " requires a non-empty value." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
-    if (!proto_path_.empty()) {
-      std::cerr << "Only one of " << name
-                << " and --proto_path can be specified."
-                << std::endl;
-      return PARSE_ARGUMENT_FAIL;
-    }
     if (!dependency_out_name_.empty()) {
       std::cerr << name << " cannot be used with --dependency_out."
                 << std::endl;
@@ -1698,13 +1734,18 @@
 
 void CommandLineInterface::PrintHelpText() {
   // Sorry for indentation here; line wrapping would be uglier.
-  std::cout <<
-"Usage: " << executable_name_ << " [OPTION] PROTO_FILES\n"
+  std::cout
+      <<
+      "Usage: " << executable_name_
+      << " [OPTION] PROTO_FILES\n"
 "Parse PROTO_FILES and generate output based on the options given:\n"
 "  -IPATH, --proto_path=PATH   Specify the directory in which to search for\n"
 "                              imports.  May be specified multiple times;\n"
 "                              directories will be searched in order.  If not\n"
 "                              given, the current working directory is used.\n"
+"                              If not found in any of the these directories,\n"
+"                              the --descriptor_set_in descriptors will be\n"
+"                              checked for required proto file.\n"
 "  --version                   Show version info and exit.\n"
 "  -h, --help                  Show this text and exit.\n"
 "  --encode=MESSAGE_TYPE       Read a text-format message of the given type\n"
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index cef29ff..48455e6 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -53,6 +53,7 @@
 namespace protobuf {
 
 class Descriptor;            // descriptor.h
+class DescriptorDatabase;    // descriptor_database.h
 class DescriptorPool;        // descriptor.h
 class FileDescriptor;        // descriptor.h
 class FileDescriptorSet;     // descriptor.h
@@ -214,14 +215,15 @@
   // Clear state from previous Run().
   void Clear();
 
-  // Remaps the proto file so that it is relative to one of the ddirectories
+  // Remaps the proto file so that it is relative to one of the directories
   // in proto_path_.  Returns false if an error occurred.
-  bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto);
+  bool MakeProtoProtoPathRelative(DiskSourceTree* source_tree, std::string* proto,
+                                  DescriptorDatabase* fallback_database);
 
   // Remaps each file in input_files_ so that it is relative to one of the
   // directories in proto_path_.  Returns false if an error occurred.
-  bool MakeInputsBeProtoPathRelative(
-    DiskSourceTree* source_tree);
+  bool MakeInputsBeProtoPathRelative(DiskSourceTree* source_tree,
+                                     DescriptorDatabase* fallback_database);
 
 
   // Return status for ParseArguments() and InterpretArgument().
@@ -259,7 +261,11 @@
   void PrintHelpText();
 
   // Loads proto_path_ into the provided source_tree.
-  bool InitializeDiskSourceTree(DiskSourceTree* source_tree);
+  bool InitializeDiskSourceTree(DiskSourceTree* source_tree,
+                                DescriptorDatabase* fallback_database);
+
+  // Verify that all the input files exist in the given database.
+  bool VerifyInputFilesInDescriptors(DescriptorDatabase* fallback_database);
 
   // Loads descriptor_set_in into the provided database
   bool PopulateSimpleDescriptorDatabase(SimpleDescriptorDatabase* database);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 4e6f4af..4dc4725 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -299,7 +299,6 @@
 void CommandLineInterfaceTest::RunWithArgs(std::vector<string> args) {
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
-#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
     string plugin_path;
 #ifdef GOOGLE_PROTOBUF_TEST_PLUGIN_PATH
     plugin_path = GOOGLE_PROTOBUF_TEST_PLUGIN_PATH;
@@ -330,11 +329,6 @@
 #endif
 
     if (plugin_path.empty()) {
-#else
-    string plugin_path = "third_party/protobuf/test_plugin";
-
-    if (access(plugin_path.c_str(), F_OK) != 0) {
-#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
       GOOGLE_LOG(ERROR)
           << "Plugin executable not found.  Plugin tests are likely to fail.";
     } else {
@@ -1761,13 +1755,49 @@
 TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn) {
   Run("protocol_compiler --test_out=$tmpdir "
       "--proto_path=$tmpdir --descriptor_set_in=$tmpdir/foo.bin foo.proto");
-  ExpectErrorText(
-      "Only one of --descriptor_set_in and --proto_path can be specified.\n");
+  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
 
   Run("protocol_compiler --test_out=$tmpdir "
       "--descriptor_set_in=$tmpdir/foo.bin --proto_path=$tmpdir foo.proto");
-  ExpectErrorText(
-      "Only one of --proto_path and --descriptor_set_in can be specified.\n");
+  ExpectErrorText("$tmpdir/foo.bin: No such file or directory\n");
+}
+
+TEST_F(CommandLineInterfaceTest, ProtoPathAndDescriptorSetIn_CompileFiles) {
+  // Test what happens if a proto is in a --descriptor_set_in and also exists
+  // on disk.
+  FileDescriptorSet file_descriptor_set;
+
+  // NOTE: This file desc SHOULD be different from the one created as a temp
+  //       to make it easier to test that the file was output instead of the
+  //       contents of the --descriptor_set_in file.
+  FileDescriptorProto* file_descriptor_proto = file_descriptor_set.add_file();
+  file_descriptor_proto->set_name("foo.proto");
+  file_descriptor_proto->add_message_type()->set_name("Foo");
+
+  WriteDescriptorSet("foo.bin", &file_descriptor_set);
+
+  CreateTempFile("foo.proto",
+                 "syntax = \"proto2\";\n"
+                 "message FooBar { required string foo_message = 1; }\n");
+
+  Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set "
+      "--descriptor_set_in=$tmpdir/foo.bin "
+      "--include_source_info "
+      "--proto_path=$tmpdir foo.proto");
+
+  ExpectNoErrors();
+
+  FileDescriptorSet descriptor_set;
+  ReadDescriptorSet("descriptor_set", &descriptor_set);
+
+  EXPECT_EQ(1, descriptor_set.file_size());
+  EXPECT_EQ("foo.proto", descriptor_set.file(0).name());
+  // Descriptor set SHOULD have source code info.
+  EXPECT_TRUE(descriptor_set.file(0).has_source_code_info());
+
+  EXPECT_EQ("FooBar", descriptor_set.file(0).message_type(0).name());
+  EXPECT_EQ("foo_message",
+            descriptor_set.file(0).message_type(0).field(0).name());
 }
 
 TEST_F(CommandLineInterfaceTest, ProtoPathAndDependencyOut) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index a19ad59..0797fc2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -161,6 +161,10 @@
     EXPECT_EQ("", error_collector.text_);
     CppGenerator generator;
     MockGeneratorContext context;
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+    generator.set_opensource_runtime(true);
+    generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
+#endif
     string error;
     ASSERT_TRUE(generator.Generate(file, file_parameter[1], &context, &error));
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 1e80715..214449a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -256,8 +256,6 @@
 
   GenerateHeader(printer);
 
-  IncludeFile("net/proto2/public/port_undef.inc", printer);
-
   GenerateBottomHeaderGuard(printer, filename_identifier);
 }
 
@@ -320,13 +318,11 @@
     path = StringReplace(path, "internal/", "", false);
     path = StringReplace(path, "proto/", "", false);
     path = StringReplace(path, "public/", "", false);
-    if (options_.opensource_include_paths) {
+    if (options_.runtime_include_base.empty()) {
       format("#include <google/protobuf/$1$>", path);
     } else {
-      format(
-          "#include "
-          "\"third_party/protobuf/testing/extracted/src/google/protobuf/$1$\"",
-          path);
+      format("#include \"$1$google/protobuf/$2$\"",
+             options_.runtime_include_base, path);
     }
   } else {
     format("#include \"$1$\"", google3_name);
@@ -346,10 +342,10 @@
 
   if (options_.opensource_runtime) {
     if (IsWellKnownMessage(file)) {
-      if (options_.opensource_include_paths) {
+      if (options_.runtime_include_base.empty()) {
         use_system_include = true;
       } else {
-        name = "third_party/protobuf/testing/extracted/src/" + basename;
+        name = options_.runtime_include_base + basename;
       }
     }
   }
@@ -809,36 +805,56 @@
       "\n",
       message_generators_.size());
 
-  // Now generate the AddDescriptors() function.
-  format(
-      "::$proto_ns$::internal::DescriptorTable $1$ = {\n"
-      "  false, $init_defaults$, \n",
-      UniqueName("descriptor_table", file_, options_));
-  format.Indent();
-
   // Embed the descriptor.  We simply serialize the entire
-  // FileDescriptorProto
-  // and embed it as a string literal, which is parsed and built into real
-  // descriptors at initialization time.
+  // FileDescriptorProto/ and embed it as a string literal, which is parsed and
+  // built into real descriptors at initialization time.
+  const string protodef_name =
+      UniqueName("descriptor_table_protodef", file_, options_);
+  format( "const char $1$[] =\n", protodef_name);
+  format.Indent();
   FileDescriptorProto file_proto;
   file_->CopyTo(&file_proto);
   string file_data;
   file_proto.SerializeToString(&file_data);
 
   {
-    // Only write 40 bytes per line.
-    static const int kBytesPerLine = 40;
-    for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
-      format(
-          "\"$1$\"\n",
-          EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+    if (file_data.size() > 65535) {
+      // Workaround for MSVC: "Error C1091: compiler limit: string exceeds
+      // 65535 bytes in length". Declare a static array of chars rather than
+      // use a string literal. Only write 25 bytes per line.
+      static const int kBytesPerLine = 25;
+      format("{ ");
+      for (int i = 0; i < file_data.size();) {
+        for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
+          format("'$1$', ", CEscape(file_data.substr(i, 1)));
+        }
+        format("\n");
+      }
+      format("'\\0' }");  // null-terminate
+    } else {
+      // Only write 40 bytes per line.
+      static const int kBytesPerLine = 40;
+      for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
+        format(
+            "\"$1$\"\n",
+            EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
+      }
     }
+    format(";\n");
   }
-
   format.Outdent();
+
+  // Now generate the AddDescriptors() function.
+  format(
+      "::$proto_ns$::internal::DescriptorTable $1$ = {\n"
+      "  false, $init_defaults$, \n"
+      "  $2$,\n",
+      UniqueName("descriptor_table", file_, options_),
+      protodef_name);
+
   const int num_deps = file_->dependency_count();
   format(
-      ",\n  \"$filename$\", &$assign_desc_table$, $1$,\n"
+      "  \"$filename$\", &$assign_desc_table$, $1$,\n"
       "};\n\n"
       "void $add_descriptors$() {\n"
       "  static constexpr ::$proto_ns$::internal::InitFunc deps[$2$] =\n"
@@ -1277,7 +1293,7 @@
     IncludeFile("net/proto2/public/unknown_field_set.h", printer);
   }
 
-  if (IsAnyMessage(file_)) {
+  if (IsAnyMessage(file_, options_)) {
     IncludeFile("net/proto2/internal/any.h", printer);
   }
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 0e7e4df..e4fecd3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -78,19 +78,8 @@
   //
   Options file_options;
 
-  switch (runtime_) {
-    case Runtime::kGoogle3:
-      file_options.opensource_runtime = false;
-      break;
-    case Runtime::kOpensource:
-      file_options.opensource_runtime = true;
-      file_options.opensource_include_paths = true;
-      break;
-    case Runtime::kOpensourceGoogle3:
-      file_options.opensource_runtime = true;
-      file_options.opensource_include_paths = false;
-      break;
-  }
+  file_options.opensource_runtime = opensource_runtime_;
+  file_options.runtime_include_base = runtime_include_base_;
 
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "dllexport_decl") {
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
index 30363e7..469af9c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -66,8 +66,17 @@
     kOpensourceGoogle3
   };
 
-  void set_runtime(Runtime runtime) {
-    runtime_ = runtime;
+  void set_opensource_runtime(bool opensource) {
+    opensource_runtime_ = opensource;
+  }
+
+  // If set to a non-empty string, generated code will do:
+  //   #include "<BASE>/google/protobuf/message.h"
+  // instead of:
+  //   #include <google/protobuf/message.h>
+  // This has no effect if opensource_runtime = false.
+  void set_runtime_include_base(const std::string& base) {
+    runtime_include_base_ = base;
   }
 
   // implements CodeGenerator ----------------------------------------
@@ -77,7 +86,8 @@
                 std::string* error) const;
 
  private:
-  Runtime runtime_ = Runtime::kOpensource;
+  bool opensource_runtime_ = true;
+  std::string runtime_include_base_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 472c55f..a1cceec 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -789,13 +789,17 @@
   }
 }
 
-bool IsAnyMessage(const FileDescriptor* descriptor) {
-  return descriptor->name() == kAnyProtoFile;
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
+  // For now we do not support Any in lite mode, so if we're building for lite
+  // then we just treat Any as if it's an ordinary message with no special
+  // behavior.
+  return descriptor->name() == kAnyProtoFile &&
+         GetOptimizeFor(descriptor, options) != FileOptions::LITE_RUNTIME;
 }
 
-bool IsAnyMessage(const Descriptor* descriptor) {
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
   return descriptor->name() == kAnyMessageName &&
-         descriptor->file()->name() == kAnyProtoFile;
+         IsAnyMessage(descriptor->file(), options);
 }
 
 bool IsWellKnownMessage(const FileDescriptor* descriptor) {
@@ -1170,6 +1174,52 @@
           wiretype != internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
 }
 
+void GenerateStrings(const FieldDescriptor* field, const Options& options,
+                     const Formatter& format, bool check_utf8) {
+  string utf8;
+  if (check_utf8) {
+    utf8 = GetUtf8Suffix(field, options);
+    if (!utf8.empty()) {
+      string name = "nullptr";
+      if (HasDescriptorMethods(field->file(), options)) {
+        name = "\"" + field->full_name() + "\"";
+      }
+      format("ctx->extra_parse_data().SetFieldName($1$);\n", name);
+    }
+  }
+  format(
+      "auto str = msg->$1$_$2$();\n"
+      "if (size > end - ptr + "
+      "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n"
+      "  object = str;\n",
+      field->is_repeated() && !field->is_packable() ? "add" : "mutable",
+      FieldName(field));
+  string name;
+  if (field->options().ctype() == FieldOptions::STRING ||
+      (IsProto1(field->file(), options) &&
+       field->options().ctype() == FieldOptions::STRING_PIECE)) {
+    name = "GreedyStringParser";
+    format("  str->clear();\n");
+    // TODO(gerbens) evaluate security
+    format("  str->reserve(size);\n");
+  } else if (field->options().ctype() == FieldOptions::CORD) {
+    name = "CordParser";
+    format("  str->Clear();\n");
+  } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
+    name = "StringPieceParser";
+    format("  str->Clear();\n");
+  }
+  format(
+      "  parser_till_end = ::$proto_ns$::internal::$1$$2$;\n"
+      "  goto len_delim_till_end;\n"
+      "}\n"
+      "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$("
+      "ptr, size, ctx));\n"
+      "::$proto_ns$::internal::Inline$1$(str, ptr, size, ctx);\n"
+      "ptr += size;\n",
+      name, utf8);
+}
+
 void GenerateLengthDelim(
                       const FieldDescriptor* field, const Options& options,
                       MessageSCCAnalyzer* scc_analyzer,
@@ -1212,72 +1262,13 @@
         field_type = FieldDescriptor::TYPE_BYTES;
       }
     }
-    string utf8 = "";
     switch (field_type) {
       case FieldDescriptor::TYPE_STRING:
-        utf8 = GetUtf8Suffix(field, options);
-        if (!utf8.empty()) {
-          string name = "nullptr";
-          if (HasDescriptorMethods(field->file(), options)) {
-            name = "\"" + field->full_name() + "\"";
-          }
-          format("ctx->extra_parse_data().SetFieldName($1$);\n", name);
-        }
-        PROTOBUF_FALLTHROUGH_INTENDED;
-      case FieldDescriptor::TYPE_BYTES: {
-        if (field->options().ctype() == FieldOptions::STRING ||
-            (IsProto1(field->file(), options) &&
-             field->options().ctype() == FieldOptions::STRING_PIECE)) {
-          format(
-              "parser_till_end = ::$proto_ns$::internal::StringParser$1$;\n"
-              "$string$* str = msg->$2$_$3$();\n"
-              "str->clear();\n",
-              utf8,
-              field->is_repeated() && !field->is_map() &&
-                      !field->is_packable()
-                  ? "add"
-                  : "mutable",
-              FieldName(field));
-          if (utf8.empty()) {
-            // special case if there is no utf8 verification.
-            format(
-                "object = str;\n"
-                "if (size > end - ptr) goto len_delim_till_end;\n"
-                "str->append(ptr, size);\n"
-                "ptr += size;\n");
-            return;
-          }
-        } else if (field->options().ctype() == FieldOptions::CORD) {
-          string cord_parser = "CordParser" + utf8;
-          format(
-              "parser_till_end = ::$proto_ns$::internal::$1$;\n"
-              "auto* str = msg->$2$_$3$();\n"
-              "str->Clear();\n",
-              cord_parser,
-              field->is_repeated() && !field->is_map() ? "add" : "mutable",
-              FieldName(field));
-        } else if (field->options().ctype() == FieldOptions::STRING_PIECE) {
-          format(
-              "parser_till_end = "
-              "::$proto_ns$::internal::StringPieceParser$1$;\n"
-              "::$proto_ns$::internal::StringPieceField* str = "
-              "msg->$2$_$3$();\n"
-              "str->Clear();\n",
-              utf8,
-              field->is_repeated() && !field->is_map() ? "add" : "mutable",
-              FieldName(field));
-        }
-        format(
-            "object = str;\n"
-            "if (size > end - ptr) goto len_delim_till_end;\n"
-            "auto newend = ptr + size;\n"
-            "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n");
-        if (!utf8.empty()) {
-          // If utf8 verification is on this can fail.
-          format("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
-        }
+        GenerateStrings(field, options, format, true /* utf8 */);
         break;
-      }
+      case FieldDescriptor::TYPE_BYTES:
+        GenerateStrings(field, options, format, false /* utf8 */);
+        break;
       case FieldDescriptor::TYPE_MESSAGE: {
         GOOGLE_CHECK(field->message_type());
         if (!IsProto1(field->file(), options) && field->is_map()) {
@@ -1306,6 +1297,36 @@
               QualifiedClassName(field->message_type()), FieldName(field));
           break;
         }
+        if (!IsProto1(field->file(), options) && IsLazy(field, options)) {
+          if (field->containing_oneof() != nullptr) {
+            format(
+                "if (!msg->has_$1$()) {\n"
+                "  msg->clear_$1$();\n"
+                "  msg->$2$_.$1$_ = ::google::protobuf::Arena::CreateMessage<\n"
+                "      ::google::protobuf::internal::LazyField>(msg->GetArenaNoVirtual());\n"
+                "  msg->set_has_$1$();\n"
+                "}\n"
+                "auto parse_closure = msg->$2$_.$1$_->_ParseClosure();\n",
+                FieldName(field), field->containing_oneof()->name());
+          } else if (HasFieldPresence(field->file())) {
+            format(
+                "HasBitSetters::set_has_$1$(msg);\n"
+                "auto parse_closure = msg->$1$_._ParseClosure();\n",
+                FieldName(field));
+          } else {
+            format(
+                "auto parse_closure = msg->$1$_._ParseClosure();\n",
+                FieldName(field));
+          }
+          format(
+              "parser_till_end = parse_closure.func;\n"
+              "object = parse_closure.object;\n"
+              "if (size > end - ptr) goto len_delim_till_end;\n"
+              "auto newend = ptr + size;\n"
+              "GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->ParseExactRange(parse_closure, ptr, newend));\n"
+              "ptr = newend;\n");
+          break;
+        }
         if (IsImplicitWeakField(field, options, scc_analyzer)) {
           if (!field->is_repeated()) {
             format("object = HasBitSetters::mutable_$1$(msg);\n",
@@ -1428,11 +1449,12 @@
       format(
           "parser_till_end = $1$::_InternalParse;\n"
           "object = msg->$2$_$3$();\n"
-          "bool ok = ctx->PrepareGroup(tag, &depth);\n"
-          "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
-          "ptr = parser_till_end(ptr, end, object, ctx);\n"
+          "auto res = ctx->ParseGroup(tag, {parser_till_end, object}, ptr, "
+          "end, "
+          "&depth);\n"
+          "ptr = res.first;\n"
           "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
-          "if (ctx->GroupContinues(depth)) goto group_continues;\n",
+          "if (res.second) goto group_continues;\n",
           QualifiedClassName(field->message_type()),
           field->is_repeated() ? "add" : "mutable", FieldName(field));
       break;
@@ -1542,11 +1564,11 @@
       "  auto msg = static_cast<$classname$*>(object);\n"
       "  $uint32$ size; (void)size;\n"
       "  int depth; (void)depth;\n"
+      "  $uint32$ tag;\n"
       "  ::$proto_ns$::internal::ParseFunc parser_till_end; "
       "(void)parser_till_end;\n"
       "  auto ptr = begin;\n"
       "  while (ptr < end) {\n"
-      "    $uint32$ tag;\n"
       "    ptr = Varint::Parse32Inline(ptr, &tag);\n"
       "    $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
       "    switch (tag >> 3) {\n");
@@ -1583,8 +1605,7 @@
       "default: {\n"
       "handle_unusual: (void)&&handle_unusual;\n"
       "  if ((tag & 7) == 4 || tag == 0) {\n"
-      "    bool ok = ctx->ValidEndGroup(tag);\n"
-      "    $GOOGLE_PROTOBUF$_PARSER_ASSERT(ok);\n"
+      "    ctx->EndGroup(tag);\n"
       "    return ptr;\n"
       "  }\n");
   if (IsMapEntryMessage(descriptor)) {
@@ -1617,6 +1638,7 @@
           "      internal_default_instance(), &msg->_internal_metadata_, "
           "ctx);\n"
           "  ptr = res.first;\n"
+          "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
           "  if (res.second) return ptr;\n"
           "  continue;\n"
           "}\n");
@@ -1626,6 +1648,7 @@
         "    ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), "
         "ctx);\n"
         "  ptr = res.first;\n"
+        "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
         "  if (res.second) return ptr;\n"
         "}\n");  // default case
   }
@@ -1643,8 +1666,8 @@
       "  $DCHK$(ptr >= end);\n"
       // Group crossed end and must be continued. Either this a parse failure
       // or we need to resume on the next chunk and thus save the state.
-      "  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, "
-      "depth);\n"
+      "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg},"
+      " {parser_till_end, object}, depth, tag));\n"
       "  return ptr;\n"
       "}\n");
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index b8431ae..bde2230 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -35,6 +35,7 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
 
+#include <algorithm>
 #include <iterator>
 #include <map>
 #include <string>
@@ -411,8 +412,8 @@
          "_";
 }
 
-bool IsAnyMessage(const FileDescriptor* descriptor);
-bool IsAnyMessage(const Descriptor* descriptor);
+bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
+bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
 
 bool IsWellKnownMessage(const FileDescriptor* descriptor);
 
@@ -471,7 +472,18 @@
   }
 
  private:
-  SCCAnalyzer analyzer_;
+  struct DepsGenerator {
+    std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
+      std::vector<const Descriptor*> deps;
+      for (int i = 0; i < desc->field_count(); i++) {
+        if (desc->field(i)->message_type()) {
+          deps.push_back(desc->field(i)->message_type());
+        }
+      }
+      return deps;
+    }
+  };
+  SCCAnalyzer<DepsGenerator> analyzer_;
   Options options_;
   std::map<const SCC*, MessageAnalysis> analysis_cache_;
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 4af5403..f9d87ed 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -1085,7 +1085,7 @@
     format("void UnsafeArenaSwap($classname$* other);\n");
   }
 
-  if (IsAnyMessage(descriptor_)) {
+  if (IsAnyMessage(descriptor_, options_)) {
     format(
         "// implements Any -----------------------------------------------\n"
         "\n"
@@ -1152,7 +1152,7 @@
     format(
         "void CopyFrom(const $classname$& from);\n"
         "void MergeFrom(const $classname$& from);\n"
-        "void Clear()$ clear_final$;\n"
+        "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear()$ clear_final$;\n"
         "bool IsInitialized() const$ is_initialized_final$;\n"
         "\n"
         "size_t ByteSizeLong() const final;\n"
@@ -1430,7 +1430,7 @@
     format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n");
   }
   // Generate _any_metadata_ for the Any type.
-  if (IsAnyMessage(descriptor_)) {
+  if (IsAnyMessage(descriptor_, options_)) {
     format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n");
   }
 
@@ -1931,7 +1931,7 @@
   format.Outdent();
   format("}\n");
 
-  if (IsAnyMessage(descriptor_)) {
+  if (IsAnyMessage(descriptor_, options_)) {
     format(
         "void $classname$::PackFrom(const ::$proto_ns$::Message& message) {\n"
         "  _any_metadata_.PackFrom(message);\n"
@@ -2240,7 +2240,7 @@
             default_val = field->default_value_string().empty()
                               ? "&::" + variables_["proto_ns"] +
                                     "::internal::fixed_address_empty_string"
-                              : "&" + Namespace(field) + " ::" + classname_ +
+                              : "&" + QualifiedClassName(descriptor_) +
                                     "::" + MakeDefaultName(field);
             break;
           case FieldOptions::CORD:
@@ -2548,7 +2548,7 @@
     }
   }
 
-  if (IsAnyMessage(descriptor_)) {
+  if (IsAnyMessage(descriptor_, options_)) {
     initializer_with_arena += ",\n  _any_metadata_(&type_url_, &value_)";
   }
   if (num_weak_fields_ > 0) {
@@ -2556,7 +2556,7 @@
   }
 
   string initializer_null = superclass + "(), _internal_metadata_(NULL)";
-  if (IsAnyMessage(descriptor_)) {
+  if (IsAnyMessage(descriptor_, options_)) {
     initializer_null += ", _any_metadata_(&type_url_, &value_)";
   }
   if (num_weak_fields_ > 0) {
@@ -2620,7 +2620,7 @@
       format(",\n$1$_(from.$1$_)", FieldName(field));
     }
 
-    if (IsAnyMessage(descriptor_)) {
+    if (IsAnyMessage(descriptor_, options_)) {
       format(",\n_any_metadata_(&type_url_, &value_)");
     }
     if (num_weak_fields_ > 0) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 84c1862..fc90bd7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -55,7 +55,7 @@
   bool lite_implicit_weak_fields = false;
   bool bootstrap = false;
   bool opensource_runtime = false;
-  bool opensource_include_paths = false;
+  std::string runtime_include_base;
   int num_cc_files = 0;
   std::string annotation_pragma_name;
   std::string annotation_guard_name;
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index ecfabe6..af4f880 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -59,7 +59,7 @@
       descriptor->default_value_string().empty()
           ? "&::" + (*variables)["proto_ns"] +
                 "::internal::GetEmptyStringAlreadyInited()"
-          : "&" + Namespace(descriptor) + "::" + (*variables)["classname"] +
+          : "&" + QualifiedClassName(descriptor->containing_type()) +
                 "::" + default_variable_string + ".get()";
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
@@ -92,7 +92,7 @@
       inlined_(false) {
 
   // TODO(ckennelly): Handle inlining for any.proto.
-  if (IsAnyMessage(descriptor_->containing_type())) {
+  if (IsAnyMessage(descriptor_->containing_type(), options_)) {
     inlined_ = false;
   }
   if (descriptor_->containing_type()->options().map_entry()) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
index 898b1fb..0323e4e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.inc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc
@@ -50,7 +50,7 @@
 #include <vector>
 
 #include <google/protobuf/unittest_no_arena.pb.h>
-
+#include <google/protobuf/stubs/strutil.h>
 #if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER)
 // We exclude this large proto from cmake build because it's too large for
 // visual studio to compile (report internal errors).
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 58498aa..9ea544d 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -120,10 +120,19 @@
 
 SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
     SourceTree* source_tree)
-  : source_tree_(source_tree),
-    error_collector_(NULL),
-    using_validation_error_collector_(false),
-    validation_error_collector_(this) {}
+    : source_tree_(source_tree),
+      fallback_database_(nullptr),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
+
+SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
+    SourceTree* source_tree, DescriptorDatabase* fallback_database)
+    : source_tree_(source_tree),
+      fallback_database_(fallback_database),
+      error_collector_(nullptr),
+      using_validation_error_collector_(false),
+      validation_error_collector_(this) {}
 
 SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
 
@@ -131,6 +140,10 @@
     const string& filename, FileDescriptorProto* output) {
   std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
   if (input == NULL) {
+    if (fallback_database_ != nullptr &&
+        fallback_database_->FindFileByName(filename, output)) {
+      return true;
+    }
     if (error_collector_ != NULL) {
       error_collector_->AddError(filename, -1, 0,
                                  source_tree_->GetLastErrorMessage());
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index cf6b012..cdd05ed 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -78,6 +78,11 @@
 class PROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
  public:
   SourceTreeDescriptorDatabase(SourceTree* source_tree);
+
+  // If non-NULL, fallback_database will be checked if a file doesn't exist in
+  // the specified source_tree.
+  SourceTreeDescriptorDatabase(SourceTree* source_tree,
+                               DescriptorDatabase* fallback_database);
   ~SourceTreeDescriptorDatabase();
 
   // Instructs the SourceTreeDescriptorDatabase to report any parse errors
@@ -110,6 +115,7 @@
   class SingleFileErrorCollector;
 
   SourceTree* source_tree_;
+  DescriptorDatabase* fallback_database_;
   MultiFileErrorCollector* error_collector_;
 
   class PROTOBUF_EXPORT ValidationErrorCollector
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index c98c8b3..a170a91 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -56,14 +56,6 @@
 
 namespace {
 
-bool EnableJavaPrimitiveExperiment() {
-#ifdef PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
-  return PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT;
-#else   // PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
-  return false;
-#endif  // !PROTOBUF_JAVA_PRIMITIVE_EXPERIMENT
-}
-
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
                            int messageBitIndex,
                            int builderBitIndex,
@@ -77,12 +69,11 @@
   (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
   (*variables)["field_type"] = (*variables)["type"];
 
-  if (EnableJavaPrimitiveExperiment() &&
-      (javaType == JAVATYPE_BOOLEAN ||
-       javaType == JAVATYPE_DOUBLE ||
-       javaType == JAVATYPE_FLOAT ||
-       javaType == JAVATYPE_INT ||
-       javaType == JAVATYPE_LONG)) {
+  if (javaType == JAVATYPE_BOOLEAN ||
+      javaType == JAVATYPE_DOUBLE ||
+      javaType == JAVATYPE_FLOAT ||
+      javaType == JAVATYPE_INT ||
+      javaType == JAVATYPE_LONG) {
     string capitalized_type = UnderscoresToCamelCase(
         PrimitiveTypeName(javaType), /*cap_first_letter=*/true);
     (*variables)["field_list_type"] =
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 5779d5e..7e547af 100644
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -43,6 +43,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/compiler/js/well_known_types_embed.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -154,6 +155,12 @@
   return StripSuffixString(filename, suffix);
 }
 
+string GetSnakeFilename(const string& filename) {
+  string snake_name = filename;
+  ReplaceCharacters(&snake_name, "/", '_');
+  return snake_name;
+}
+
 // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
 // file foo/bar/baz.js.
 string GetJSFilename(const GeneratorOptions& options, const string& filename) {
@@ -199,9 +206,9 @@
   return basename + "_pb";
 }
 
-// Returns the fully normalized JavaScript path for the given
+// Returns the fully normalized JavaScript namespace for the given
 // file descriptor's package.
-string GetFilePath(const GeneratorOptions& options,
+string GetNamespace(const GeneratorOptions& options,
                    const FileDescriptor* file) {
   if (!options.namespace_prefix.empty()) {
     return options.namespace_prefix;
@@ -234,7 +241,7 @@
 string GetPrefix(const GeneratorOptions& options,
                  const FileDescriptor* file_descriptor,
                  const Descriptor* containing_type) {
-  string prefix = GetFilePath(options, file_descriptor) +
+  string prefix = GetNamespace(options, file_descriptor) +
                   GetNestedMessageName(containing_type);
   if (!prefix.empty()) {
     prefix += ".";
@@ -246,9 +253,7 @@
 // message descriptor.
 string GetMessagePathPrefix(const GeneratorOptions& options,
                             const Descriptor* descriptor) {
-  return GetPrefix(
-      options, descriptor->file(),
-      descriptor->containing_type());
+  return GetPrefix(options, descriptor->file(), descriptor->containing_type());
 }
 
 // Returns the fully normalized JavaScript path for the given
@@ -261,9 +266,9 @@
 // Returns the fully normalized JavaScript path prefix for the given
 // enumeration descriptor.
 string GetEnumPathPrefix(const GeneratorOptions& options,
-                   const EnumDescriptor* enum_descriptor) {
+                         const EnumDescriptor* enum_descriptor) {
   return GetPrefix(options, enum_descriptor->file(),
-      enum_descriptor->containing_type());
+                   enum_descriptor->containing_type());
 }
 
 // Returns the fully normalized JavaScript path for the given
@@ -392,7 +397,7 @@
   return result;
 }
 
-string ToFileName(const string& input) {
+string ToLower(const string& input) {
   string result;
   result.reserve(input.size());
 
@@ -407,27 +412,77 @@
   return result;
 }
 
-// When we're generating one output file per type name, this is the filename
+// When we're generating one output file per SCC, this is the filename
 // that top-level extensions should go in.
+// e.g. one proto file (test.proto):
+// package a;
+// extends Foo {
+//   ...
+// }
+// If "with_filename" equals true, the extension filename will be
+// "proto.a_test_extensions.js", otherwise will be "proto.a.js"
 string GetExtensionFileName(const GeneratorOptions& options,
-                            const FileDescriptor* file) {
-  return options.output_dir + "/" + ToFileName(GetFilePath(options, file)) +
+                            const FileDescriptor* file, bool with_filename) {
+  string snake_name = StripProto(GetSnakeFilename(file->name()));
+  return options.output_dir + "/" + ToLower(GetNamespace(options, file)) +
+      (with_filename ? ("_" + snake_name + "_extensions") : "") +
+      options.GetFileNameExtension();
+}
+// When we're generating one output file per SCC, this is the filename
+// that all messages in the SCC should go in.
+// If with_package equals true, filename will have package prefix,
+// If the filename length is longer than 200, the filename will be the
+// SCC's proto filename with suffix "_long_sccs_(index)" (if with_package equals
+// true it still has package prefix)
+string GetMessagesFileName(
+    const GeneratorOptions& options, const SCC* scc, bool with_package) {
+  static std::map<const Descriptor*, string>* long_name_dict =
+      new std::map<const Descriptor*, string>();
+  string package_base =
+      with_package
+      ? ToLower(
+          GetNamespace(options, scc->GetRepresentative()->file()) + "_")
+      : "";
+  string filename_base = "";
+  std::vector<string> all_message_names;
+  for (auto one_desc : scc->descriptors) {
+    if (one_desc->containing_type() == nullptr) {
+      all_message_names.push_back(ToLower(one_desc->name()));
+    }
+  }
+  sort(all_message_names.begin(), all_message_names.end());
+  for (auto one_message : all_message_names) {
+    if (!filename_base.empty()) {
+      filename_base += "_";
+    }
+    filename_base += one_message;
+  }
+  if (filename_base.size() + package_base.size() > 200) {
+    if ((*long_name_dict).find(scc->GetRepresentative()) ==
+        (*long_name_dict).end()) {
+      string snake_name = StripProto(
+          GetSnakeFilename(scc->GetRepresentative()->file()->name()));
+      (*long_name_dict)[scc->GetRepresentative()] =
+          StrCat(snake_name, "_long_sccs_",
+              static_cast<uint64>((*long_name_dict).size()));
+    }
+    filename_base = (*long_name_dict)[scc->GetRepresentative()];
+  }
+  return options.output_dir + "/" + package_base + filename_base +
          options.GetFileNameExtension();
 }
 
 // When we're generating one output file per type name, this is the filename
-// that a top-level message should go in.
-string GetMessageFileName(const GeneratorOptions& options,
-                          const Descriptor* desc) {
-  return options.output_dir + "/" + ToFileName(desc->name()) +
-         options.GetFileNameExtension();
-}
-
-// When we're generating one output file per type name, this is the filename
-// that a top-level message should go in.
+// that a top-level enum should go in.
+// If with_package equals true, filename will have package prefix.
 string GetEnumFileName(const GeneratorOptions& options,
-                       const EnumDescriptor* desc) {
-  return options.output_dir + "/" + ToFileName(desc->name()) +
+                       const EnumDescriptor* desc,
+                       bool with_package) {
+  return options.output_dir + "/" +
+         (with_package
+              ? ToLower(GetNamespace(options, desc->file()) + "_")
+              : "") +
+         ToLower(desc->name()) +
          options.GetFileNameExtension();
 }
 
@@ -627,7 +682,7 @@
 // JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
 // Returns false if |out| was truncated because |in| contained invalid UTF-8 or
 // codepoints outside the BMP.
-// TODO(lukestebbing): Support codepoints outside the BMP.
+// TODO(b/115551870): Support codepoints outside the BMP.
 bool EscapeJSString(const string& in, string* out) {
   size_t decoded = 0;
   for (size_t i = 0; i < in.size(); i += decoded) {
@@ -659,7 +714,7 @@
       case '\r': *out += "\\r"; break;
       case '\\': *out += "\\\\"; break;
       default:
-        // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
+        // TODO(b/115551870): Once we're supporting codepoints outside the BMP,
         // use a single Unicode codepoint escape if the output language is
         // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
         // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
@@ -818,7 +873,7 @@
         string out;
         bool is_valid = EscapeJSString(field->default_value_string(), &out);
         if (!is_valid) {
-          // TODO(lukestebbing): Decide whether this should be a hard error.
+          // TODO(b/115551870): Decide whether this should be a hard error.
           GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
                        << " was truncated since it contained invalid UTF-8 or"
                           " codepoints outside the basic multilingual plane.";
@@ -1413,37 +1468,57 @@
 }
 
 // We use this to implement the semantics that same file can be generated
-// multiple times, but the last one wins.  We never actually write the files,
-// but we keep a set of which descriptors were the final one for a given
-// filename.
+// multiple times, but only the last one keep the short name. Others all use
+// long name with extra information to distinguish (For message and enum, the
+// extra information is package name, for file level extension, the extra
+// information is proto's filename).
+// We never actually write the files, but we keep a set of which descriptors
+// were the final one for a given filename.
 class FileDeduplicator {
  public:
   explicit FileDeduplicator(const GeneratorOptions& options)
       : error_on_conflict_(options.error_on_name_conflict) {}
 
-  bool AddFile(const string& filename, const void* desc, string* error) {
-    if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
+  // params:
+  //   filenames: a pair of {short filename, full filename}
+  //              (short filename don't have extra information, full filename
+  //               contains extra information)
+  //   desc: The Descriptor or SCC pointer or EnumDescriptor.
+  //   error: The returned error information.
+  bool AddFile(
+      const std::pair<string, string> filenames,
+      const void* desc, string* error) {
+    if (descs_by_shortname_.find(filenames.first) !=
+        descs_by_shortname_.end()) {
       if (error_on_conflict_) {
-        *error = "Name conflict: file name " + filename +
+        *error = "Name conflict: file name " + filenames.first +
                  " would be generated by two descriptors";
         return false;
       }
-      allowed_descs_.erase(descs_by_filename_[filename]);
+      // Change old pointer's actual name to full name.
+      auto short_name_desc = descs_by_shortname_[filenames.first];
+      allowed_descs_actual_name_[short_name_desc] =
+          allowed_descs_full_name_[short_name_desc];
     }
+    descs_by_shortname_[filenames.first] = desc;
+    allowed_descs_actual_name_[desc] = filenames.first;
+    allowed_descs_full_name_[desc] = filenames.second;
 
-    descs_by_filename_[filename] = desc;
-    allowed_descs_.insert(desc);
     return true;
   }
 
-  void GetAllowedSet(std::set<const void*>* allowed_set) {
-    *allowed_set = allowed_descs_;
+  void GetAllowedMap(std::map<const void*, string>* allowed_set) {
+    *allowed_set = allowed_descs_actual_name_;
   }
 
  private:
   bool error_on_conflict_;
-  std::map<string, const void*> descs_by_filename_;
-  std::set<const void*> allowed_descs_;
+  // The map that restores all the descs that are using short name as filename.
+  std::map<string, const void*> descs_by_shortname_;
+  // The final actual filename map.
+  std::map<const void*, string> allowed_descs_actual_name_;
+  // The full name map.
+  std::map<const void*, string> allowed_descs_full_name_;
 };
 
 void DepthFirstSearch(const FileDescriptor* file,
@@ -1504,25 +1579,61 @@
 // by choosing the last descriptor that writes each filename and permitting
 // only those to generate code.
 
-bool GenerateJspbAllowedSet(const GeneratorOptions& options,
+struct DepsGenerator {
+  std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
+    std::vector<const Descriptor*> deps;
+    auto maybe_add = [&](const Descriptor* d) {
+      if (d) deps.push_back(d);
+    };
+    for (int i = 0; i < desc->field_count(); i++) {
+      if (!IgnoreField(desc->field(i))) {
+        maybe_add(desc->field(i)->message_type());
+      }
+    }
+    for (int i = 0; i < desc->extension_count(); i++) {
+      maybe_add(desc->extension(i)->message_type());
+      maybe_add(desc->extension(i)->containing_type());
+    }
+    for (int i = 0; i < desc->nested_type_count(); i++) {
+      maybe_add(desc->nested_type(i));
+    }
+    maybe_add(desc->containing_type());
+
+    return deps;
+  }
+};
+
+bool GenerateJspbAllowedMap(const GeneratorOptions& options,
                             const std::vector<const FileDescriptor*>& files,
-                            std::set<const void*>* allowed_set,
+                            std::map<const void*, string>* allowed_set,
+                            SCCAnalyzer<DepsGenerator>* analyzer,
                             string* error) {
   std::vector<const FileDescriptor*> files_ordered;
   GenerateJspbFileOrder(files, &files_ordered);
 
   // Choose the last descriptor for each filename.
   FileDeduplicator dedup(options);
+  std::set<const SCC*> added;
   for (int i = 0; i < files_ordered.size(); i++) {
     for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
       const Descriptor* desc = files_ordered[i]->message_type(j);
-      if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
+      if (added.insert(analyzer->GetSCC(desc)).second && !dedup.AddFile(
+          std::make_pair(
+            GetMessagesFileName(options, analyzer->GetSCC(desc), false),
+            GetMessagesFileName(options, analyzer->GetSCC(desc), true)),
+          analyzer->GetSCC(desc),
+          error)) {
         return false;
       }
     }
     for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
       const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
-      if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
+      if (!dedup.AddFile(
+          std::make_pair(
+            GetEnumFileName(options, desc, false),
+            GetEnumFileName(options, desc, true)),
+          desc,
+          error)) {
         return false;
       }
     }
@@ -1537,14 +1648,17 @@
     }
 
     if (has_extension) {
-      if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
-                         files_ordered[i], error)) {
+      if (!dedup.AddFile(
+          std::make_pair(
+              GetExtensionFileName(options, files_ordered[i], false),
+              GetExtensionFileName(options, files_ordered[i], true)),
+          files_ordered[i], error)) {
         return false;
       }
     }
   }
 
-  dedup.GetAllowedSet(allowed_set);
+  dedup.GetAllowedMap(allowed_set);
 
   return true;
 }
@@ -1565,6 +1679,10 @@
   printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64);
 }
 
+bool IsWellKnownTypeFile(const FileDescriptor* file) {
+  return HasPrefixString(file->name(), "google/protobuf/");
+}
+
 }  // anonymous namespace
 
 void Generator::GenerateHeader(const GeneratorOptions& options,
@@ -1647,7 +1765,7 @@
       continue;
     }
 
-    string name = GetFilePath(options, field->file()) + "." +
+    string name = GetNamespace(options, field->file()) + "." +
                   JSObjectFieldName(options, field);
     provided->insert(name);
   }
@@ -1685,20 +1803,27 @@
   }
 }
 
-void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
-                                           io::Printer* printer,
-                                           const Descriptor* desc,
-                                           std::set<string>* provided) const {
+void Generator::GenerateRequiresForSCC(const GeneratorOptions& options,
+                                       io::Printer* printer, const SCC* scc,
+                                       std::set<string>* provided) const {
   std::set<string> required;
   std::set<string> forwards;
   bool have_message = false;
-  FindRequiresForMessage(options, desc,
-                         &required, &forwards, &have_message);
+  bool has_extension = false;
+  bool has_map = false;
+  for (auto desc : scc->descriptors) {
+    if (desc->containing_type() == nullptr) {
+      FindRequiresForMessage(options, desc, &required, &forwards,
+                             &have_message);
+      has_extension = (has_extension || HasExtensions(desc));
+      has_map = (has_map || HasMap(options, desc));
+    }
+  }
 
   GenerateRequiresImpl(options, printer, &required, &forwards, provided,
-                       /* require_jspb = */ have_message,
-                       /* require_extension = */ HasExtensions(desc),
-                       /* require_map = */ HasMap(options, desc));
+      /* require_jspb = */ have_message,
+      /* require_extension = */ has_extension,
+      /* require_map = */ has_map);
 }
 
 void Generator::GenerateRequiresForLibrary(
@@ -1851,20 +1976,20 @@
                                      const FieldDescriptor* field,
                                      std::set<string>* required,
                                      std::set<string>* forwards) const {
-    if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
-        // N.B.: file-level extensions with enum type do *not* create
-        // dependencies, as per original codegen.
-        !(field->is_extension() && field->extension_scope() == NULL)) {
-      if (options.add_require_for_enums) {
-        required->insert(GetEnumPath(options, field->enum_type()));
-      } else {
-        forwards->insert(GetEnumPath(options, field->enum_type()));
-      }
-    } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      if (!IgnoreMessage(field->message_type())) {
-        required->insert(GetMessagePath(options, field->message_type()));
-      }
+  if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
+      // N.B.: file-level extensions with enum type do *not* create
+      // dependencies, as per original codegen.
+      !(field->is_extension() && field->extension_scope() == nullptr)) {
+    if (options.add_require_for_enums) {
+      required->insert(GetEnumPath(options, field->enum_type()));
+    } else {
+      forwards->insert(GetEnumPath(options, field->enum_type()));
     }
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    if (!IgnoreMessage(field->message_type())) {
+      required->insert(GetMessagePath(options, field->message_type()));
+    }
+  }
 }
 
 void Generator::FindRequiresForExtension(const GeneratorOptions& options,
@@ -1889,6 +2014,10 @@
                                         io::Printer* printer,
                                         const FileDescriptor* file) const {
   for (int i = 0; i < file->message_type_count(); i++) {
+    GenerateClassConstructorAndDeclareExtensionFieldInfo(
+        options, printer, file->message_type(i));
+  }
+  for (int i = 0; i < file->message_type_count(); i++) {
     GenerateClass(options, printer, file->message_type(i));
   }
   for (int i = 0; i < file->enum_type_count(); i++) {
@@ -1905,7 +2034,6 @@
 
   if (!NamespaceOnly(desc)) {
     printer->Print("\n");
-    GenerateClassConstructor(options, printer, desc);
     GenerateClassFieldInfo(options, printer, desc);
 
 
@@ -1931,9 +2059,6 @@
   if (!NamespaceOnly(desc)) {
     GenerateClassRegistration(options, printer, desc);
     GenerateClassFields(options, printer, desc);
-    if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
-      GenerateClassExtensionFieldInfo(options, printer, desc);
-    }
 
     if (options.import_style != GeneratorOptions::kImportClosure) {
       for (int i = 0; i < desc->extension_count(); i++) {
@@ -1984,6 +2109,24 @@
       "classname", GetMessagePath(options, desc));
 }
 
+void Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo(
+    const GeneratorOptions& options,
+    io::Printer* printer,
+    const Descriptor* desc) const {
+  if (!NamespaceOnly(desc)) {
+    GenerateClassConstructor(options, printer, desc);
+    if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
+      GenerateClassExtensionFieldInfo(options, printer, desc);
+    }
+  }
+  for (int i = 0; i < desc->nested_type_count(); i++) {
+    if (!IgnoreMessage(desc->nested_type(i))) {
+      GenerateClassConstructorAndDeclareExtensionFieldInfo(
+          options, printer, desc->nested_type(i));
+    }
+  }
+}
+
 void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
                                        io::Printer* printer,
                                        const Descriptor* desc) const {
@@ -3222,7 +3365,7 @@
   string extension_scope =
       (field->extension_scope()
            ? GetMessagePath(options, field->extension_scope())
-           : GetFilePath(options, field->file()));
+           : GetNamespace(options, field->file()));
 
   const string extension_object_name = JSObjectFieldName(options, field);
   printer->Print(
@@ -3397,8 +3540,8 @@
     return kEverythingInOneFile;
   }
 
-  // Otherwise, we create one output file per type.
-  return kOneOutputFilePerType;
+  // Otherwise, we create one output file per SCC.
+  return kOneOutputFilePerSCC;
 }
 
 void Generator::GenerateFilesInDepOrder(
@@ -3441,6 +3584,37 @@
   }
 }
 
+bool Generator::GenerateFile(const FileDescriptor* file,
+                             const GeneratorOptions &options,
+                             GeneratorContext* context,
+                             bool use_short_name) const {
+  string filename =
+      options.output_dir + "/" + GetJSFilename(options,
+          use_short_name ? file->name().substr(file->name().rfind('/'))
+                         : file->name());
+  std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
+  GOOGLE_CHECK(output);
+  GeneratedCodeInfo annotations;
+  io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+      &annotations);
+  io::Printer printer(
+      output.get(), '$', options.annotate_code ?
+                         &annotation_collector : nullptr);
+
+
+  GenerateFile(options, &printer, file);
+
+  if (printer.failed()) {
+    return false;
+  }
+
+  if (options.annotate_code) {
+    EmbedCodeAnnotations(annotations, &printer);
+  }
+
+  return true;
+}
+
 void Generator::GenerateFile(const GeneratorOptions& options,
                              io::Printer* printer,
                              const FileDescriptor* file) const {
@@ -3479,7 +3653,7 @@
         IgnoreField(file->extension(i))) {
       continue;
     }
-    provided.insert(GetFilePath(options, file) + "." +
+    provided.insert(GetNamespace(options, file) + "." +
                     JSObjectFieldName(options, file->extension(i)));
     extensions.insert(file->extension(i));
   }
@@ -3505,10 +3679,10 @@
   if (options.import_style == GeneratorOptions::kImportCommonJs &&
       !provided.empty()) {
     printer->Print("goog.object.extend(exports, $package$);\n",
-                   "package", GetFilePath(options, file));
+                   "package", GetNamespace(options, file));
   } else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) {
     printer->Print("goog.object.extend(exports, proto);\n", "package",
-                   GetFilePath(options, file));
+                   GetNamespace(options, file));
   }
 
   // Emit well-known type methods.
@@ -3570,21 +3744,36 @@
     if (printer.failed()) {
       return false;
     }
-  } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) {
-    std::set<const void*> allowed_set;
-    if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
+  } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerSCC) {
+    std::set<const Descriptor*> have_printed;
+    SCCAnalyzer<DepsGenerator> analyzer;
+    std::map<const void*, string> allowed_map;
+    if (!GenerateJspbAllowedMap(
+        options, files, &allowed_map, &analyzer, error)) {
       return false;
     }
 
+    bool generated = false;
     for (int i = 0; i < files.size(); i++) {
       const FileDescriptor* file = files[i];
+      // Force well known type to generate in a whole file.
+      if (IsWellKnownTypeFile(file)) {
+        if (!GenerateFile(file, options, context, true)) {
+          return false;
+        }
+        generated = true;
+        continue;
+      }
       for (int j = 0; j < file->message_type_count(); j++) {
         const Descriptor* desc = file->message_type(j);
-        if (allowed_set.count(desc) == 0) {
+        if (have_printed.count(desc) ||
+            allowed_map.count(analyzer.GetSCC(desc)) == 0) {
           continue;
         }
 
-        string filename = GetMessageFileName(options, desc);
+        generated = true;
+        const SCC* scc = analyzer.GetSCC(desc);
+        const string& filename = allowed_map[scc];
         std::unique_ptr<io::ZeroCopyOutputStream> output(
             context->Open(filename));
         GOOGLE_CHECK(output.get());
@@ -3593,12 +3782,30 @@
         GenerateHeader(options, &printer);
 
         std::set<string> provided;
-        FindProvidesForMessage(options, &printer, desc, &provided);
+        for (auto one_desc : scc->descriptors) {
+          if (one_desc->containing_type() == nullptr) {
+            FindProvidesForMessage(options, &printer, one_desc, &provided);
+          }
+        }
         GenerateProvides(options, &printer, &provided);
         GenerateTestOnly(options, &printer);
-        GenerateRequiresForMessage(options, &printer, desc, &provided);
+        GenerateRequiresForSCC(options, &printer, scc, &provided);
 
-        GenerateClass(options, &printer, desc);
+        for (auto one_desc : scc->descriptors) {
+          if (one_desc->containing_type() == nullptr) {
+            GenerateClassConstructorAndDeclareExtensionFieldInfo(
+                options, &printer, one_desc);
+          }
+        }
+        for (auto one_desc : scc->descriptors) {
+          if (one_desc->containing_type() == nullptr) {
+            GenerateClass(options, &printer, one_desc);
+          }
+        }
+
+        for (auto one_desc : scc->descriptors) {
+          have_printed.insert(one_desc);
+        }
 
         if (printer.failed()) {
           return false;
@@ -3606,11 +3813,12 @@
       }
       for (int j = 0; j < file->enum_type_count(); j++) {
         const EnumDescriptor* enumdesc = file->enum_type(j);
-        if (allowed_set.count(enumdesc) == 0) {
+        if (allowed_map.count(enumdesc) == 0) {
           continue;
         }
 
-        string filename = GetEnumFileName(options, enumdesc);
+        generated = true;
+        const string& filename = allowed_map[enumdesc];
         std::unique_ptr<io::ZeroCopyOutputStream> output(
             context->Open(filename));
         GOOGLE_CHECK(output.get());
@@ -3631,8 +3839,9 @@
       }
       // File-level extensions (message-level extensions are generated under
       // the enclosing message).
-      if (allowed_set.count(file) == 1) {
-        string filename = GetExtensionFileName(options, file);
+      if (allowed_map.count(file) == 1) {
+        generated = true;
+        const string& filename = allowed_map[file];
 
         std::unique_ptr<io::ZeroCopyOutputStream> output(
             context->Open(filename));
@@ -3662,32 +3871,20 @@
         }
       }
     }
+    if (!generated) {
+      string filename = options.output_dir + "/" +
+          "empty_no_content_void_file" + options.GetFileNameExtension();
+      std::unique_ptr<io::ZeroCopyOutputStream> output(
+          context->Open(filename));
+    }
   } else /* options.output_mode() == kOneOutputFilePerInputFile */ {
     // Generate one output file per input (.proto) file.
 
     for (int i = 0; i < files.size(); i++) {
       const FileDescriptor* file = files[i];
-
-      string filename =
-          options.output_dir + "/" + GetJSFilename(options, file->name());
-      std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
-      GOOGLE_CHECK(output.get());
-      GeneratedCodeInfo annotations;
-      io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
-          &annotations);
-      io::Printer printer(output.get(), '$',
-                          options.annotate_code ? &annotation_collector : NULL);
-
-
-      GenerateFile(options, &printer, file);
-
-      if (printer.failed()) {
+      if (!GenerateFile(file, options, context, false)) {
         return false;
       }
-
-      if (options.annotate_code) {
-        EmbedCodeAnnotations(annotations, &printer);
-      }
     }
   }
   return true;
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index 4567b07..a48750b 100644
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -38,6 +38,7 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/scc.h>
 #include <google/protobuf/compiler/code_generator.h>
 
 #include <google/protobuf/port_def.inc>
@@ -98,7 +99,7 @@
     // Create an output file for each input .proto file.
     kOneOutputFilePerInputFile,
     // Create an output file for each type.
-    kOneOutputFilePerType,
+    kOneOutputFilePerSCC,
     // Put everything in a single file named by the library option.
     kEverythingInOneFile,
   };
@@ -191,10 +192,10 @@
       const GeneratorOptions& options, io::Printer* printer,
       const std::vector<const FileDescriptor*>& files,
       std::set<std::string>* provided) const;
-  void GenerateRequiresForMessage(const GeneratorOptions& options,
-                        io::Printer* printer,
-                        const Descriptor* desc,
-                        std::set<std::string>* provided) const;
+  void GenerateRequiresForSCC(const GeneratorOptions& options,
+                              io::Printer* printer,
+                              const SCC* scc,
+                              std::set<std::string>* provided) const;
   // For extension fields at file scope.
   void GenerateRequiresForExtensions(
       const GeneratorOptions& options, io::Printer* printer,
@@ -218,7 +219,13 @@
                                 const FieldDescriptor* field,
                                 std::set<std::string>* required,
                                 std::set<std::string>* forwards) const;
-
+  // Generate all things in a proto file into one file.
+  // If use_short_name is true, the generated file's name will only be short
+  // name that without directory, otherwise filename equals file->name()
+  bool GenerateFile(const FileDescriptor* file,
+                    const GeneratorOptions &options,
+                    GeneratorContext* context,
+                    bool use_short_name) const;
   void GenerateFile(const GeneratorOptions& options,
                     io::Printer* printer,
                     const FileDescriptor* file) const;
@@ -255,6 +262,10 @@
   void GenerateClassFieldInfo(const GeneratorOptions& options,
                               io::Printer* printer,
                               const Descriptor* desc) const;
+  void GenerateClassConstructorAndDeclareExtensionFieldInfo(
+      const GeneratorOptions& options,
+      io::Printer* printer,
+      const Descriptor* desc) const;
   void GenerateClassXid(const GeneratorOptions& options,
                         io::Printer* printer,
                         const Descriptor* desc) const;
diff --git a/src/google/protobuf/compiler/js/well_known_types_embed.cc b/src/google/protobuf/compiler/js/well_known_types_embed.cc
index c00c60c..5cb7365 100644
--- a/src/google/protobuf/compiler/js/well_known_types_embed.cc
+++ b/src/google/protobuf/compiler/js/well_known_types_embed.cc
@@ -46,6 +46,7 @@
      "\n"
      "/**\n"
      " * Packs the given message instance into this Any.\n"
+     " * For binary format usage only.\n"
      " * @param {!Uint8Array} serialized The serialized data to pack.\n"
      " * @param {string} name The type name of this message object.\n"
      " * @param {string=} opt_typeUrlPrefix the type URL prefix.\n"
@@ -85,7 +86,8 @@
      "  } else {\n"
      "    return null;\n"
      "  }\n"
-     "};\n"},
+     "};\n"
+    },
     {"timestamp.js",
      "/* This code will be inserted into generated code for\n"
      " * google/protobuf/timestamp.proto. */\n"
@@ -109,6 +111,19 @@
      "proto.google.protobuf.Timestamp.prototype.fromDate = function(value) {\n"
      "  this.setSeconds(Math.floor(value.getTime() / 1000));\n"
      "  this.setNanos(value.getMilliseconds() * 1000000);\n"
+     "};\n"
+     "\n"
+     "\n"
+     "/**\n"
+     " * Factory method that returns a Timestamp object with value equal to\n"
+     " * the given Date.\n"
+     " * @param {!Date} value The value to set.\n"
+     " * @return {!proto.google.protobuf.Timestamp}\n"
+     " */\n"
+     "proto.google.protobuf.Timestamp.fromDate = function(value) {\n"
+     "  var timestamp = new proto.google.protobuf.Timestamp();\n"
+     "  timestamp.fromDate(value);\n"
+     "  return timestamp;\n"
      "};\n"},
     {"struct.js",
      "/* This code will be inserted into generated code for\n"
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 8be2652..0b86049 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -55,10 +55,9 @@
   cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator,
                         "Generate C++ header and source.");
 
-#ifdef GOOGLE_PROTOBUF_USE_OPENSOURCE_GOOGLE3_RUNTIME
-  cpp_generator.set_runtime(cpp::CppGenerator::Runtime::kOpensourceGoogle3);
-#elif defined(GOOGLE_PROTOBUF_USE_OPENSOURCE_RUNTIME)
-  cpp_generator.set_runtime(cpp::CppGenerator::Runtime::kOpensource);
+#ifdef GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE
+  cpp_generator.set_opensource_runtime(true);
+  cpp_generator.set_runtime_include_base(GOOGLE_PROTOBUF_RUNTIME_INCLUDE_BASE);
 #endif
 
   // Proto2 Java
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 0cec293..c533c6a 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -2184,26 +2184,22 @@
     file->clear_package();
   }
 
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kPackageFieldNumber);
+  location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
+
   DO(Consume("package"));
 
-  {
-    LocationRecorder location(root_location,
-                              FileDescriptorProto::kPackageFieldNumber);
-    location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
-
-    while (true) {
-      string identifier;
-      DO(ConsumeIdentifier(&identifier, "Expected identifier."));
-      file->mutable_package()->append(identifier);
-      if (!TryConsume(".")) break;
-      file->mutable_package()->append(".");
-    }
-
-    location.EndAt(input_->previous());
-
-    DO(ConsumeEndOfDeclaration(";", &location));
+  while (true) {
+    string identifier;
+    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+    file->mutable_package()->append(identifier);
+    if (!TryConsume(".")) break;
+    file->mutable_package()->append(".");
   }
 
+  DO(ConsumeEndOfDeclaration(";", &location));
+
   return true;
 }
 
@@ -2212,31 +2208,30 @@
                          RepeatedField<int32>* weak_dependency,
                          const LocationRecorder& root_location,
                          const FileDescriptorProto* containing_file) {
+  LocationRecorder location(root_location,
+                            FileDescriptorProto::kDependencyFieldNumber,
+                            dependency->size());
+
   DO(Consume("import"));
+
   if (LookingAt("public")) {
-    LocationRecorder location(
+    LocationRecorder public_location(
         root_location, FileDescriptorProto::kPublicDependencyFieldNumber,
         public_dependency->size());
     DO(Consume("public"));
     *public_dependency->Add() = dependency->size();
   } else if (LookingAt("weak")) {
-    LocationRecorder location(
+    LocationRecorder weak_location(
         root_location, FileDescriptorProto::kWeakDependencyFieldNumber,
         weak_dependency->size());
     DO(Consume("weak"));
     *weak_dependency->Add() = dependency->size();
   }
-  {
-    LocationRecorder location(root_location,
-                              FileDescriptorProto::kDependencyFieldNumber,
-                              dependency->size());
-    DO(ConsumeString(dependency->Add(),
-      "Expected a string naming the file to import."));
 
-    location.EndAt(input_->previous());
+  DO(ConsumeString(dependency->Add(),
+                   "Expected a string naming the file to import."));
+  DO(ConsumeEndOfDeclaration(";", &location));
 
-    DO(ConsumeEndOfDeclaration(";", &location));
-  }
   return true;
 }
 
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 008d97d..e63739b 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -1693,7 +1693,7 @@
   // Now try to define it as a package.
   ExpectHasValidationErrors(
     "package foo.bar;",
-    "0:8: \"foo\" is already defined (as something other than a package) "
+    "0:0: \"foo\" is already defined (as something other than a package) "
       "in file \"bar.proto\".\n");
 }
 
@@ -2555,16 +2555,22 @@
 TEST_F(SourceInfoTest, BasicFileDecls) {
   EXPECT_TRUE(Parse(
       "$a$syntax = \"proto2\";$i$\n"
-      "package $b$foo.bar$c$;\n"
-      "import $d$\"baz.proto\"$e$;\n"
-      "import $f$\"qux.proto\"$g$;$h$\n"
+      "$b$package foo.bar;$c$\n"
+      "$d$import \"baz.proto\";$e$\n"
+      "$f$import\"qux.proto\";$h$\n"
+      "$j$import $k$public$l$ \"bar.proto\";$m$\n"
+      "$n$import $o$weak$p$ \"bar.proto\";$q$\n"
       "\n"
       "// comment ignored\n"));
 
-  EXPECT_TRUE(HasSpan('a', 'h', file_));
+  EXPECT_TRUE(HasSpan('a', 'q', file_));
   EXPECT_TRUE(HasSpan('b', 'c', file_, "package"));
   EXPECT_TRUE(HasSpan('d', 'e', file_, "dependency", 0));
-  EXPECT_TRUE(HasSpan('f', 'g', file_, "dependency", 1));
+  EXPECT_TRUE(HasSpan('f', 'h', file_, "dependency", 1));
+  EXPECT_TRUE(HasSpan('j', 'm', file_, "dependency", 2));
+  EXPECT_TRUE(HasSpan('k', 'l', file_, "public_dependency", 0));
+  EXPECT_TRUE(HasSpan('n', 'q', file_, "dependency", 3));
+  EXPECT_TRUE(HasSpan('o', 'p', file_, "weak_dependency", 0));
   EXPECT_TRUE(HasSpan('a', 'i', file_, "syntax"));
 }
 
@@ -3301,7 +3307,7 @@
       "// detached after empty before package\n"
       "\n"
       "// package leading\n"
-      "package $c$foo$d$;\n"
+      "$c$package foo;$d$\n"
       "// package trailing\n"
       "\n"
       "// ignored detach\n"
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 234be0d..171d1fe 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -179,8 +179,7 @@
   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto, file_level_service_descriptors_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto[] =
   "\n%google/protobuf/compiler/plugin.proto\022"
   "\030google.protobuf.compiler\032 google/protob"
   "uf/descriptor.proto\"F\n\007Version\022\r\n\005major\030"
@@ -197,7 +196,10 @@
   "content\030\017 \001(\tBg\n\034com.google.protobuf.com"
   "pilerB\014PluginProtosZ9github.com/golang/p"
   "rotobuf/protoc-gen-go/plugin;plugin_go"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fcompiler_2fplugin_2eproto,
   "google/protobuf/compiler/plugin.proto", &assign_descriptors_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto, 638,
 };
 
@@ -314,10 +316,10 @@
   auto msg = static_cast<Version*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -357,26 +359,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.Version.suffix");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_suffix();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_suffix();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -387,7 +392,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -795,10 +800,10 @@
   auto msg = static_cast<CodeGeneratorRequest*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -809,14 +814,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-          ::std::string* str = msg->add_file_to_generate();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_file_to_generate();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
@@ -827,14 +835,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorRequest.parameter");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_parameter();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_parameter();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional .google.protobuf.compiler.Version compiler_version = 3;
@@ -873,13 +884,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -890,7 +901,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1313,10 +1324,10 @@
   auto msg = static_cast<CodeGeneratorResponse_File*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1326,14 +1337,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string insertion_point = 2;
@@ -1342,14 +1356,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_insertion_point();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_insertion_point();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string content = 15;
@@ -1358,26 +1375,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.File.content");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_content();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_content();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1388,7 +1408,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1761,10 +1781,10 @@
   auto msg = static_cast<CodeGeneratorResponse*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1774,14 +1794,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.compiler.CodeGeneratorResponse.error");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_error();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_error();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
@@ -1805,13 +1828,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1822,7 +1845,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 187587c..6e8c8d2 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -147,7 +147,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Version& from);
   void MergeFrom(const Version& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -299,7 +299,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const CodeGeneratorRequest& from);
   void MergeFrom(const CodeGeneratorRequest& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -473,7 +473,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const CodeGeneratorResponse_File& from);
   void MergeFrom(const CodeGeneratorResponse_File& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -633,7 +633,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const CodeGeneratorResponse& from);
   void MergeFrom(const CodeGeneratorResponse& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 6dc61ec..ba7ecde 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -172,6 +172,7 @@
     io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) {
   // TODO(robinson): Allow parameterization of Python version?
   printer->Print(
+      "# -*- coding: utf-8 -*-\n"
       "# Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
       "# source: $filename$\n"
       "\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))"  //##PY25
diff --git a/src/google/protobuf/compiler/scc.cc b/src/google/protobuf/compiler/scc.cc
deleted file mode 100644
index bbdabbf..0000000
--- a/src/google/protobuf/compiler/scc.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <google/protobuf/compiler/scc.h>
-
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/descriptor.h>
-
-namespace google {
-namespace protobuf {
-namespace compiler {
-
-SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) {
-  // Must not have visited already.
-  GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
-
-  // Mark visited by inserting in map.
-  NodeData& result = cache_[descriptor];
-  // Initialize data structures.
-  result.index = result.lowlink = index_++;
-  stack_.push_back(descriptor);
-
-  // Recurse the fields / nodes in graph
-  for (int i = 0; i < descriptor->field_count(); i++) {
-    const Descriptor* child = descriptor->field(i)->message_type();
-    if (child) {
-      if (cache_.count(child) == 0) {
-        // unexplored node
-        NodeData child_data = DFS(child);
-        result.lowlink = std::min(result.lowlink, child_data.lowlink);
-      } else {
-        NodeData child_data = cache_[child];
-        if (child_data.scc == nullptr) {
-          // Still in the stack_ so we found a back edge
-          result.lowlink = std::min(result.lowlink, child_data.index);
-        }
-      }
-    }
-  }
-  if (result.index == result.lowlink) {
-    // This is the root of a strongly connected component
-    SCC* scc = CreateSCC();
-    while (true) {
-      const Descriptor* scc_desc = stack_.back();
-      scc->descriptors.push_back(scc_desc);
-      // Remove from stack
-      stack_.pop_back();
-      cache_[scc_desc].scc = scc;
-
-      if (scc_desc == descriptor) break;
-    }
-
-    // The order of descriptors is random and depends how this SCC was
-    // discovered. In-order to ensure maximum stability we sort it by name.
-    std::sort(scc->descriptors.begin(), scc->descriptors.end(),
-              [](const Descriptor* a, const Descriptor* b) {
-                return a->full_name() < b->full_name();
-              });
-    AddChildren(scc);
-  }
-  return result;
-}
-
-void SCCAnalyzer::AddChildren(SCC* scc) {
-  std::set<const SCC*> seen;
-  for (int i = 0; i < scc->descriptors.size(); i++) {
-    const Descriptor* descriptor = scc->descriptors[i];
-    for (int j = 0; j < descriptor->field_count(); j++) {
-      const Descriptor* child_msg = descriptor->field(j)->message_type();
-      if (child_msg) {
-        const SCC* child = GetSCC(child_msg);
-        if (child == scc) continue;
-        if (seen.insert(child).second) {
-          scc->children.push_back(child);
-        }
-      }
-    }
-  }
-}
-
-}  // namespace compiler
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/compiler/scc.h b/src/google/protobuf/compiler/scc.h
index c8cf77d..6243048 100644
--- a/src/google/protobuf/compiler/scc.h
+++ b/src/google/protobuf/compiler/scc.h
@@ -33,6 +33,8 @@
 
 #include <map>
 
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 
 #include <google/protobuf/port_def.inc>
@@ -54,6 +56,7 @@
 // This class is used for analyzing the SCC for each message, to ensure linear
 // instead of quadratic performance, if we do this per message we would get
 // O(V*(V+E)).
+template <class DepsGenerator>
 class PROTOC_EXPORT SCCAnalyzer {
  public:
   explicit SCCAnalyzer() : index_(0) {}
@@ -81,10 +84,69 @@
   }
 
   // Tarjan's Strongly Connected Components algo
-  NodeData DFS(const Descriptor* descriptor);
+  NodeData DFS(const Descriptor* descriptor) {
+    // Must not have visited already.
+    GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0);
+
+    // Mark visited by inserting in map.
+    NodeData& result = cache_[descriptor];
+    // Initialize data structures.
+    result.index = result.lowlink = index_++;
+    stack_.push_back(descriptor);
+
+    // Recurse the fields / nodes in graph
+    for (auto dep : DepsGenerator()(descriptor)) {
+      GOOGLE_CHECK(dep);
+      if (cache_.count(dep) == 0) {
+        // unexplored node
+        NodeData child_data = DFS(dep);
+        result.lowlink = std::min(result.lowlink, child_data.lowlink);
+      } else {
+        NodeData child_data = cache_[dep];
+        if (child_data.scc == nullptr) {
+          // Still in the stack_ so we found a back edge
+          result.lowlink = std::min(result.lowlink, child_data.index);
+        }
+      }
+    }
+    if (result.index == result.lowlink) {
+      // This is the root of a strongly connected component
+      SCC* scc = CreateSCC();
+      while (true) {
+        const Descriptor* scc_desc = stack_.back();
+        scc->descriptors.push_back(scc_desc);
+        // Remove from stack
+        stack_.pop_back();
+        cache_[scc_desc].scc = scc;
+
+        if (scc_desc == descriptor) break;
+      }
+
+      // The order of descriptors is random and depends how this SCC was
+      // discovered. In-order to ensure maximum stability we sort it by name.
+      std::sort(scc->descriptors.begin(), scc->descriptors.end(),
+                [](const Descriptor* a, const Descriptor* b) {
+                  return a->full_name() < b->full_name();
+                });
+      AddChildren(scc);
+    }
+    return result;
+  }
 
   // Add the SCC's that are children of this SCC to its children.
-  void AddChildren(SCC* scc);
+  void AddChildren(SCC* scc) {
+    std::set<const SCC*> seen;
+    for (auto descriptor : scc->descriptors) {
+      for (auto child_msg : DepsGenerator()(descriptor)) {
+        GOOGLE_CHECK(child_msg);
+        const SCC* child = GetSCC(child_msg);
+        if (child == scc) continue;
+        if (seen.insert(child).second) {
+          scc->children.push_back(child);
+        }
+      }
+    }
+  }
 
   // This is necessary for compiler bug in msvc2015.
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SCCAnalyzer);
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index 5bd3d43..66c6e2a 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -125,8 +125,10 @@
   }
 
   // Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'.
-  // Using a malloc'ed string because CreateProcess() can mutate its second parameter.  (WTF).
-  char *command_line =  portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
+  // Using a malloc'ed string because CreateProcess() can mutate its second
+  // parameter.
+  char *command_line =
+      portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
 
   // Create the process.
   PROCESS_INFORMATION process_info;
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 26f2b8c..5b7bd90 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -4498,6 +4498,7 @@
   }
 }
 
+
 void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
                                      const Descriptor* parent,
                                      Descriptor* result) {
@@ -4546,6 +4547,7 @@
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 
+
   for (int i = 0; i < proto.reserved_range_size(); i++) {
     const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i);
     for (int j = i + 1; j < proto.reserved_range_size(); j++) {
@@ -4634,7 +4636,6 @@
   }
 }
 
-
 void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
                                               const Descriptor* parent,
                                               FieldDescriptor* result,
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index f85ed13..a15884e 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -1051,8 +1051,7 @@
   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto, 27, file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto, file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fdescriptor_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] =
   "\n google/protobuf/descriptor.proto\022\017goog"
   "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file"
   "\030\001 \003(\0132$.google.protobuf.FileDescriptorP"
@@ -1204,7 +1203,10 @@
   "Z>github.com/golang/protobuf/protoc-gen-"
   "go/descriptor;descriptor\370\001\001\242\002\003GPB\252\002\032Goog"
   "le.Protobuf.Reflection"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fdescriptor_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
   "google/protobuf/descriptor.proto", &assign_descriptors_table_google_2fprotobuf_2fdescriptor_2eproto, 6022,
 };
 
@@ -1468,10 +1470,10 @@
   auto msg = static_cast<FileDescriptorSet*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1496,13 +1498,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1513,7 +1515,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1929,10 +1931,10 @@
   auto msg = static_cast<FileDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1942,14 +1944,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string package = 2;
@@ -1958,14 +1963,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.package");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_package();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_package();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated string dependency = 3;
@@ -1975,14 +1983,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.dependency");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-          ::std::string* str = msg->add_dependency();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_dependency();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
@@ -2141,26 +2152,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileDescriptorProto.syntax");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_syntax();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_syntax();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2171,7 +2185,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2968,10 +2982,10 @@
   auto msg = static_cast<DescriptorProto_ExtensionRange*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -3013,13 +3027,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -3030,7 +3044,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3393,10 +3407,10 @@
   auto msg = static_cast<DescriptorProto_ReservedRange*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -3423,13 +3437,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -3440,7 +3454,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3831,10 +3845,10 @@
   auto msg = static_cast<DescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -3844,14 +3858,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.FieldDescriptorProto field = 2;
@@ -4002,14 +4019,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.DescriptorProto.reserved_name");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-          ::std::string* str = msg->add_reserved_name();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_reserved_name();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 82 && (ptr += 1));
         break;
@@ -4017,13 +4037,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -4034,7 +4054,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -4704,10 +4724,10 @@
   auto msg = static_cast<ExtensionRangeOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -4732,20 +4752,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -4756,7 +4777,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -5189,10 +5210,10 @@
   auto msg = static_cast<FieldDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -5202,14 +5223,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string extendee = 2;
@@ -5218,14 +5242,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.extendee");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_extendee();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_extendee();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional int32 number = 3;
@@ -5272,14 +5299,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.type_name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_type_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_type_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string default_value = 7;
@@ -5288,14 +5318,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.default_value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_default_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_default_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional .google.protobuf.FieldOptions options = 8;
@@ -5329,26 +5362,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FieldDescriptorProto.json_name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_json_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_json_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -5359,7 +5395,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6083,10 +6119,10 @@
   auto msg = static_cast<OneofDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -6096,14 +6132,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.OneofDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional .google.protobuf.OneofOptions options = 2;
@@ -6124,13 +6163,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -6141,7 +6180,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6483,10 +6522,10 @@
   auto msg = static_cast<EnumDescriptorProto_EnumReservedRange*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -6513,13 +6552,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -6530,7 +6569,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -6901,10 +6940,10 @@
   auto msg = static_cast<EnumDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -6914,14 +6953,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
@@ -6982,14 +7024,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.EnumDescriptorProto.reserved_name");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-          ::std::string* str = msg->add_reserved_name();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_reserved_name();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 42 && (ptr += 1));
         break;
@@ -6997,13 +7042,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -7014,7 +7059,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -7527,10 +7572,10 @@
   auto msg = static_cast<EnumValueDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -7540,14 +7585,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValueDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional int32 number = 2;
@@ -7578,13 +7626,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -7595,7 +7643,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -8010,10 +8058,10 @@
   auto msg = static_cast<ServiceDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -8023,14 +8071,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.ServiceDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.MethodDescriptorProto method = 2;
@@ -8069,13 +8120,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -8086,7 +8137,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -8548,10 +8599,10 @@
   auto msg = static_cast<MethodDescriptorProto*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -8561,14 +8612,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string input_type = 2;
@@ -8577,14 +8631,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.input_type");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_input_type();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_input_type();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string output_type = 3;
@@ -8593,14 +8650,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.MethodDescriptorProto.output_type");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_output_type();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_output_type();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional .google.protobuf.MethodOptions options = 4;
@@ -8641,13 +8701,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -8658,7 +8718,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -9353,10 +9413,10 @@
   auto msg = static_cast<FileOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -9366,14 +9426,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_package");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_java_package();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_java_package();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string java_outer_classname = 8;
@@ -9382,14 +9445,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.java_outer_classname");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_java_outer_classname();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_java_outer_classname();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
@@ -9422,14 +9488,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.go_package");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_go_package();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_go_package();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional bool cc_generic_services = 16 [default = false];
@@ -9508,14 +9577,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.objc_class_prefix");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_objc_class_prefix();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_objc_class_prefix();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string csharp_namespace = 37;
@@ -9524,14 +9596,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.csharp_namespace");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_csharp_namespace();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_csharp_namespace();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string swift_prefix = 39;
@@ -9540,14 +9615,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.swift_prefix");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_swift_prefix();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_swift_prefix();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string php_class_prefix = 40;
@@ -9556,14 +9634,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_class_prefix");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_php_class_prefix();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_php_class_prefix();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string php_namespace = 41;
@@ -9572,14 +9653,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_namespace");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_php_namespace();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_php_namespace();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional bool php_generic_services = 42 [default = false];
@@ -9598,14 +9682,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.php_metadata_namespace");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_php_metadata_namespace();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_php_metadata_namespace();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string ruby_package = 45;
@@ -9614,14 +9701,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.FileOptions.ruby_package");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_ruby_package();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_ruby_package();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
@@ -9645,20 +9735,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -9669,7 +9760,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -10821,10 +10912,10 @@
   auto msg = static_cast<MessageOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -10889,20 +10980,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -10913,7 +11005,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -11386,10 +11478,10 @@
   auto msg = static_cast<FieldOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -11482,20 +11574,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -11506,7 +11599,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12025,10 +12118,10 @@
   auto msg = static_cast<OneofOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -12053,20 +12146,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -12077,7 +12171,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12394,10 +12488,10 @@
   auto msg = static_cast<EnumOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -12442,20 +12536,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -12466,7 +12561,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -12846,10 +12941,10 @@
   auto msg = static_cast<EnumValueOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -12884,20 +12979,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -12908,7 +13004,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -13250,10 +13346,10 @@
   auto msg = static_cast<ServiceOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -13288,20 +13384,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -13312,7 +13409,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -13667,10 +13764,10 @@
   auto msg = static_cast<MethodOptions*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -13719,20 +13816,21 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
       if ((8000u <= tag)) {
         auto res = msg->_extensions_.ParseField(tag, {_InternalParse, msg}, ptr, end,
             internal_default_instance(), &msg->_internal_metadata_, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
         continue;
       }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -13743,7 +13841,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -14140,10 +14238,10 @@
   auto msg = static_cast<UninterpretedOption_NamePart*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -14153,14 +14251,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.NamePart.name_part");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_name_part();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name_part();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // required bool is_extension = 2;
@@ -14176,13 +14277,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -14193,7 +14294,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -14600,10 +14701,10 @@
   auto msg = static_cast<UninterpretedOption*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -14631,14 +14732,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.identifier_value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_identifier_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_identifier_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional uint64 positive_int_value = 4;
@@ -14675,12 +14779,16 @@
         if (static_cast<::google::protobuf::uint8>(tag) != 58) goto handle_unusual;
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::internal::StringParser;
-        ::std::string* str = msg->mutable_string_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        str->append(ptr, size);
+        auto str = msg->mutable_string_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
         ptr += size;
         break;
       }
@@ -14690,26 +14798,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.UninterpretedOption.aggregate_value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_aggregate_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_aggregate_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -14720,7 +14831,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -15276,10 +15387,10 @@
   auto msg = static_cast<SourceCodeInfo_Location*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -15335,14 +15446,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_comments");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_leading_comments();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_leading_comments();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional string trailing_comments = 4;
@@ -15351,14 +15465,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.trailing_comments");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_trailing_comments();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_trailing_comments();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated string leading_detached_comments = 6;
@@ -15368,14 +15485,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-          ::std::string* str = msg->add_leading_detached_comments();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_leading_detached_comments();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 50 && (ptr += 1));
         break;
@@ -15383,13 +15503,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -15400,7 +15520,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -15898,10 +16018,10 @@
   auto msg = static_cast<SourceCodeInfo*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -15926,13 +16046,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -15943,7 +16063,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -16252,10 +16372,10 @@
   auto msg = static_cast<GeneratedCodeInfo_Annotation*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -16288,14 +16408,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.GeneratedCodeInfo.Annotation.source_file");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8Verify;
-        ::std::string* str = msg->mutable_source_file();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_source_file();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8Verify;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8Verify(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // optional int32 begin = 3;
@@ -16321,13 +16444,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -16338,7 +16461,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -16754,10 +16877,10 @@
   auto msg = static_cast<GeneratedCodeInfo*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -16782,13 +16905,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -16799,7 +16922,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index c4b8365..b9245b2 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -372,7 +372,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FileDescriptorSet& from);
   void MergeFrom(const FileDescriptorSet& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -512,7 +512,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FileDescriptorProto& from);
   void MergeFrom(const FileDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -841,7 +841,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const DescriptorProto_ExtensionRange& from);
   void MergeFrom(const DescriptorProto_ExtensionRange& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -997,7 +997,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const DescriptorProto_ReservedRange& from);
   void MergeFrom(const DescriptorProto_ReservedRange& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1140,7 +1140,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const DescriptorProto& from);
   void MergeFrom(const DescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1422,7 +1422,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const ExtensionRangeOptions& from);
   void MergeFrom(const ExtensionRangeOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1565,7 +1565,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FieldDescriptorProto& from);
   void MergeFrom(const FieldDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1948,7 +1948,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const OneofDescriptorProto& from);
   void MergeFrom(const OneofDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -2113,7 +2113,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumDescriptorProto_EnumReservedRange& from);
   void MergeFrom(const EnumDescriptorProto_EnumReservedRange& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -2256,7 +2256,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumDescriptorProto& from);
   void MergeFrom(const EnumDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -2472,7 +2472,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumValueDescriptorProto& from);
   void MergeFrom(const EnumValueDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -2645,7 +2645,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const ServiceDescriptorProto& from);
   void MergeFrom(const ServiceDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -2823,7 +2823,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const MethodDescriptorProto& from);
   void MergeFrom(const MethodDescriptorProto& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -3054,7 +3054,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FileOptions& from);
   void MergeFrom(const FileOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -3555,7 +3555,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const MessageOptions& from);
   void MergeFrom(const MessageOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -3730,7 +3730,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FieldOptions& from);
   void MergeFrom(const FieldOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -3977,7 +3977,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const OneofOptions& from);
   void MergeFrom(const OneofOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4120,7 +4120,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumOptions& from);
   void MergeFrom(const EnumOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4279,7 +4279,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumValueOptions& from);
   void MergeFrom(const EnumValueOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4430,7 +4430,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const ServiceOptions& from);
   void MergeFrom(const ServiceOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4581,7 +4581,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const MethodOptions& from);
   void MergeFrom(const MethodOptions& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4768,7 +4768,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const UninterpretedOption_NamePart& from);
   void MergeFrom(const UninterpretedOption_NamePart& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -4931,7 +4931,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const UninterpretedOption& from);
   void MergeFrom(const UninterpretedOption& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -5172,7 +5172,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const SourceCodeInfo_Location& from);
   void MergeFrom(const SourceCodeInfo_Location& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -5400,7 +5400,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const SourceCodeInfo& from);
   void MergeFrom(const SourceCodeInfo& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -5542,7 +5542,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const GeneratedCodeInfo_Annotation& from);
   void MergeFrom(const GeneratedCodeInfo_Annotation& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -5724,7 +5724,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const GeneratedCodeInfo& from);
   void MergeFrom(const GeneratedCodeInfo& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 02602d2..bc0cb3e 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -69,15 +69,17 @@
   file_level_metadata_google_2fprotobuf_2fduration_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fduration_2eproto, file_level_service_descriptors_google_2fprotobuf_2fduration_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fduration_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto[] =
   "\n\036google/protobuf/duration.proto\022\017google"
   ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r"
   "\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu"
   "rationProtoP\001Z*github.com/golang/protobu"
   "f/ptypes/duration\370\001\001\242\002\003GPB\252\002\036Google.Prot"
   "obuf.WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fduration_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fduration_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fduration_2eproto,
   "google/protobuf/duration.proto", &assign_descriptors_table_google_2fprotobuf_2fduration_2eproto, 227,
 };
 
@@ -176,10 +178,10 @@
   auto msg = static_cast<Duration*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -206,13 +208,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -223,7 +225,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 78d9466..25c55e8 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -125,7 +125,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Duration& from);
   void MergeFrom(const Duration& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 9d0f9ae..724607c 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -67,14 +67,16 @@
   file_level_metadata_google_2fprotobuf_2fempty_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fempty_2eproto, file_level_service_descriptors_google_2fprotobuf_2fempty_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fempty_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto[] =
   "\n\033google/protobuf/empty.proto\022\017google.pr"
   "otobuf\"\007\n\005EmptyBv\n\023com.google.protobufB\n"
   "EmptyProtoP\001Z\'github.com/golang/protobuf"
   "/ptypes/empty\370\001\001\242\002\003GPB\252\002\036Google.Protobuf"
   ".WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fempty_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fempty_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fempty_2eproto,
   "google/protobuf/empty.proto", &assign_descriptors_table_google_2fprotobuf_2fempty_2eproto, 183,
 };
 
@@ -162,23 +164,23 @@
   auto msg = static_cast<Empty*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -189,7 +191,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 39b944b..4a40eca 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -125,7 +125,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Empty& from);
   void MergeFrom(const Empty& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index ff2fc35..f63afef 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -38,6 +38,8 @@
 #include <unordered_map>
 #include <utility>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/message_lite.h>
@@ -48,9 +50,6 @@
 #include <google/protobuf/stubs/hash.h>
 
 #include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
 
 namespace google {
 namespace protobuf {
@@ -178,7 +177,11 @@
   GOOGLE_CHECK(type == WireFormatLite::TYPE_MESSAGE ||
         type == WireFormatLite::TYPE_GROUP);
   ExtensionInfo info(type, is_repeated, is_packed);
-  info.message_prototype = prototype;
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+  info.message_info = {prototype, prototype->_ParseFunc()};
+#else
+  info.message_info = {prototype};
+#endif
   Register(containing_type, number, info);
 }
 
@@ -1215,194 +1218,8 @@
     return UnknownFieldParse(tag, parent, begin, end,
                              metadata->mutable_unknown_fields(), ctx);
   }
-  auto ptr = begin;
-  ParseClosure child;
-  int depth;
-  if (was_packed_on_wire) {
-    switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
-  case WireFormatLite::TYPE_##UPPERCASE:                                     \
-    child = {                                                                \
-        internal::Packed##CPP_CAMELCASE##Parser,                             \
-        MutableRawRepeatedField(number, extension.type, extension.is_packed, \
-                                extension.descriptor)};                      \
-    goto length_delim
-      HANDLE_TYPE(INT32, Int32);
-      HANDLE_TYPE(INT64, Int64);
-      HANDLE_TYPE(UINT32, UInt32);
-      HANDLE_TYPE(UINT64, UInt64);
-      HANDLE_TYPE(SINT32, SInt32);
-      HANDLE_TYPE(SINT64, SInt64);
-      HANDLE_TYPE(FIXED32, Fixed32);
-      HANDLE_TYPE(FIXED64, Fixed64);
-      HANDLE_TYPE(SFIXED32, SFixed32);
-      HANDLE_TYPE(SFIXED64, SFixed64);
-      HANDLE_TYPE(FLOAT, Float);
-      HANDLE_TYPE(DOUBLE, Double);
-      HANDLE_TYPE(BOOL, Bool);
-#undef HANDLE_TYPE
-
-      case WireFormatLite::TYPE_ENUM:
-        ctx->extra_parse_data().SetEnumValidatorArg(
-            extension.enum_validity_check.func,
-            extension.enum_validity_check.arg,
-            metadata->mutable_unknown_fields(), tag >> 3);
-        child = {
-            internal::PackedValidEnumParserLiteArg,
-            MutableRawRepeatedField(number, extension.type, extension.is_packed,
-                                    extension.descriptor)};
-        goto length_delim;
-      case WireFormatLite::TYPE_STRING:
-      case WireFormatLite::TYPE_BYTES:
-      case WireFormatLite::TYPE_GROUP:
-      case WireFormatLite::TYPE_MESSAGE:
-        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
-        break;
-    }
-  } else {
-    switch (extension.type) {
-#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 value;                                                           \
-    ptr = Varint::Parse64(ptr, &value);                                     \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_VARINT_TYPE(INT32, Int32);
-      HANDLE_VARINT_TYPE(INT64, Int64);
-      HANDLE_VARINT_TYPE(UINT32, UInt32);
-      HANDLE_VARINT_TYPE(UINT64, UInt64);
-#undef HANDLE_VARINT_TYPE
-#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 val;                                                             \
-    ptr = Varint::Parse64(ptr, &val);                                       \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
-    auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
-      HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
-#undef HANDLE_SVARINT_TYPE
-#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    CPPTYPE value;                                                          \
-    std::memcpy(&value, ptr, sizeof(CPPTYPE));                              \
-    ptr += sizeof(CPPTYPE);                                                 \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
-      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
-      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
-      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
-      HANDLE_FIXED_TYPE(FLOAT, Float, float);
-      HANDLE_FIXED_TYPE(DOUBLE, Double, double);
-      HANDLE_FIXED_TYPE(BOOL, Bool, bool);
-#undef HANDLE_FIXED_TYPE
-
-      case WireFormatLite::TYPE_ENUM: {
-        uint64 val;
-        ptr = Varint::Parse64(ptr, &val);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-        int value = val;
-
-        if (!extension.enum_validity_check.func(
-                extension.enum_validity_check.arg, value)) {
-          WriteVarint(number, val, metadata->mutable_unknown_fields());
-        } else if (extension.is_repeated) {
-          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
-                  extension.descriptor);
-        } else {
-          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
-                  extension.descriptor);
-        }
-        break;
-      }
-
-      case WireFormatLite::TYPE_BYTES:
-      case WireFormatLite::TYPE_STRING: {
-        string* value = extension.is_repeated
-                            ? AddString(number, WireFormatLite::TYPE_STRING,
-                                        extension.descriptor)
-                            : MutableString(number, WireFormatLite::TYPE_STRING,
-                                            extension.descriptor);
-        child = {StringParser, value};
-        goto length_delim;
-      }
-
-      case WireFormatLite::TYPE_GROUP: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
-                             *extension.message_prototype, extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
-                                 *extension.message_prototype,
-                                 extension.descriptor);
-        child = {value->_ParseFunc(), value};
-        bool ok = ctx->PrepareGroup(tag, &depth);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-        ptr = child(ptr, end, ctx);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-        if (ctx->GroupContinues(depth)) goto group_continues;
-        break;
-      }
-
-      case WireFormatLite::TYPE_MESSAGE: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
-                             *extension.message_prototype, extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
-                                 *extension.message_prototype,
-                                 extension.descriptor);
-        child = {value->_ParseFunc(), value};
-        goto length_delim;
-      }
-    }
-  }
-
-  return std::make_pair(ptr, false);
-
-length_delim:
-  uint32 size;
-  ptr = Varint::Parse32Inline(ptr, &size);
-  GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-  if (size > end - ptr) goto len_delim_till_end;
-  {
-    auto newend = ptr + size;
-    bool ok = ctx->ParseExactRange(child, ptr, newend);
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-    ptr = newend;
-  }
-  return std::make_pair(ptr, false);
-len_delim_till_end:
-  return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
-                        true);
-
-group_continues:
-  ctx->StoreGroup(parent, child, depth);
-  return std::make_pair(ptr, true);
+  return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
+                                     metadata, parent, begin, end, ctx);
 }
 #endif
 
@@ -1542,21 +1359,27 @@
       }
 
       case WireFormatLite::TYPE_GROUP: {
-        MessageLite* value = extension.is_repeated ?
-            AddMessage(number, WireFormatLite::TYPE_GROUP,
-                       *extension.message_prototype, extension.descriptor) :
-            MutableMessage(number, WireFormatLite::TYPE_GROUP,
-                           *extension.message_prototype, extension.descriptor);
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
         if (!WireFormatLite::ReadGroup(number, input, value)) return false;
         break;
       }
 
       case WireFormatLite::TYPE_MESSAGE: {
-        MessageLite* value = extension.is_repeated ?
-            AddMessage(number, WireFormatLite::TYPE_MESSAGE,
-                       *extension.message_prototype, extension.descriptor) :
-            MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
-                           *extension.message_prototype, extension.descriptor);
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
         if (!WireFormatLite::ReadMessage(input, value)) return false;
         break;
       }
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index b31c8c4..57dbdef 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -47,16 +47,13 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/port.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
 
 #include <google/protobuf/port_def.inc>
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
@@ -121,9 +118,16 @@
     const void* arg;
   };
 
+  struct MessageInfo {
+    const MessageLite* prototype;
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+    ParseFunc parse_func;
+#endif
+  };
+
   union {
     EnumValidityCheck enum_validity_check;
-    const MessageLite* message_prototype;
+    MessageInfo message_info;
   };
 
   // The descriptor for this extension, if one exists and is known.  May be
@@ -396,6 +400,11 @@
                   io::CodedOutputStream* unknown_fields);
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+  template <typename T>
+  std::pair<const char*, bool> ParseFieldWithExtensionInfo(
+      int number, bool was_packed_on_wire, const ExtensionInfo& info,
+      T* metadata, ParseClosure parent, const char* begin, const char* end,
+      internal::ParseContext* ctx);
   // Lite parser
   std::pair<const char*, bool> ParseField(
       uint64 tag, ParseClosure parent, const char* begin, const char* end,
@@ -408,6 +417,11 @@
       const Message* containing_type,
       internal::InternalMetadataWithArena* metadata,
       internal::ParseContext* ctx);
+  std::pair<const char*, bool> ParseFieldMaybeLazily(
+      uint64 tag, ParseClosure parent, const char* begin, const char* end,
+      const Message* containing_type,
+      internal::InternalMetadataWithArena* metadata,
+      internal::ParseContext* ctx);
   const char* ParseMessageSetItem(ParseClosure parent, const char* begin,
                                   const char* end,
                                   const Message* containing_type,
@@ -799,6 +813,7 @@
 };
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
 template <typename Msg, typename Metadata>
 const char* ParseMessageSet(const char* begin, const char* end, Msg* msg,
                             ExtensionSet* ext, Metadata* metadata,
@@ -811,26 +826,27 @@
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     if (tag == WireFormatLite::kMessageSetItemStartTag) {
-      bool ok = ctx->PrepareGroup(tag, &depth);
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
       ctx->extra_parse_data().payload.clear();
-      ptr = Msg::InternalParseMessageSetItem(ptr, end, msg, ctx);
+      auto res = ctx->ParseGroup(tag, {Msg::InternalParseMessageSetItem, msg},
+                                 ptr, end, &depth);
+      ptr = res.first;
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-      if (ctx->GroupContinues(depth)) goto group_continues;
+      if (res.second) {
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup(
+            {Msg::_InternalParse, msg}, {Msg::InternalParseMessageSetItem, msg},
+            depth, tag));
+        return ptr;
+      }
     } else {
       auto res =
           ext->ParseField(tag, {Msg::_InternalParse, msg}, ptr, end,
                           Msg::internal_default_instance(), metadata, ctx);
       ptr = res.first;
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       if (res.second) break;
     }
   }
   return ptr;
-group_continues:
-  GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({Msg::_InternalParse, msg},
-                  {Msg::InternalParseMessageSetItem, msg}, depth);
-  return ptr;
 }
 #endif
 
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 20d36ab..90a96b5 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -35,12 +35,15 @@
 // Contains methods defined in extension_set.h which cannot be part of the
 // lite library because they use descriptors or reflection.
 
+#include <google/protobuf/extension_set.h>
+
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/extension_set_inl.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/extension_set.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/unknown_field_set.h>
@@ -301,11 +304,15 @@
     output->is_packed = extension->options().packed();
     output->descriptor = extension;
     if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      output->message_prototype =
+      output->message_info.prototype =
           factory_->GetPrototype(extension->message_type());
-      GOOGLE_CHECK(output->message_prototype != NULL)
+      GOOGLE_CHECK(output->message_info.prototype != nullptr)
           << "Extension factory's GetPrototype() returned NULL for extension: "
           << extension->full_name();
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+      output->message_info.parse_func =
+          output->message_info.prototype->_ParseFunc();
+#endif
     } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
       output->enum_validity_check.func = ValidateEnumUsingDescriptor;
       output->enum_validity_check.arg = extension->enum_type();
@@ -315,6 +322,7 @@
   }
 }
 
+
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 bool ExtensionSet::FindExtension(int wire_type, uint32 field,
                                  const Message* containing_type,
@@ -352,194 +360,16 @@
     return UnknownFieldParse(tag, parent, begin, end,
                              metadata->mutable_unknown_fields(), ctx);
   }
-  auto ptr = begin;
-  ParseClosure child;
-  int depth;
-  if (was_packed_on_wire) {
-    switch (extension.type) {
-#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
-  case WireFormatLite::TYPE_##UPPERCASE:                                     \
-    child = {                                                                \
-        internal::Packed##CPP_CAMELCASE##Parser,                             \
-        MutableRawRepeatedField(number, extension.type, extension.is_packed, \
-                                extension.descriptor)};                      \
-    goto length_delim
-      HANDLE_TYPE(INT32, Int32);
-      HANDLE_TYPE(INT64, Int64);
-      HANDLE_TYPE(UINT32, UInt32);
-      HANDLE_TYPE(UINT64, UInt64);
-      HANDLE_TYPE(SINT32, SInt32);
-      HANDLE_TYPE(SINT64, SInt64);
-      HANDLE_TYPE(FIXED32, Fixed32);
-      HANDLE_TYPE(FIXED64, Fixed64);
-      HANDLE_TYPE(SFIXED32, SFixed32);
-      HANDLE_TYPE(SFIXED64, SFixed64);
-      HANDLE_TYPE(FLOAT, Float);
-      HANDLE_TYPE(DOUBLE, Double);
-      HANDLE_TYPE(BOOL, Bool);
-#undef HANDLE_TYPE
+  return ParseFieldWithExtensionInfo(number, was_packed_on_wire, extension,
+                                     metadata, parent, begin, end, ctx);
+}
 
-      case WireFormatLite::TYPE_ENUM:
-        ctx->extra_parse_data().SetEnumValidatorArg(
-            extension.enum_validity_check.func,
-            extension.enum_validity_check.arg,
-            metadata->mutable_unknown_fields(), tag >> 3);
-        child = {
-            internal::PackedValidEnumParserArg,
-            MutableRawRepeatedField(number, extension.type, extension.is_packed,
-                                    extension.descriptor)};
-        goto length_delim;
-      case WireFormatLite::TYPE_STRING:
-      case WireFormatLite::TYPE_BYTES:
-      case WireFormatLite::TYPE_GROUP:
-      case WireFormatLite::TYPE_MESSAGE:
-        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
-        break;
-    }
-  } else {
-    switch (extension.type) {
-#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 value;                                                           \
-    ptr = Varint::Parse64(ptr, &value);                                     \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_VARINT_TYPE(INT32, Int32);
-      HANDLE_VARINT_TYPE(INT64, Int64);
-      HANDLE_VARINT_TYPE(UINT32, UInt32);
-      HANDLE_VARINT_TYPE(UINT64, UInt64);
-#undef HANDLE_VARINT_TYPE
-#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    uint64 val;                                                             \
-    ptr = Varint::Parse64(ptr, &val);                                       \
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
-    auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
-      HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
-#undef HANDLE_SVARINT_TYPE
-#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
-  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
-    CPPTYPE value;                                                          \
-    std::memcpy(&value, ptr, sizeof(CPPTYPE));                              \
-    ptr += sizeof(CPPTYPE);                                                 \
-    if (extension.is_repeated) {                                            \
-      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
-                         extension.is_packed, value, extension.descriptor); \
-    } else {                                                                \
-      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
-                         extension.descriptor);                             \
-    }                                                                       \
-  } break
-
-      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
-      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
-      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
-      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
-      HANDLE_FIXED_TYPE(FLOAT, Float, float);
-      HANDLE_FIXED_TYPE(DOUBLE, Double, double);
-      HANDLE_FIXED_TYPE(BOOL, Bool, bool);
-#undef HANDLE_FIXED_TYPE
-
-      case WireFormatLite::TYPE_ENUM: {
-        uint64 val;
-        ptr = Varint::Parse64(ptr, &val);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-        int value = val;
-
-        if (!extension.enum_validity_check.func(
-                extension.enum_validity_check.arg, value)) {
-          WriteVarint(number, val, metadata->mutable_unknown_fields());
-        } else if (extension.is_repeated) {
-          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
-                  extension.descriptor);
-        } else {
-          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
-                  extension.descriptor);
-        }
-        break;
-      }
-
-      case WireFormatLite::TYPE_BYTES:
-      case WireFormatLite::TYPE_STRING: {
-        string* value = extension.is_repeated
-                            ? AddString(number, WireFormatLite::TYPE_STRING,
-                                        extension.descriptor)
-                            : MutableString(number, WireFormatLite::TYPE_STRING,
-                                            extension.descriptor);
-        child = {StringParser, value};
-        goto length_delim;
-      }
-
-      case WireFormatLite::TYPE_GROUP: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
-                             *extension.message_prototype, extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
-                                 *extension.message_prototype,
-                                 extension.descriptor);
-        child = {value->_ParseFunc(), value};
-        bool ok = ctx->PrepareGroup(tag, &depth);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-        ptr = child(ptr, end, ctx);
-        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-        if (ctx->GroupContinues(depth)) goto group_continues;
-        break;
-      }
-
-      case WireFormatLite::TYPE_MESSAGE: {
-        MessageLite* value =
-            extension.is_repeated
-                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
-                             *extension.message_prototype, extension.descriptor)
-                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
-                                 *extension.message_prototype,
-                                 extension.descriptor);
-        child = {value->_ParseFunc(), value};
-        goto length_delim;
-      }
-    }
-  }
-
-  return std::make_pair(ptr, false);
-
-length_delim:
-  uint32 size;
-  ptr = Varint::Parse32Inline(ptr, &size);
-  GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-  if (size > end - ptr) goto len_delim_till_end;
-  {
-    auto newend = ptr + size;
-    bool ok = ctx->ParseExactRange(child, ptr, newend);
-    GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-    ptr = newend;
-  }
-  return std::make_pair(ptr, false);
-len_delim_till_end:
-  return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
-                        true);
-
-group_continues:
-  ctx->StoreGroup(parent, child, depth);
-  return std::make_pair(ptr, true);
+std::pair<const char*, bool> ExtensionSet::ParseFieldMaybeLazily(
+    uint64 tag, ParseClosure parent, const char* begin, const char* end,
+    const Message* containing_type,
+    internal::InternalMetadataWithArena* metadata,
+    internal::ParseContext* ctx) {
+  return ParseField(tag, parent, begin, end, containing_type, metadata, ctx);
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
@@ -576,13 +406,14 @@
         tag = *ptr++;
         GOOGLE_PROTOBUF_PARSER_ASSERT(tag ==
                                        WireFormatLite::kMessageSetMessageTag);
-        auto res = ParseField(static_cast<uint64>(type_id) * 8 + 2, parent, ptr,
-                              end, containing_type, metadata, ctx);
+        auto res =
+            ParseFieldMaybeLazily(static_cast<uint64>(type_id) * 8 + 2, parent,
+                                  ptr, end, containing_type, metadata, ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) break;
       } else {
         ExtensionInfo extension;
-        GeneratedExtensionFinder finder(containing_type);
         bool was_packed_on_wire;
         if (!FindExtension(2, type_id, containing_type, ctx, &extension,
                            &was_packed_on_wire)) {
@@ -593,18 +424,18 @@
         MessageLite* value =
             extension.is_repeated
                 ? AddMessage(type_id, WireFormatLite::TYPE_MESSAGE,
-                             *extension.message_prototype, extension.descriptor)
+                             *extension.message_info.prototype,
+                             extension.descriptor)
                 : MutableMessage(type_id, WireFormatLite::TYPE_MESSAGE,
-                                 *extension.message_prototype,
+                                 *extension.message_info.prototype,
                                  extension.descriptor);
-        ParseClosure parser = {value->_ParseFunc(), value};
-        StringPiece chunk(ctx->extra_parse_data().payload.data());
+        ParseClosure parser = {extension.message_info.parse_func, value};
+        StringPiece chunk(ctx->extra_parse_data().payload);
         bool ok = ctx->ParseExactRange(parser, chunk.begin(), chunk.end());
         GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
       }
     } else if (tag == WireFormatLite::kMessageSetItemEndTag) {
-      bool ok = ctx->ValidEndGroup(tag);
-      GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+      ctx->EndGroup(tag);
       break;
     } else if (tag == WireFormatLite::kMessageSetMessageTag) {
       uint32 size;
@@ -612,13 +443,12 @@
       GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       ParseClosure child = {internal::StringParser,
                             &ctx->extra_parse_data().payload};
-      if (size > end - ptr) {
+      if (size > end - ptr + internal::ParseContext::kSlopBytes) {
+        ctx->extra_parse_data().payload.clear();
         return ctx->StoreAndTailCall(ptr, end, parent, child, size);
       } else {
-        auto newend = ptr + size;
-        bool ok = ctx->ParseExactRange(child, ptr, newend);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
-        ptr = newend;
+        ctx->extra_parse_data().payload.assign(ptr, size);
+        ptr += size;
       }
     } else {
       ptr--;
@@ -627,6 +457,7 @@
       auto res =
           ParseField(tag, parent, ptr, end, containing_type, metadata, ctx);
       ptr = res.first;
+      GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
       if (res.second) break;
     }
   }
@@ -922,7 +753,6 @@
   return target;
 }
 
-
 bool ExtensionSet::ParseFieldMaybeLazily(
     int wire_type, int field_number, io::CodedInputStream* input,
     ExtensionFinder* extension_finder,
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
new file mode 100644
index 0000000..93a0558
--- /dev/null
+++ b/src/google/protobuf/extension_set_inl.h
@@ -0,0 +1,244 @@
+// 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_EXTENSION_SET_INL_H__
+#define GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
+
+#include <google/protobuf/extension_set.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+template <typename T>
+std::pair<const char*, bool> ExtensionSet::ParseFieldWithExtensionInfo(
+    int number, bool was_packed_on_wire, const ExtensionInfo& extension,
+    T* metadata, ParseClosure parent, const char* begin, const char* end,
+    internal::ParseContext* ctx) {
+  auto ptr = begin;
+  ParseClosure child;
+  int depth;
+  if (was_packed_on_wire) {
+    switch (extension.type) {
+#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE)                                \
+  case WireFormatLite::TYPE_##UPPERCASE:                                     \
+    child = {                                                                \
+        internal::Packed##CPP_CAMELCASE##Parser,                             \
+        MutableRawRepeatedField(number, extension.type, extension.is_packed, \
+                                extension.descriptor)};                      \
+    goto length_delim
+      HANDLE_TYPE(INT32, Int32);
+      HANDLE_TYPE(INT64, Int64);
+      HANDLE_TYPE(UINT32, UInt32);
+      HANDLE_TYPE(UINT64, UInt64);
+      HANDLE_TYPE(SINT32, SInt32);
+      HANDLE_TYPE(SINT64, SInt64);
+      HANDLE_TYPE(FIXED32, Fixed32);
+      HANDLE_TYPE(FIXED64, Fixed64);
+      HANDLE_TYPE(SFIXED32, SFixed32);
+      HANDLE_TYPE(SFIXED64, SFixed64);
+      HANDLE_TYPE(FLOAT, Float);
+      HANDLE_TYPE(DOUBLE, Double);
+      HANDLE_TYPE(BOOL, Bool);
+#undef HANDLE_TYPE
+
+      case WireFormatLite::TYPE_ENUM:
+        ctx->extra_parse_data().SetEnumValidatorArg(
+            extension.enum_validity_check.func,
+            extension.enum_validity_check.arg,
+            metadata->mutable_unknown_fields(), number);
+        child = {
+            internal::PackedValidEnumParserLiteArg,
+            MutableRawRepeatedField(number, extension.type, extension.is_packed,
+                                    extension.descriptor)};
+        goto length_delim;
+      case WireFormatLite::TYPE_STRING:
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_GROUP:
+      case WireFormatLite::TYPE_MESSAGE:
+        GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
+        break;
+    }
+  } else {
+    switch (extension.type) {
+#define HANDLE_VARINT_TYPE(UPPERCASE, CPP_CAMELCASE)                        \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64 value;                                                           \
+    ptr = Varint::Parse64(ptr, &value);                                     \
+    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_VARINT_TYPE(INT32, Int32);
+      HANDLE_VARINT_TYPE(INT64, Int64);
+      HANDLE_VARINT_TYPE(UINT32, UInt32);
+      HANDLE_VARINT_TYPE(UINT64, UInt64);
+#undef HANDLE_VARINT_TYPE
+#define HANDLE_SVARINT_TYPE(UPPERCASE, CPP_CAMELCASE, SIZE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    uint64 val;                                                             \
+    ptr = Varint::Parse64(ptr, &val);                                       \
+    GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));     \
+    auto value = WireFormatLite::ZigZagDecode##SIZE(val);                   \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_SVARINT_TYPE(SINT32, Int32, 32);
+      HANDLE_SVARINT_TYPE(SINT64, Int64, 64);
+#undef HANDLE_SVARINT_TYPE
+#define HANDLE_FIXED_TYPE(UPPERCASE, CPP_CAMELCASE, CPPTYPE)                \
+  case WireFormatLite::TYPE_##UPPERCASE: {                                  \
+    CPPTYPE value;                                                          \
+    std::memcpy(&value, ptr, sizeof(CPPTYPE));                              \
+    ptr += sizeof(CPPTYPE);                                                 \
+    if (extension.is_repeated) {                                            \
+      Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE,          \
+                         extension.is_packed, value, extension.descriptor); \
+    } else {                                                                \
+      Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value,   \
+                         extension.descriptor);                             \
+    }                                                                       \
+  } break
+
+      HANDLE_FIXED_TYPE(FIXED32, UInt32, uint32);
+      HANDLE_FIXED_TYPE(FIXED64, UInt64, uint64);
+      HANDLE_FIXED_TYPE(SFIXED32, Int32, int32);
+      HANDLE_FIXED_TYPE(SFIXED64, Int64, int64);
+      HANDLE_FIXED_TYPE(FLOAT, Float, float);
+      HANDLE_FIXED_TYPE(DOUBLE, Double, double);
+      HANDLE_FIXED_TYPE(BOOL, Bool, bool);
+#undef HANDLE_FIXED_TYPE
+
+      case WireFormatLite::TYPE_ENUM: {
+        uint64 val;
+        ptr = Varint::Parse64(ptr, &val);
+        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+        int value = val;
+
+        if (!extension.enum_validity_check.func(
+                extension.enum_validity_check.arg, value)) {
+          WriteVarint(number, val, metadata->mutable_unknown_fields());
+        } else if (extension.is_repeated) {
+          AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
+                  extension.descriptor);
+        } else {
+          SetEnum(number, WireFormatLite::TYPE_ENUM, value,
+                  extension.descriptor);
+        }
+        break;
+      }
+
+      case WireFormatLite::TYPE_BYTES:
+      case WireFormatLite::TYPE_STRING: {
+        std::string* value = extension.is_repeated
+                            ? AddString(number, WireFormatLite::TYPE_STRING,
+                                        extension.descriptor)
+                            : MutableString(number, WireFormatLite::TYPE_STRING,
+                                            extension.descriptor);
+        child = {StringParser, value};
+        goto length_delim;
+      }
+
+      case WireFormatLite::TYPE_GROUP: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_GROUP,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_GROUP,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        child = {extension.message_info.parse_func, value};
+        uint32 tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP;
+        auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
+        ptr = res.first;
+        GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+        if (res.second) {
+          GOOGLE_PROTOBUF_ASSERT_RETURN(
+              ctx->StoreGroup(parent, child, depth, tag),
+              std::make_pair(nullptr, true));
+          return std::make_pair(ptr, true);
+        }
+        break;
+      }
+
+      case WireFormatLite::TYPE_MESSAGE: {
+        MessageLite* value =
+            extension.is_repeated
+                ? AddMessage(number, WireFormatLite::TYPE_MESSAGE,
+                             *extension.message_info.prototype,
+                             extension.descriptor)
+                : MutableMessage(number, WireFormatLite::TYPE_MESSAGE,
+                                 *extension.message_info.prototype,
+                                 extension.descriptor);
+        child = {extension.message_info.parse_func, value};
+        goto length_delim;
+      }
+    }
+  }
+
+  return std::make_pair(ptr, false);
+
+length_delim:
+  uint32 size;
+  ptr = Varint::Parse32Inline(ptr, &size);
+  GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
+  if (size > end - ptr) goto len_delim_till_end;
+  {
+    auto newend = ptr + size;
+    bool ok = ctx->ParseExactRange(child, ptr, newend);
+    GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
+    ptr = newend;
+  }
+  return std::make_pair(ptr, false);
+len_delim_till_end:
+  return std::make_pair(ctx->StoreAndTailCall(ptr, end, parent, child, size),
+                        true);
+}
+#endif
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_INL_H__
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index 8b25299..af51c07 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -68,15 +68,17 @@
   file_level_metadata_google_2fprotobuf_2ffield_5fmask_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto, file_level_service_descriptors_google_2fprotobuf_2ffield_5fmask_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2ffield_5fmask_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto[] =
   "\n google/protobuf/field_mask.proto\022\017goog"
   "le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB"
   "\214\001\n\023com.google.protobufB\016FieldMaskProtoP"
   "\001Z9google.golang.org/genproto/protobuf/f"
   "ield_mask;field_mask\370\001\001\242\002\003GPB\252\002\036Google.P"
   "rotobuf.WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ffield_5fmask_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2ffield_5fmask_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2ffield_5fmask_2eproto,
   "google/protobuf/field_mask.proto", &assign_descriptors_table_google_2fprotobuf_2ffield_5fmask_2eproto, 230,
 };
 
@@ -170,10 +172,10 @@
   auto msg = static_cast<FieldMask*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -184,14 +186,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.FieldMask.paths");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-          ::std::string* str = msg->add_paths();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_paths();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 10 && (ptr += 1));
         break;
@@ -199,13 +204,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -216,7 +221,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index 5b8561d..14a62d4 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -125,7 +125,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FieldMask& from);
   void MergeFrom(const FieldMask& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/generated_message_table_driven.cc b/src/google/protobuf/generated_message_table_driven.cc
index d4450a6..b56f6b9 100644
--- a/src/google/protobuf/generated_message_table_driven.cc
+++ b/src/google/protobuf/generated_message_table_driven.cc
@@ -53,6 +53,10 @@
 }
 
 struct UnknownFieldHandler {
+  // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
+  // and conflating InternalMetaData into it, simplifying the template.
+  static constexpr bool IsLite() { return false; }
+
   static bool Skip(MessageLite* msg, const ParseTable& table,
                    io::CodedInputStream* input,
                    int tag) {
diff --git a/src/google/protobuf/generated_message_table_driven_lite.cc b/src/google/protobuf/generated_message_table_driven_lite.cc
index 83c8180..892a1e6 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.cc
+++ b/src/google/protobuf/generated_message_table_driven_lite.cc
@@ -50,6 +50,10 @@
 }
 
 struct UnknownFieldHandlerLite {
+  // TODO(mvels): consider renaming UnknownFieldHandler to (TableDrivenTraits?),
+  // and conflating InternalMetaData into it, simplifying the template.
+  static constexpr bool IsLite() { return true; }
+
   static bool Skip(MessageLite* msg, const ParseTable& table,
                    io::CodedInputStream* input,
                    int tag) {
diff --git a/src/google/protobuf/generated_message_table_driven_lite.h b/src/google/protobuf/generated_message_table_driven_lite.h
index 17e256a..ea3d439 100644
--- a/src/google/protobuf/generated_message_table_driven_lite.h
+++ b/src/google/protobuf/generated_message_table_driven_lite.h
@@ -222,16 +222,19 @@
   }
 }
 
-template <Cardinality cardinality, bool validate, StringType ctype>
+template <typename UnknownFieldHandler, Cardinality cardinality,
+          bool is_string_type, StringType ctype>
 static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
                                 Arena* arena, uint32* has_bits,
                                 uint32 has_bit_index, int64 offset,
                                 const void* default_ptr,
                                 const char* field_name) {
+  StringPiece utf8_string_data;
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  const char* sdata;
-  size_t size;
-#endif
+  constexpr bool kValidateUtf8 = is_string_type;
+#else
+  constexpr bool kValidateUtf8 = false;
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
 
   switch (ctype) {
     case StringType_INLINED: {
@@ -251,55 +254,54 @@
       }
       GOOGLE_DCHECK(s != nullptr);
       ::std::string* value = s->MutableNoArena(NULL);
-
       if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
         return false;
       }
-
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-      sdata = value->data();
-      size = value->size();
-#endif
+      utf8_string_data = *value;
       break;
     }
     case StringType_STRING: {
-      std::string* value;
       switch (cardinality) {
-        case Cardinality_SINGULAR:
-          // TODO(ckennelly): Is this optimal?
-          value =
-              MutableField<ArenaStringPtr>(msg, has_bits, has_bit_index, offset)
-                  ->Mutable(static_cast<const std::string*>(default_ptr), arena);
-          break;
-        case Cardinality_REPEATED:
-          value = AddField<std::string>(msg, offset);
-          break;
-        case Cardinality_ONEOF:
-          value = Raw<ArenaStringPtr>(msg, offset)
-                      ->Mutable(static_cast<const std::string*>(default_ptr), arena);
-          break;
+        case Cardinality_SINGULAR: {
+          ArenaStringPtr* field = MutableField<ArenaStringPtr>(
+              msg, has_bits, has_bit_index, offset);
+          std::string* value =
+              field->Mutable(static_cast<const std::string*>(default_ptr), arena);
+          if (PROTOBUF_PREDICT_FALSE(
+                  !WireFormatLite::ReadString(input, value))) {
+            return false;
+          }
+          utf8_string_data = field->Get();
+        } break;
+        case Cardinality_REPEATED: {
+          std::string* value = AddField<std::string>(msg, offset);
+          if (PROTOBUF_PREDICT_FALSE(
+                  !WireFormatLite::ReadString(input, value))) {
+            return false;
+          }
+          utf8_string_data = *value;
+        } break;
+        case Cardinality_ONEOF: {
+          ArenaStringPtr* field = Raw<ArenaStringPtr>(msg, offset);
+          std::string* value =
+              field->Mutable(static_cast<const std::string*>(default_ptr), arena);
+          if (PROTOBUF_PREDICT_FALSE(
+                  !WireFormatLite::ReadString(input, value))) {
+            return false;
+          }
+          utf8_string_data = field->Get();
+        } break;
       }
-      GOOGLE_DCHECK(value != nullptr);
-
-      if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
-        return false;
-      }
-
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-      sdata = value->data();
-      size = value->size();
-#endif
       break;
     }
   }
 
-#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
-  if (validate) {
-    WireFormatLite::VerifyUtf8String(sdata, size, WireFormatLite::PARSE,
-                                     field_name);
+  if (kValidateUtf8) {
+    // TODO(b/118759213): fail if proto3
+    WireFormatLite::VerifyUtf8String(utf8_string_data.data(),
+                                     utf8_string_data.length(),
+                                     WireFormatLite::PARSE, field_name);
   }
-#endif
-
   return true;
 }
 
@@ -371,9 +373,11 @@
   }
 };
 
-template <typename UnknownFieldHandler, typename InternalMetadata>
-bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
-                                     io::CodedInputStream* input) {
+template <typename UnknownFieldHandler, typename InternalMetadata,
+          uint32 kMaxTag>
+bool MergePartialFromCodedStreamInlined(MessageLite* msg,
+                                        const ParseTable& table,
+                                        io::CodedInputStream* input) {
   // We require that has_bits are present, as to avoid having to check for them
   // for every field.
   //
@@ -383,13 +387,12 @@
   GOOGLE_DCHECK(has_bits != NULL);
 
   while (true) {
-    uint32 tag = input->ReadTag();
-
+    uint32 tag = input->ReadTagWithCutoffNoLastTag(kMaxTag).first;
     const WireFormatLite::WireType wire_type =
         WireFormatLite::GetTagWireType(tag);
     const int field_number = WireFormatLite::GetTagFieldNumber(tag);
 
-    if (field_number > table.max_field_number) {
+    if (PROTOBUF_PREDICT_FALSE(field_number > table.max_field_number)) {
       // check for possible extensions
       if (UnknownFieldHandler::ParseExtension(msg, table, input, tag)) {
         // successfully parsed
@@ -476,16 +479,17 @@
         case WireFormatLite::TYPE_BYTES:
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case WireFormatLite::TYPE_STRING:
-#endif
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena =
               GetArena<InternalMetadata>(msg, table.arena_offset);
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
 
-          if (PROTOBUF_PREDICT_FALSE((
-                  !HandleString<Cardinality_SINGULAR, false, StringType_STRING>(
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 false, StringType_STRING>(
                       input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, NULL)))) {
+                      default_ptr, nullptr)))) {
             return false;
           }
           break;
@@ -493,16 +497,17 @@
         case TYPE_BYTES_INLINED:
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case TYPE_STRING_INLINED:
-#endif
+#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena =
               GetArena<InternalMetadata>(msg, table.arena_offset);
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
 
-          if (PROTOBUF_PREDICT_FALSE((!HandleString<Cardinality_SINGULAR, false,
-                                                    StringType_INLINED>(
-                  input, msg, arena, has_bits, presence_index, offset,
-                  default_ptr, NULL)))) {
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 false, StringType_INLINED>(
+                      input, msg, arena, has_bits, presence_index, offset,
+                      default_ptr, nullptr)))) {
             return false;
           }
           break;
@@ -510,7 +515,7 @@
         case WireFormatLite::TYPE_BYTES | kOneofMask:
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case WireFormatLite::TYPE_STRING | kOneofMask:
-#endif
+#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena =
               GetArena<InternalMetadata>(msg, table.arena_offset);
@@ -522,9 +527,10 @@
               offset, default_ptr);
 
           if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<Cardinality_ONEOF, false, StringType_STRING>(
-                      input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, NULL)))) {
+                  (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, false,
+                                 StringType_STRING>(input, msg, arena, has_bits,
+                                                    presence_index, offset,
+                                                    default_ptr, nullptr)))) {
             return false;
           }
           break;
@@ -534,17 +540,18 @@
 #ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
         case TYPE_STRING_INLINED | kRepeatedMask:
-#endif
+#endif  // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         {
           Arena* const arena =
               GetArena<InternalMetadata>(msg, table.arena_offset);
           const void* default_ptr =
               table.aux[field_number].strings.default_ptr;
 
-          if (PROTOBUF_PREDICT_FALSE((
-                  !HandleString<Cardinality_REPEATED, false, StringType_STRING>(
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
+                                 false, StringType_STRING>(
                       input, msg, arena, has_bits, presence_index, offset,
-                      default_ptr, NULL)))) {
+                      default_ptr, nullptr)))) {
             return false;
           }
           break;
@@ -557,7 +564,8 @@
           const char* field_name = table.aux[field_number].strings.field_name;
 
           if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<Cardinality_SINGULAR, true, StringType_STRING>(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 true, StringType_STRING>(
                       input, msg, arena, has_bits, presence_index, offset,
                       default_ptr, field_name)))) {
             return false;
@@ -572,7 +580,8 @@
           const char* field_name = table.aux[field_number].strings.field_name;
 
           if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<Cardinality_REPEATED, true, StringType_STRING>(
+                  (!HandleString<UnknownFieldHandler, Cardinality_REPEATED,
+                                 true, StringType_STRING>(
                       input, msg, arena, has_bits, presence_index, offset,
                       default_ptr, field_name)))) {
             return false;
@@ -591,14 +600,15 @@
               offset, default_ptr);
 
           if (PROTOBUF_PREDICT_FALSE(
-                  (!HandleString<Cardinality_ONEOF, true, StringType_STRING>(
+                  (!HandleString<UnknownFieldHandler, Cardinality_ONEOF, true,
+                                 StringType_STRING>(
                       input, msg, arena, has_bits, presence_index, offset,
                       default_ptr, field_name)))) {
             return false;
           }
           break;
         }
-#endif
+#endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
         case WireFormatLite::TYPE_ENUM: {
           if (PROTOBUF_PREDICT_FALSE(
                   (!HandleEnum<UnknownFieldHandler, InternalMetadata,
@@ -735,8 +745,9 @@
           const void* default_ptr = table.aux[field_number].strings.default_ptr;
           const char* field_name = table.aux[field_number].strings.field_name;
 
-          if (PROTOBUF_PREDICT_FALSE((
-                  !HandleString<Cardinality_SINGULAR, true, StringType_INLINED>(
+          if (PROTOBUF_PREDICT_FALSE(
+                  (!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
+                                 true, StringType_INLINED>(
                       input, msg, arena, has_bits, presence_index, offset,
                       default_ptr, field_name)))) {
             return false;
@@ -753,6 +764,7 @@
         }
         case 0: {
           // Done.
+          input->SetLastTag(tag);
           return true;
         }
         default:
@@ -847,6 +859,7 @@
     } else {
       if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
         // Must be the end of the message.
+        input->SetLastTag(tag);
         return true;
       }
 
@@ -865,6 +878,26 @@
   }
 }
 
+template <typename UnknownFieldHandler, typename InternalMetadata>
+bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,
+                                     io::CodedInputStream* input) {
+  // The main beneficial cutoff values are 1 and 2 byte tags.
+  // Instantiate calls with the appropriate upper tag range
+  if (table.max_field_number <= (0x7F >> 3)) {
+    return MergePartialFromCodedStreamInlined<UnknownFieldHandler,
+                                              InternalMetadata, 0x7F>(
+        msg, table, input);
+  } else if (table.max_field_number <= (0x3FFF >> 3)) {
+    return MergePartialFromCodedStreamInlined<UnknownFieldHandler,
+                                              InternalMetadata, 0x3FFF>(
+        msg, table, input);
+  } else {
+    return MergePartialFromCodedStreamInlined<
+        UnknownFieldHandler, InternalMetadata,
+        std::numeric_limits<uint32>::max()>(msg, table, input);
+  }
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index b9bbb26..ca6cc9c 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -46,6 +46,7 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/has_bits.h>
 #include <google/protobuf/implicit_weak_message.h>
 #include <google/protobuf/map_entry_lite.h>
@@ -53,6 +54,7 @@
 #include <google/protobuf/stubs/once.h>  // Add direct dep on port for pb.cc
 #include <google/protobuf/port.h>
 #include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/strutil.h>
 
 #include <google/protobuf/port_def.inc>
 
@@ -60,11 +62,6 @@
 #error "You cannot SWIG proto headers"
 #endif
 
-#if GOOGLE_PROTOBUF_ENABLE_MOMI_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
-
 namespace google {
 namespace protobuf {
 
@@ -354,6 +351,32 @@
   OnShutdownRun(DestroyString, ptr);
 }
 
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
+inline void InlineGreedyStringParser(std::string* str, const char* begin, int size,
+                               ParseContext*) {
+  str->assign(begin, size);
+}
+
+
+inline bool StringCheck(const char* begin, int size, ParseContext* ctx) {
+  return true;
+}
+
+inline bool StringCheckUTF8(const char* begin, int size, ParseContext* ctx) {
+  return VerifyUTF8(StringPiece(begin, size), ctx);
+}
+
+inline bool StringCheckUTF8Verify(const char* begin, int size,
+                                  ParseContext* ctx) {
+#ifndef NDEBUG
+  VerifyUTF8(StringPiece(begin, size), ctx);
+#endif
+  return true;
+}
+
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/implicit_weak_message.cc b/src/google/protobuf/implicit_weak_message.cc
index f924842..b26f441 100644
--- a/src/google/protobuf/implicit_weak_message.cc
+++ b/src/google/protobuf/implicit_weak_message.cc
@@ -30,15 +30,13 @@
 
 #include <google/protobuf/implicit_weak_message.h>
 
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite_inl.h>
 
 #include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index e893316..477b368 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -235,10 +235,10 @@
     TestUtilLite::ExpectClear(message);
     TestUtilLite::SetAllFields(&message);
     data = message.SerializeAsString();
-    empty_message.ParseFromString(data);
+    ASSERT_TRUE(empty_message.ParseFromString(data));
     data.clear();
     data = empty_message.SerializeAsString();
-    message2.ParseFromString(data);
+    EXPECT_TRUE(message2.ParseFromString(data));
     data = message2.SerializeAsString();
     TestUtilLite::ExpectAllFieldsSet(message2);
     message.Clear();
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 98b2aca..08a02ac 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -35,6 +35,7 @@
 #include <string>
 
 #include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/arenastring.h>
 #include <google/protobuf/map.h>
@@ -44,10 +45,6 @@
 #include <google/protobuf/wire_format_lite_inl.h>
 
 #include <google/protobuf/port_def.inc>
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
@@ -403,7 +400,7 @@
                                 Metadata* metadata,
                                 bool (*validate_enum)(int)) {
       io::CodedInputStream input(reinterpret_cast<const uint8*>(begin),
-                                 end - begin);
+                                 static_cast<int>(end - begin));
       auto entry = NewEntry();
       // TODO(gerbens) implement _InternalParse for maps. We can't use
       // ParseFromString as this will call _InternalParse
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index 2ce54cb..7c10d67 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -162,6 +162,39 @@
   return iter != map.end();
 }
 
+void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
+  const FieldDescriptor* val_des =
+      default_entry_->GetDescriptor()->FindFieldByName("value");
+  map_val->SetType(val_des->cpp_type());
+  // Allocate memory for the MapValueRef, and initialize to
+  // default value.
+  switch (val_des->cpp_type()) {
+#define HANDLE_TYPE(CPPTYPE, TYPE)                      \
+    case FieldDescriptor::CPPTYPE_##CPPTYPE: {          \
+      TYPE* value = new TYPE();                         \
+      map_val->SetValue(value);                          \
+      break;                                            \
+    }
+    HANDLE_TYPE(INT32, int32);
+    HANDLE_TYPE(INT64, int64);
+    HANDLE_TYPE(UINT32, uint32);
+    HANDLE_TYPE(UINT64, uint64);
+    HANDLE_TYPE(DOUBLE, double);
+    HANDLE_TYPE(FLOAT, float);
+    HANDLE_TYPE(BOOL, bool);
+    HANDLE_TYPE(STRING, string);
+    HANDLE_TYPE(ENUM, int32);
+#undef HANDLE_TYPE
+    case FieldDescriptor::CPPTYPE_MESSAGE: {
+      const Message& message = default_entry_->GetReflection()->GetMessage(
+          *default_entry_, val_des);
+      Message* value = message.New();
+      map_val->SetValue(value);
+      break;
+    }
+  }
+}
+
 bool DynamicMapField::InsertOrLookupMapValue(
     const MapKey& map_key, MapValueRef* val) {
   // Always use mutable map because users may change the map value by
@@ -169,38 +202,8 @@
   Map<MapKey, MapValueRef>* map = MutableMap();
   Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
   if (iter == map->end()) {
-    // Insert
-    MapValueRef& map_val = (*map)[map_key];
-    const FieldDescriptor* val_des =
-        default_entry_->GetDescriptor()->FindFieldByName("value");
-    map_val.SetType(val_des->cpp_type());
-    // Allocate memory for the inserted MapValueRef, and initialize to
-    // default value.
-    switch (val_des->cpp_type()) {
-#define HANDLE_TYPE(CPPTYPE, TYPE)           \
-  case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
-    TYPE* value = new TYPE();                \
-    map_val.SetValue(value);                 \
-    break;                                   \
-  }
-      HANDLE_TYPE(INT32, int32);
-      HANDLE_TYPE(INT64, int64);
-      HANDLE_TYPE(UINT32, uint32);
-      HANDLE_TYPE(UINT64, uint64);
-      HANDLE_TYPE(DOUBLE, double);
-      HANDLE_TYPE(FLOAT, float);
-      HANDLE_TYPE(BOOL, bool);
-      HANDLE_TYPE(STRING, string);
-      HANDLE_TYPE(ENUM, int32);
-#undef HANDLE_TYPE
-      case FieldDescriptor::CPPTYPE_MESSAGE: {
-        const Message& message = default_entry_->GetReflection()->GetMessage(
-            *default_entry_, val_des);
-        Message* value = message.New();
-        map_val.SetValue(value);
-        break;
-      }
-    }
+    MapValueRef& map_val = map_[map_key];
+    AllocateMapValue(&map_val);
     val->CopyFrom(map_val);
     return true;
   }
@@ -243,6 +246,72 @@
   map_iter->value_.CopyFrom(iter->second);
 }
 
+void DynamicMapField::MergeFrom(const MapFieldBase& other) {
+  GOOGLE_DCHECK(IsMapValid() && other.IsMapValid());
+  Map<MapKey, MapValueRef>* map = MutableMap();
+  const DynamicMapField& other_field =
+      reinterpret_cast<const DynamicMapField&>(other);
+  for (typename Map<MapKey, MapValueRef>::const_iterator other_it =
+           other_field.map_.begin(); other_it != other_field.map_.end();
+       ++other_it) {
+    Map<MapKey, MapValueRef>::iterator iter = map->find(other_it->first);
+    MapValueRef* map_val;
+    if (iter == map->end()) {
+      map_val = &map_[other_it->first];
+      AllocateMapValue(map_val);
+    } else {
+      map_val = &iter->second;
+    }
+
+    // Copy map value
+    const FieldDescriptor* field_descriptor =
+        default_entry_->GetDescriptor()->FindFieldByName("value");
+    switch (field_descriptor->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32: {
+        map_val->SetInt32Value(other_it->second.GetInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+        map_val->SetInt64Value(other_it->second.GetInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+        map_val->SetUInt32Value(other_it->second.GetUInt32Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+        map_val->SetUInt64Value(other_it->second.GetUInt64Value());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_FLOAT: {
+        map_val->SetFloatValue(other_it->second.GetFloatValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_DOUBLE: {
+        map_val->SetDoubleValue(other_it->second.GetDoubleValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_BOOL: {
+        map_val->SetBoolValue(other_it->second.GetBoolValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+        map_val->SetStringValue(other_it->second.GetStringValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        map_val->SetEnumValue(other_it->second.GetEnumValue());
+        break;
+      }
+      case FieldDescriptor::CPPTYPE_MESSAGE: {
+        map_val->MutableMessageValue()->CopyFrom(
+            other_it->second.GetMessageValue());
+        break;
+      }
+    }
+  }
+}
+
 void DynamicMapField::Swap(MapFieldBase* other) {
   DynamicMapField* other_field = down_cast<DynamicMapField*>(other);
   std::swap(this->MapFieldBase::repeated_field_, other_field->repeated_field_);
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 38dd35d..bba5d8a 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -103,6 +103,7 @@
                              const MapIterator& b) const = 0;
   virtual void MapBegin(MapIterator* map_iter) const = 0;
   virtual void MapEnd(MapIterator* map_iter) const = 0;
+  virtual void MergeFrom(const MapFieldBase& other) = 0;
   virtual void Swap(MapFieldBase* other) = 0;
   // Sync Map with repeated field and returns the size of map.
   virtual int size() const = 0;
@@ -270,7 +271,7 @@
   // Convenient methods for generated message implementation.
   int size() const override;
   void Clear();
-  void MergeFrom(const MapField& other);
+  void MergeFrom(const MapFieldBase& other) override;
   void Swap(MapFieldBase* other) override;
 
   // Used in the implementation of parsing. Caller should take the ownership iff
@@ -326,6 +327,7 @@
   bool ContainsMapKey(const MapKey& map_key) const override;
   bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
   bool DeleteMapValue(const MapKey& map_key) override;
+  void MergeFrom(const MapFieldBase& other) override;
   void Swap(MapFieldBase* other) override;
 
   const Map<MapKey, MapValueRef>& GetMap() const override;
@@ -337,6 +339,8 @@
   Map<MapKey, MapValueRef> map_;
   const Message* default_entry_;
 
+  void AllocateMapValue(MapValueRef* map_val);
+
   // Implements MapFieldBase
   void SyncRepeatedFieldWithMapNoLock() const override;
   void SyncMapWithRepeatedFieldNoLock() const override;
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index 0e78342..73c16ed 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -242,10 +242,11 @@
           WireFormatLite::FieldType kKeyFieldType,
           WireFormatLite::FieldType kValueFieldType, int default_enum_value>
 void MapField<Derived, Key, T, kKeyFieldType, kValueFieldType,
-              default_enum_value>::MergeFrom(const MapField& other) {
+              default_enum_value>::MergeFrom(const MapFieldBase& other) {
   MapFieldBase::SyncMapWithRepeatedField();
-  other.SyncMapWithRepeatedField();
-  impl_.MergeFrom(other.impl_);
+  const MapField& other_field = static_cast<const MapField&>(other);
+  other_field.SyncMapWithRepeatedField();
+  impl_.MergeFrom(other_field.impl_);
   MapFieldBase::SetMapDirty();
 }
 
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index dcfcca7..ae7bd58 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -96,6 +96,7 @@
   int size() const { return 0; }
   void MapBegin(MapIterator* map_iter) const {}
   void MapEnd(MapIterator* map_iter) const {}
+  void MergeFrom(const MapFieldBase& other) override {}
   void Swap(MapFieldBase* other) {}
   void InitializeIterator(MapIterator* map_iter) const {}
   void DeleteIterator(MapIterator* map_iter) const {}
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 080b9df..41d9c37 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -2032,6 +2032,31 @@
   MapTestUtil::ExpectMapFieldsSet(message2);
 }
 
+TEST(GeneratedMapFieldTest, DynamicMessageMergeFromDynamicMessage) {
+  // Construct two dynamic message and sets via map reflection.
+  DynamicMessageFactory factory;
+  std::unique_ptr<Message> message1;
+  message1.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+  MapReflectionTester reflection_tester(
+      unittest::TestMap::descriptor());
+  reflection_tester.SetMapFieldsViaMapReflection(message1.get());
+
+  std::unique_ptr<Message> message2;
+  message2.reset(
+      factory.GetPrototype(unittest::TestMap::descriptor())->New());
+  reflection_tester.SetMapFieldsViaMapReflection(message2.get());
+
+  message2->MergeFrom(*message1);
+
+  // Test MergeFrom does not sync to repeated fields and
+  // there is no duplicate keys in text format.
+  string output1, output2;
+  TextFormat::PrintToString(*message1, &output1);
+  TextFormat::PrintToString(*message2, &output2);
+  EXPECT_EQ(output1, output2);
+}
+
 TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) {
   // Test copying to a DynamicMessage, which must fall back to using reflection.
   unittest::TestMap message2;
@@ -2097,6 +2122,18 @@
 
   message1.MergeFrom(message2);
   MapTestUtil::ExpectMapFieldsSet(message1);
+
+  // Test reflection MergeFrom does not sync to repeated field
+  // and there is no duplicated keys.
+  MapTestUtil::SetMapFields(&message1);
+  MapTestUtil::SetMapFields(&message2);
+
+  message2.MergeFrom(message1);
+
+  string output1, output2;
+  TextFormat::PrintToString(message1, &output1);
+  TextFormat::PrintToString(message2, &output2);
+  EXPECT_EQ(output1, output2);
 }
 
 TEST(GeneratedMapFieldTest, MergeFromMessageMap) {
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 5a9acaf..fc307f0 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -43,6 +43,7 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/reflection_internal.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -51,6 +52,7 @@
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
 #include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/stubs/strutil.h>
@@ -309,15 +311,12 @@
 }
 
 ParseClosure GetLenDelim(int field_number, const FieldDescriptor* field,
-                         Message* msg, UnknownFieldSet* unknown,
-                         const Reflection* reflection,
+                         Message* msg, const Reflection* reflection,
                          internal::ParseContext* ctx) {
-  if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) !=
-                              WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
-    if (field && field->is_packable()) {
-      return GetPackedField(field, msg, reflection, ctx);
-    }
-    return {internal::StringParser, unknown->AddLengthDelimited(field_number)};
+  if (WireFormat::WireTypeForFieldType(field->type()) !=
+      WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+    ABSL_ASSERT(field->is_packable());
+    return GetPackedField(field, msg, reflection, ctx);
   }
   enum { kNone = 0, kVerify, kStrict } utf8_level = kNone;
   internal::ParseFunc string_parsers[] = {internal::StringParser,
@@ -402,77 +401,8 @@
   }
 }
 
-const char* ReflectiveParseMessageSetItem(const char* begin, const char* end,
-                                          void* object,
-                                          internal::ParseContext* ctx) {
-  ParseClosure child;
-  auto msg = static_cast<Message*>(object);
-  auto reflection = msg->GetReflection();
-  uint32 size;
-  auto ptr = begin;
-  while (ptr < end) {
-    uint32 tag = *ptr++;
-    if (tag == WireFormatLite::kMessageSetTypeIdTag) {
-      uint32 type_id;
-      ptr = Varint::Parse32(ptr, &type_id);
-      if (!ptr) goto error;
-
-      auto field = reflection->FindKnownExtensionByNumber(type_id);
-
-      if (ctx->extra_parse_data().payload.empty()) {
-        tag = *ptr++;
-        if (tag == WireFormatLite::kMessageSetMessageTag) {
-          ptr = Varint::Parse32Inline(ptr, &size);
-          if (!ptr) goto error;
-          child = GetLenDelim(type_id * 8 + 2, field, msg,
-                              reflection->MutableUnknownFields(msg), reflection,
-                              ctx);
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
-          ptr = newend;
-        } else {
-          goto error;
-        }
-      } else {
-        GOOGLE_LOG(FATAL) << "Wrong order";
-      }
-    } else if (tag == WireFormatLite::kMessageSetItemEndTag) {
-      if (!ctx->ValidEndGroup(tag)) goto error;
-      break;
-    } else if (tag == WireFormatLite::kMessageSetMessageTag) {
-      uint32 size;
-      ptr = Varint::Parse32Inline(ptr, &size);
-      if (!ptr) goto error;
-      child = {internal::StringParser, &ctx->extra_parse_data().payload};
-      if (size > end - ptr) goto len_delim_till_end;
-      auto newend = ptr + size;
-      if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
-      ptr = newend;
-    } else {
-      GOOGLE_LOG(FATAL) << "Unknown message set item tag";
-    }
-  }
-  return ptr;
-error:
-  return nullptr;
-len_delim_till_end:
-  return ctx->StoreAndTailCall(ptr, end, {ReflectiveParseMessageSetItem, msg},
-                               child, size);
-}
-
 ParseClosure GetGroup(int field_number, const FieldDescriptor* field,
-                      Message* msg, UnknownFieldSet* unknown,
-                      const Reflection* reflection) {
-  if (field == nullptr && field_number == 1 &&
-      msg->GetDescriptor()->options().message_set_wire_format()) {
-    return {ReflectiveParseMessageSetItem, msg};
-  }
-  if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) !=
-                              WireFormatLite::WIRETYPE_START_GROUP) {
-    return {internal::UnknownGroupParse, unknown->AddGroup(field_number)};
-  }
-
+                      Message* msg, const Reflection* reflection) {
   Message* object;
   if (field->is_repeated()) {
     object = reflection->AddMessage(msg, field, nullptr);
@@ -484,125 +414,147 @@
 
 const char* Message::_InternalParse(const char* begin, const char* end,
                                     void* object, internal::ParseContext* ctx) {
-  auto msg = static_cast<Message*>(object);
-  const Descriptor* descriptor = msg->GetDescriptor();
-  const Reflection* reflection = msg->GetReflection();
-  auto unknown = reflection->MutableUnknownFields(msg);
-  GOOGLE_DCHECK(descriptor);
-  GOOGLE_DCHECK(reflection);
+  class ReflectiveFieldParser {
+   public:
+    ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx)
+        : ReflectiveFieldParser(msg, ctx, false) {}
 
-  GOOGLE_DCHECK(begin <= end);
-  uint32 size;
-  internal::ParseFunc parser_till_end;
-  uint32 tag;
-  int depth;
-  auto ptr = begin;
-  while (ptr < end) {
-    ptr = Varint::Parse32Inline(ptr, &tag);
-    if (ptr == nullptr) return nullptr;
-    if (tag == 0) {
-      if (ctx->ValidEndGroup(0)) return ptr;
-      return nullptr;
-    }
-    if ((tag >> 3) == 0) return nullptr;
-    const FieldDescriptor* field = nullptr;
-
-    int field_number = WireFormatLite::GetTagFieldNumber(tag);
-    field = descriptor->FindFieldByNumber(field_number);
-
-    // If that failed, check if the field is an extension.
-    if (field == nullptr && descriptor->IsExtensionNumber(field_number)) {
-      auto pool = ctx->extra_parse_data().pool;
-      if (pool == NULL) {
-        field = reflection->FindKnownExtensionByNumber(field_number);
+    void AddVarint(uint32 num, uint64 value) {
+      if (is_item_ && num == 2) {
+        if (!ctx_->extra_parse_data().payload.empty()) {
+          auto field = Field(value, 2);
+          if (field && field->message_type()) {
+            auto child = reflection_->MutableMessage(msg_, field);
+            // TODO(gerbens) signal error
+            child->ParsePartialFromString(ctx_->extra_parse_data().payload);
+          } else {
+            MutableUnknown()->AddLengthDelimited(value)->swap(
+                ctx_->extra_parse_data().payload);
+          }
+          return;
+        }
+        ctx_->extra_parse_data().field_number = value;
+        return;
+      }
+      auto field = Field(num, 0);
+      if (field) {
+        SetField(value, field, msg_, reflection_);
       } else {
-        field = pool->FindExtensionByNumber(descriptor, field_number);
+        MutableUnknown()->AddVarint(num, value);
+      }
+    }
+    void AddFixed64(uint32 num, uint64 value) {
+      auto field = Field(num, 1);
+      if (field) {
+        SetField(value, field, msg_, reflection_);
+      } else {
+        MutableUnknown()->AddFixed64(num, value);
+      }
+    }
+    ParseClosure AddLengthDelimited(uint32 num, uint32) {
+      if (is_item_ && num == 3) {
+        int type_id = ctx_->extra_parse_data().field_number;
+        if (type_id == 0) {
+          return {internal::StringParser, &ctx_->extra_parse_data().payload};
+        }
+        ctx_->extra_parse_data().field_number = 0;
+        num = type_id;
+      }
+      auto field = Field(num, 2);
+      if (field) {
+        return GetLenDelim(num, field, msg_, reflection_, ctx_);
+      } else {
+        return {internal::StringParser,
+                MutableUnknown()->AddLengthDelimited(num)};
+      }
+    }
+    ParseClosure StartGroup(uint32 num) {
+      if (!is_item_ && descriptor_->options().message_set_wire_format() &&
+          num == 1) {
+        ctx_->extra_parse_data().payload.clear();
+        ctx_->extra_parse_data().field_number = 0;
+        return {ItemParser, msg_};
+      }
+      auto field = Field(num, 3);
+      if (field) {
+        return GetGroup(num, field, msg_, reflection_);
+      } else {
+        return {internal::UnknownGroupParse, MutableUnknown()->AddGroup(num)};
+      }
+    }
+    void EndGroup(uint32 num) {}
+    void AddFixed32(uint32 num, uint32 value) {
+      auto field = Field(num, 5);
+      if (field) {
+        SetField(value, field, msg_, reflection_);
+      } else {
+        MutableUnknown()->AddFixed32(num, value);
       }
     }
 
-    switch (tag & 7) {
-      case 0: {
-        uint64 val;
-        ptr = Varint::Parse64(ptr, &val);
-        if (!ptr) goto error;
-        if (field == nullptr ||
-            WireFormat::WireTypeForFieldType(field->type()) != 0) {
-          unknown->AddVarint(field_number, val);
-          break;
-        }
-        SetField(val, field, msg, reflection);
-        break;
-      }
-      case 1: {
-        uint64 val = UNALIGNED_LOAD64(ptr);
-        ptr = ptr + 8;
-        if (field == nullptr ||
-            WireFormat::WireTypeForFieldType(field->type()) != 1) {
-          unknown->AddFixed64(field_number, val);
-          break;
-        }
-        SetField(val, field, msg, reflection);
-        break;
-      }
-      case 2: {
-        ptr = Varint::Parse32Inline(ptr, &size);
-        if (!ptr) goto error;
-        ParseClosure child =
-            GetLenDelim(field_number, field, msg, unknown, reflection, ctx);
-        parser_till_end = child.func;
-        object = child.object;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (!ctx->ParseExactRange(child, ptr, newend)) goto error;
-        ptr = newend;
-        break;
-      }
-      case 3: {
-        if (!ctx->PrepareGroup(tag, &depth)) goto error;
+   private:
+    Message* msg_;
+    const Descriptor* descriptor_;
+    const Reflection* reflection_;
+    internal::ParseContext* ctx_;
+    UnknownFieldSet* unknown_ = nullptr;
+    bool is_item_ = false;
 
-        ParseClosure child =
-            GetGroup(field_number, field, msg, unknown, reflection);
-        parser_till_end = child.func;
-        object = child.object;
-
-        if (ptr < end) ptr = child(ptr, end, ctx);
-        if (!ptr) goto error;
-        if (ctx->GroupContinues(depth)) goto group_continues;
-        break;
-      }
-      case 4: {
-        if (!ctx->ValidEndGroup(tag)) goto error;
-        return ptr;
-      }
-      case 5: {
-        uint32 val = UNALIGNED_LOAD32(ptr);
-        ptr = ptr + 4;
-        if (field == nullptr ||
-            WireFormat::WireTypeForFieldType(field->type()) != 5) {
-          unknown->AddFixed32(field_number, val);
-          break;
-        }
-        SetField(val, field, msg, reflection);
-        break;
-      }
-      default:
-        goto error;
+    ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx,
+                          bool is_item)
+        : msg_(msg),
+          descriptor_(msg->GetDescriptor()),
+          reflection_(msg->GetReflection()),
+          ctx_(ctx),
+          is_item_(is_item) {
+      GOOGLE_CHECK(descriptor_) << typeid(*this).name();
+      GOOGLE_CHECK(reflection_) << descriptor_->name() << " " << typeid(*this).name();
     }
-  }
-  return ptr;
-error:
-  return nullptr;
-len_delim_till_end:
-  // Length delimited field crosses end
-  return ctx->StoreAndTailCall(ptr, end, {Message::_InternalParse, msg},
-                               {parser_till_end, object}, size);
-group_continues:
-  GOOGLE_DCHECK(ptr >= end);
-  // Group crossed end and must be continued. Either this a parse failure
-  // or we need to resume on the next chunk and thus save the state.
-  ctx->StoreGroup({Message::_InternalParse, msg}, {parser_till_end, object},
-                  depth);
-  return ptr;
+
+    const FieldDescriptor* Field(int num, int wire_type) {
+      auto field = descriptor_->FindFieldByNumber(num);
+
+      // If that failed, check if the field is an extension.
+      if (field == nullptr && descriptor_->IsExtensionNumber(num)) {
+        const DescriptorPool* pool = ctx_->extra_parse_data().pool;
+        if (pool == NULL) {
+          field = reflection_->FindKnownExtensionByNumber(num);
+        } else {
+          field = pool->FindExtensionByNumber(descriptor_, num);
+        }
+      }
+      if (field == nullptr) return nullptr;
+
+      if (internal::WireFormat::WireTypeForFieldType(field->type()) !=
+          wire_type) {
+        if (field->is_packable()) {
+          if (wire_type ==
+              internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+            return field;
+          }
+        }
+        return nullptr;
+      }
+      return field;
+    }
+
+    UnknownFieldSet* MutableUnknown() {
+      if (unknown_) return unknown_;
+      return unknown_ = reflection_->MutableUnknownFields(msg_);
+    }
+
+    static const char* ItemParser(const char* begin, const char* end,
+                                  void* object, internal::ParseContext* ctx) {
+      auto msg = static_cast<Message*>(object);
+      ReflectiveFieldParser field_parser(msg, ctx, true);
+      return internal::WireFormatParser({ItemParser, object}, field_parser,
+                                        begin, end, ctx);
+    }
+  };
+
+  ReflectiveFieldParser field_parser(static_cast<Message*>(object), ctx);
+  return internal::WireFormatParser({_InternalParse, object}, field_parser,
+                                    begin, end, ctx);
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 9f44132..0734df5 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -201,7 +201,7 @@
 class PROTOBUF_EXPORT Message : public MessageLite {
  public:
   inline Message() {}
-  virtual ~Message() {}
+  ~Message() override {}
 
   // Basic Operations ------------------------------------------------
 
@@ -436,15 +436,12 @@
 
   // Get the UnknownFieldSet for the message.  This contains fields which
   // were seen when the Message was parsed but were not recognized according
-  // to the Message's definition. For proto3 protos, this method will always
-  // return an empty UnknownFieldSet.
+  // to the Message's definition.
   virtual const UnknownFieldSet& GetUnknownFields(
       const Message& message) const = 0;
   // Get a mutable pointer to the UnknownFieldSet for the message.  This
   // contains fields which were seen when the Message was parsed but were not
-  // recognized according to the Message's definition. For proto3 protos, this
-  // method will return a valid mutable UnknownFieldSet pointer but modifying
-  // it won't affect the serialized bytes of the message.
+  // recognized according to the Message's definition.
   virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
 
   // Estimate the amount of memory used by the message object.
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 01bb0d3..8edae78 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -39,22 +39,19 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 #include <google/protobuf/port_def.inc>
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#include "util/utf8/public/unilib.h"
-#include "util/utf8/public/unilib_utf8_utils.h"
-#endif
-
 namespace google {
 namespace protobuf {
 
@@ -106,376 +103,149 @@
   return result;
 }
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-// This is wrapper to turn a ZeroCopyInputStream (ZCIS) into a
-// InputStreamWithOverlap. This is done by copying data around the seams,
-// hence the name EpsCopyInputStream, pictorially if ZCIS presents a stream
-// in chunks like so
-// [---------------------------------------------------------------]
-// [---------------------] chunk 1
-//                      [----------------------------] chunk 2
-//                                          chunk 3 [--------------]
-// where '-' depicts bytes of the stream or chunks vertically alligned with the
-// corresponding bytes between stream and chunk.
-//
-// This class will convert this into chunks
-// [-----------------....] chunk 1
-//                  [----....] patch
-//                      [------------------------....] chunk 2
-//                                              [----....] patch
-//                                          chunk 3 [----------....]
-//                                                      patch [----****]
-// by using a fixed size buffer to patch over the seams. This requires
-// copying of an "epsilon" neighboorhood around the seams. In the picture above
-// dots mean bytes beyond the end of the new chunks. Each chunk is kSlopBytes
-// smalller as its original chunk (above depicted as 4 dots) and the number of
-// of chunks is doubled because each seam in the original stream introduces a
-// new patch.
-//
-// The algorithm is simple but not entirely trivial. Two complications arise
-// 1) The original chunk could be less than kSlopBytes. Hence we can't simply
-// chop the last kSlopBytes of a chunk.
-// 2) We need to leave the underlying CodedInputStream (CIS) precisely at the
-// last byte read in the parse. In most cases a parse ends on a limit or end of
-// the ZeroCopyInputStream, which is not problematic because CIS will never give
-// us data beyond that. But the parse can end on a 0 end tag or an end group.
-// If that happens in the first kSlopBytes of the patch (which are copied
-// from the previous buffer) the CIS has already moved to the next chunk to
-// copy the remaining bytes of the patch buffer. There exist no API to rollback
-// to a previous buffer.
-//
-// We model this as a state machine. A call to get the next chunk either returns
-// an original chunk except the last kSlopBytes or it has to copy the last
-// kSlopBytes of the current chunk to the patch buffer and copy the first
-// kSlopBytes of the next chunk to the end of the patch buffer.
-//
-// In order to deal with problem 1, we need to deal with the case that a new
-// chunk can be less or equal than kSlopBytes big. We can just copy the chunk
-// to the end and return (buffer, chunk->size). Pictorially
-// [--------] chunk 1
-//         [--] chunk 2
-//           [---] chunk 3
-// will become
-// [----....] chunk 1
-//     [--....] patch (not full range of the buffer, only two hyphens)
-//         [--] chunk 2 (too small so never returned as buffer)
-//       [---....] patch (not full range of the buffer, only three hyphens)
-//           [---] chunk 3 (too small so never returned as buffer)
-//          [----****] patch (full range, last bytes are garbage)
-// Because of this the source (the dots in above) can overlap with the
-// destination buffer and so we have to use memmove.
-//
-// To solve problem 2, we verify after copying the last kSlopBytes the parse
-// won't end before we continue to get the next chunk.
-template <int kSlopBytes>
-class EpsCopyInputStream {
- public:
-  EpsCopyInputStream(io::CodedInputStream* input) : input_(input) {}
-  ~EpsCopyInputStream() {
-    ABSL_ASSERT(skip_ >= 0);
-    input_->Skip(skip_);
-  }
-
-  template <typename EnsureNotEnd>
-  StringPiece SafeNextWithOverlap(const EnsureNotEnd& ensure_not_end) {
-    switch (next_state_) {
-      case kEOS:
-        // End of stream
-        return nullptr;
-      case kChunk:
-        // chunk_ contains a buffer of sufficient size (> kSlopBytes).
-        // To parse the last kSlopBytes we need to copy the bytes into the
-        // buffer. Hence we set,
-        next_state_ = kBuffer;
-        skip_ = chunk_.size() - kSlopBytes;
-        return {chunk_.begin(), chunk_.size() - kSlopBytes};
-      case kBuffer: {
-        // We have to parse the last kSlopBytes of chunk_, which could alias
-        // buffer_ so we have to memmove.
-        std::memmove(buffer_, chunk_.end() - kSlopBytes, kSlopBytes);
-        skip_ += kSlopBytes;
-        // We need to fill in the other half of buffer_ with the start of the
-        // next chunk. So we need to continue to the next buffer in the ZCIS,
-        // which makes it impossible to rollback to the current buffer :(
-        // We need to verify this won't happen.
-        if (!ensure_not_end(buffer_, kSlopBytes)) {
-          // We are guaranteed to exit in this interval.
-          next_state_ = kEOS;
-          return {buffer_, kSlopBytes};
-        }
-        chunk_ = GetChunk();
-        auto size = chunk_.size();
-        if (size > kSlopBytes) {
-          next_state_ = kChunk;
-          std::memcpy(buffer_ + kSlopBytes, chunk_.begin(), kSlopBytes);
-          return {buffer_, kSlopBytes};
-        } else if (size == 0) {
-          next_state_ = kEOS;
-          return {buffer_, kSlopBytes};
-        } else {
-          // next_state_ = kBuffer, but this is unnecessary
-
-          // The next chunk is not big enough. So we copy it in the current
-          // after the current buffer. Resulting in a buffer with
-          // size + kSlopBytes bytes.
-          std::memcpy(buffer_ + kSlopBytes, chunk_.begin(), size);
-          // skip_ becomes negative here.
-          skip_ += size - kSlopBytes;
-          chunk_ = {buffer_, size + kSlopBytes};
-          return {buffer_, size};
-        }
-      }
-      case kStart: {
-        chunk_ = GetChunk();
-        auto size = chunk_.size();
-        if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
-          next_state_ = kBuffer;
-          skip_ = size - kSlopBytes;
-          return {chunk_.begin(), size - kSlopBytes};
-        }
-        size_t i = 0;
-        do {
-          if (size == 0) {
-            next_state_ = kEOS;
-            return {buffer_, i};
-          }
-          std::memcpy(buffer_ + i, chunk_.begin(), size);
-          ABSL_ASSERT(skip_ == 0);
-          skip_ = size;
-          i += size;
-          if (i > kSlopBytes) {
-            skip_ -= kSlopBytes;
-            chunk_ = {buffer_, i};
-            next_state_ = kBuffer;
-            return {buffer_, i - kSlopBytes};
-          }
-          if (!ensure_not_end(buffer_, i)) {
-            next_state_ = kEOS;
-            return {buffer_, i};
-          }
-          chunk_ = GetChunk();
-          size = chunk_.size();
-        } while (size <= kSlopBytes);
-        std::memcpy(buffer_ + i, chunk_.begin(), kSlopBytes);
-        next_state_ = kChunk;
-        return {buffer_, i};
-      }
-    }
-  }
-
-  StringPiece NextWithOverlap() {
-    return SafeNextWithOverlap([](const char*, size_t) { return true; });
-  }
-
-  void AdjustPos(int delta) {
-    ABSL_ASSERT(delta <= kSlopBytes);
-    skip_ += delta;
-  }
-
-  void SetError() { skip_ = 0; }
-
- private:
-  io::CodedInputStream* input_;
-  StringPiece chunk_;
-  char buffer_[2 * kSlopBytes] = {};
-  enum State {
-    kStart,
-    kEOS,     // -> end of stream.
-    kChunk,   // -> chunk_ contains the data for Next.
-    kBuffer,  // -> We need to copy the left over from previous chunk_ and
-              //    load and patch the start of the next chunk in the
-              //    local buffer.
-  };
-  State next_state_ = kStart;
-  int skip_ = 0;  // how much bytes to skip to current position in the stream.
-
-  StringPiece GetChunk() {
-    const void* ptr;
-    ABSL_ASSERT(skip_ >= 0);
-    input_->Skip(skip_);
-    skip_ = 0;
-    int size;
-    if (!input_->GetDirectBufferPointer(&ptr, &size)) {
-      return nullptr;
-    }
-    return StringPiece(static_cast<const char*>(ptr), size);
-  }
-};
-#endif
-
-// Several of the Parse methods below just do one thing and then call another
-// method.  In a naive implementation, we might have ParseFromString() call
-// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
-// ParseFromCodedStream() which would call MergeFromCodedStream() which would
-// call MergePartialFromCodedStream().  However, when parsing very small
-// messages, every function call introduces significant overhead.  To avoid
-// this without reproducing code, we use these forced-inline helpers.
-
-inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
-                                       MessageLite* message) {
-  if (!message->MergePartialFromCodedStream(input)) return false;
-  if (!message->IsInitialized()) {
-    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
-    return false;
-  }
-  return true;
-}
-
-inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
-                                              MessageLite* message) {
-  message->Clear();
-  return message->MergePartialFromCodedStream(input);
-}
-
-inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
-                                       MessageLite* message) {
-  message->Clear();
-  return InlineMergeFromCodedStream(input, message);
-}
-
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-template <template <int> class Input>
-inline bool InlineMergePartialEntireInput(
-    Input<internal::ParseContext::kSlopBytes>* input, MessageLite* message) {
-  internal::ParseContext ctx;
-
-  auto chunk = input->NextWithOverlap();
-  if (chunk.empty()) {
-    return true;
-  }
-  auto res = ctx.StartParse({message->_ParseFunc(), message}, chunk);
-  while (res.first == internal::ParseContext::kContinue) {
-    int overrun = res.second;
-    chunk = input->NextWithOverlap();
-    if (chunk.empty()) {
-      if (!ctx.ValidEnd(overrun)) return false;
-      return true;
-    }
-    res = ctx.ResumeParse(chunk, overrun);
-  }
-  // Either failure or ended on a zero or end-group tag
-  return false;
-}
-#endif
-
-inline bool InlineMergePartialEntireStream(io::CodedInputStream* cis,
-                                           MessageLite* message) {
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  EpsCopyInputStream<internal::ParseContext::kSlopBytes> input(cis);
-  if (InlineMergePartialEntireInput(&input, message)) {
-    cis->SetConsumed();
-    return true;
-  }
-  return false;
-#else
-  return message->MergePartialFromCodedStream(cis) &&
-         cis->ConsumedEntireMessage();
-#endif
-}
-
-inline bool InlineMergeEntireStream(io::CodedInputStream* input,
-                                    MessageLite* message) {
-  if (!InlineMergePartialEntireStream(input, message)) return false;
-  if (!message->IsInitialized()) {
-    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
-    return false;
-  }
-  return true;
-}
-
-inline bool InlineParsePartialEntireStream(io::CodedInputStream* input,
-                                           MessageLite* message) {
-  message->Clear();
-  return InlineMergePartialEntireStream(input, message);
-}
-
-inline bool InlineParseEntireStream(io::CodedInputStream* input,
-                                    MessageLite* message) {
-  message->Clear();
-  return InlineMergeEntireStream(input, message);
-}
-
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-template <int kSlopBytes>
-class ArrayInput {
- public:
-  ArrayInput(StringPiece chunk) : chunk_(chunk) {}
-
-  StringPiece NextWithOverlap() {
-    auto s = chunk_.size();
-    if (s > 16) {
-      auto res = chunk_.substr(0, s - 16);
-      chunk_ = chunk_.substr(s - 16);
-      return res;
-    } else if (s == 0) {
-      return nullptr;
-    } else {
-      std::memcpy(buffer_, chunk_.begin(), s);
-      chunk_ = nullptr;
-      return {buffer_, s};
-    }
-  }
-
-  void SetError() {}
-
- private:
-  StringPiece chunk_;
-  char buffer_[32] = {};
-  int state_ = 0;
-};
-#endif
-
-inline bool InlineMergePartialFromArray(const void* data, int size,
-                                        MessageLite* msg,
-                                        bool aliasing = false) {
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  auto begin = static_cast<const char*>(data);
-  if (aliasing) {
-    // TODO(gerbens) make this safe against corruption buffer overflow.
-    // Short cut to allow aliasing string_piece
-    internal::ParseContext ctx;
-    ctx.extra_parse_data().aliasing = true;
-    return ctx.ParseExactRange({msg->_ParseFunc(), msg}, begin, begin + size);
-  }
-  ArrayInput<internal::ParseContext::kSlopBytes> input(
-      StringPiece(begin, size));
-  return InlineMergePartialEntireInput(&input, msg);
-#else
-  io::CodedInputStream input(static_cast<const uint8*>(data), size);
-  return msg->MergePartialFromCodedStream(&input) &&
-         input.ConsumedEntireMessage();
-#endif
-}
-
-inline bool InlineMergeFromArray(const void* data, int size,
-                                 MessageLite* message, bool aliasing = false) {
-  if (!InlineMergePartialFromArray(data, size, message, aliasing)) return false;
-  if (!message->IsInitialized()) {
-    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
-    return false;
-  }
-  return true;
-}
-
-inline bool InlineParsePartialFromArray(const void* data, int size,
-                                        MessageLite* message,
-                                        bool aliasing = false) {
-  message->Clear();
-  return InlineMergePartialFromArray(data, size, message, aliasing);
-}
-
-inline bool InlineParseFromArray(const void* data, int size,
-                                 MessageLite* message, bool aliasing = false) {
-  if (!InlineParsePartialFromArray(data, size, message, aliasing)) return false;
-  if (!message->IsInitialized()) {
-    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
-    return false;
-  }
-  return true;
+inline StringPiece as_string_view(const void* data, int size) {
+  return StringPiece(static_cast<const char*>(data), size);
 }
 
 }  // namespace
 
+void MessageLite::LogInitializationErrorMessage() const {
+  GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+}
+
+namespace internal {
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+template <typename Next>
+bool ParseStream(const Next& next, MessageLite* msg) {
+  internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
+  EpsCopyParser<false> parser({msg->_ParseFunc(), msg}, &ctx);
+  auto range = next();
+  while (!range.empty()) {
+    if (!parser.Parse(range)) return false;
+    range = next();
+  }
+  return parser.Done();
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg) {
+  auto begin = input.data();
+  int size = input.size();
+  ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit());
+  internal::ParseClosure parser = {msg->_ParseFunc(), msg};
+  // TODO(gerbens) fine tune
+  constexpr int kThreshold = 48;
+  static_assert(kThreshold >= ParseContext::kSlopBytes,
+                "Requires enough room for at least kSlopBytes to be copied.");
+  // TODO(gerbens) This could be left uninitialized and given an MSAN
+  // annotation instead.
+  char buffer[kThreshold + ParseContext::kSlopBytes] = {};
+  if (size <= kThreshold) {
+    std::memcpy(buffer, begin, size);
+    if (aliasing) {
+      ctx.extra_parse_data().aliasing =
+          reinterpret_cast<std::uintptr_t>(begin) -
+          reinterpret_cast<std::uintptr_t>(buffer);
+    }
+    return ctx.ParseExactRange(parser, buffer, buffer + size);
+  }
+  if (aliasing) {
+    ctx.extra_parse_data().aliasing = ParseContext::ExtraParseData::kNoDelta;
+  }
+  size -= ParseContext::kSlopBytes;
+  int overrun = 0;
+  ctx.StartParse(parser);
+  if (!ctx.ParseRange(StringPiece(begin, size), &overrun)) return false;
+  begin += size;
+  std::memcpy(buffer, begin, ParseContext::kSlopBytes);
+  if (aliasing) {
+    ctx.extra_parse_data().aliasing = reinterpret_cast<std::uintptr_t>(begin) -
+        reinterpret_cast<std::uintptr_t>(buffer);
+  }
+  return ctx.ParseRange({buffer, ParseContext::kSlopBytes}, &overrun) &&
+         ctx.ValidEnd(overrun);
+}
+
+StringPiece Next(BoundedZCIS* input) {
+  const void* data;
+  int size;
+  if (input->limit == 0) return {};
+  while (input->zcis->Next(&data, &size)) {
+    if (size != 0) {
+      input->limit -= size;
+      if (input->limit < 0) {
+        size += input->limit;
+        input->zcis->BackUp(-input->limit);
+        input->limit = 0;
+      }
+      return StringPiece(static_cast<const char*>(data), size);
+    }
+  }
+  return {};
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg) {
+  // TODO(gerbens) implement aliasing
+  auto next = [&input]() { return Next(&input); };
+  return ParseStream(next, msg) && input.limit == 0;
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg) {
+  // TODO(gerbens) implement aliasing
+  BoundedZCIS bounded_zcis{input, INT_MAX};
+  auto next = [&bounded_zcis]() { return Next(&bounded_zcis); };
+  return ParseStream(next, msg) && bounded_zcis.limit > 0;
+}
+
+
+#else
+
+inline bool InlineMergePartialEntireStream(io::CodedInputStream* cis,
+                                           MessageLite* message,
+                                           bool aliasing) {
+  return message->MergePartialFromCodedStream(cis) &&
+         cis->ConsumedEntireMessage();
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg) {
+  io::CodedInputStream decoder(reinterpret_cast<const uint8*>(input.data()),
+                               input.size());
+  return InlineMergePartialEntireStream(&decoder, msg, aliasing);
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg) {
+  io::CodedInputStream decoder(input.zcis);
+  decoder.PushLimit(input.limit);
+  return InlineMergePartialEntireStream(&decoder, msg, aliasing) &&
+         decoder.BytesUntilLimit() == 0;
+}
+
+template <bool aliasing>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg) {
+  io::CodedInputStream decoder(input);
+  return InlineMergePartialEntireStream(&decoder, msg, aliasing);
+}
+
+#endif
+
+template bool MergePartialFromImpl<false>(StringPiece input,
+                                          MessageLite* msg);
+template bool MergePartialFromImpl<true>(StringPiece input,
+                                         MessageLite* msg);
+template bool MergePartialFromImpl<false>(io::ZeroCopyInputStream* input,
+                                          MessageLite* msg);
+template bool MergePartialFromImpl<true>(io::ZeroCopyInputStream* input,
+                                         MessageLite* msg);
+template bool MergePartialFromImpl<false>(BoundedZCIS input, MessageLite* msg);
+template bool MergePartialFromImpl<true>(BoundedZCIS input, MessageLite* msg);
+
+}  // namespace internal
+
 MessageLite* MessageLite::New(Arena* arena) const {
   MessageLite* message = New();
   if (arena != NULL) {
@@ -485,100 +255,100 @@
 }
 
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* cis) {
-  EpsCopyInputStream<internal::ParseContext::kSlopBytes> input(cis);
-  internal::ParseContext ctx(cis->RecursionBudget());
-  ctx.extra_parse_data().pool = cis->GetExtensionPool();
-  ctx.extra_parse_data().factory = cis->GetExtensionFactory();
-
-  auto chunk = input.SafeNextWithOverlap(
-      [&ctx](const char* ptr, int n) { return ctx.EnsureNoEnd(ptr, n, 0); });
-  if (chunk.empty()) {
-    cis->SetConsumed();
-    return true;
-  }
-  auto res = ctx.StartParse({_ParseFunc(), this}, chunk);
-  while (res.first == internal::ParseContext::kContinue) {
-    int overrun = res.second;
-    chunk = input.SafeNextWithOverlap([&ctx, overrun](const char* ptr, int n) {
-      return ctx.EnsureNoEnd(ptr, n, overrun);
-    });
-    if (chunk.empty()) {
-      if (!ctx.ValidEnd(overrun)) goto error;
-      cis->SetConsumed();
+bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
+  // MergePartialFromCodedStream must leave input in "exactly" the same state
+  // as the old implementation. At least when the parse is successful. For
+  // MergePartialFromCodedStream a successful parse can also occur by ending
+  // on a zero tag or an end-group tag. In these cases input is left precisely
+  // past the terminating tag and last_tag_ is set to the terminating tags
+  // value. If the parse ended on a limit (either a pushed limit or end of the
+  // ZeroCopyInputStream) legitimate_end_ is set to true.
+  int size = 0;
+  auto next = [input, &size]() {
+    const void* ptr;
+    input->Skip(size);  // skip previous buffer
+    if (!input->GetDirectBufferPointer(&ptr, &size)) return StringPiece{};
+    return StringPiece(static_cast<const char*>(ptr), size);
+  };
+  internal::ParseContext ctx(input->RecursionBudget());
+  ctx.extra_parse_data().pool = input->GetExtensionPool();
+  ctx.extra_parse_data().factory = input->GetExtensionFactory();
+  internal::EpsCopyParser<true> parser({_ParseFunc(), this}, &ctx);
+  auto range = next();
+  while (!range.empty()) {
+    if (!parser.Parse(range)) {
+      if (!ctx.EndedOnTag()) return false;
+      // Parse ended on a zero or end-group tag, leave the stream in the
+      // appropriate state. Note we only skip forward, due to using
+      // ensure_non_negative_skip being set to true in parser.
+      input->Skip(parser.Skip());
+      input->SetLastTag(ctx.LastTag());
       return true;
     }
-    res = ctx.ResumeParse(chunk, overrun);
+    range = next();
   }
-  // Either failure or ended on a zero or end-group tag
-  if (res.first != internal::ParseContext::kFailure) {
-    cis->SetLastTag(res.first);
-    input.AdjustPos(res.second);
-    return true;
-  }
-error:
-  // Error can happen at a spot from which we can't back up. But in this case
-  // the user can't resume the stream as the error could be in an arbitrary
-  // location in the stream, so just leave the stream alone. This prevents
-  // triggering assertion fail.
-  input.SetError();
-  return false;
+  input->SetConsumed();
+  return parser.Done();
 }
 #endif
 
 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
-  return InlineMergeFromCodedStream(input, this);
+  return MergePartialFromCodedStream(input) && IsInitializedWithErrors();
 }
 
 bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
-  return InlineParseFromCodedStream(input, this);
+  Clear();
+  return MergeFromCodedStream(input);
 }
 
 bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
-  return InlineParsePartialFromCodedStream(input, this);
+  Clear();
+  return MergePartialFromCodedStream(input);
 }
 
 bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
-  io::CodedInputStream decoder(input);
-  return InlineParseEntireStream(&decoder, this);
+  return ParseFrom<kParse>(input);
 }
 
 bool MessageLite::ParsePartialFromZeroCopyStream(
     io::ZeroCopyInputStream* input) {
-  io::CodedInputStream decoder(input);
-  return InlineParsePartialEntireStream(&decoder, this);
+  return ParseFrom<kParsePartial>(input);
+}
+
+bool MessageLite::MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kMergePartial>(internal::BoundedZCIS{input, size});
+}
+
+bool MessageLite::MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                                 int size) {
+  return ParseFrom<kMerge>(internal::BoundedZCIS{input, size});
 }
 
 bool MessageLite::ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
                                                  int size) {
-  io::CodedInputStream decoder(input);
-  decoder.PushLimit(size);
-  return InlineParseEntireStream(&decoder, this) &&
-         decoder.BytesUntilLimit() == 0;
+  return ParseFrom<kParse>(internal::BoundedZCIS{input, size});
 }
 
 bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
     io::ZeroCopyInputStream* input, int size) {
-  io::CodedInputStream decoder(input);
-  decoder.PushLimit(size);
-  return InlineParsePartialEntireStream(&decoder, this) &&
-         decoder.BytesUntilLimit() == 0;
+  return ParseFrom<kParsePartial>(internal::BoundedZCIS{input, size});
 }
 
 bool MessageLite::ParseFromString(const string& data) {
-  return InlineParseFromArray(data.data(), data.size(), this);
+  return ParseFrom<kParse>(data);
 }
 
 bool MessageLite::ParsePartialFromString(const string& data) {
-  return InlineParsePartialFromArray(data.data(), data.size(), this);
+  return ParseFrom<kParsePartial>(data);
 }
 
 bool MessageLite::ParseFromArray(const void* data, int size) {
-  return InlineParseFromArray(data, size, this);
+  return ParseFrom<kParse>(as_string_view(data, size));
 }
 
 bool MessageLite::ParsePartialFromArray(const void* data, int size) {
-  return InlineParsePartialFromArray(data, size, this);
+  return ParseFrom<kParsePartial>(as_string_view(data, size));
 }
 
 
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 0e8c347..39c9e8f 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -46,6 +46,7 @@
 #include <google/protobuf/arena.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
 
 
 #include <google/protobuf/port_def.inc>
@@ -259,6 +260,11 @@
   // Read a protocol buffer from the given zero-copy input stream, expecting
   // the message to be exactly "size" bytes long.  If successful, exactly
   // this many bytes will have been consumed from the input.
+  bool MergePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
+  // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+  // missing required fields.
+  bool MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+                                             int size);
   bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
   // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
   // missing required fields.
@@ -426,6 +432,21 @@
     return Arena::CreateMaybeMessage<T>(arena);
   }
 
+ public:
+  enum ParseFlags {
+    kMerge = 0,
+    kParse = 1,
+    kMergePartial = 2,
+    kParsePartial = 3,
+    kMergeWithAliasing = 4,
+    kParseWithAliasing = 5,
+    kMergePartialWithAliasing = 6,
+    kParsePartialWithAliasing = 7
+  };
+
+  template <ParseFlags flags, typename T>
+  bool ParseFrom(const T& input);
+
  private:
   // TODO(gerbens) make this a pure abstract function
   virtual const void* InternalGetTable() const { return NULL; }
@@ -434,9 +455,64 @@
   friend class Message;
   friend class internal::WeakFieldMap;
 
+  bool IsInitializedWithErrors() const {
+    if (IsInitialized()) return true;
+    LogInitializationErrorMessage();
+    return false;
+  }
+
+  void LogInitializationErrorMessage() const;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
 };
 
+namespace internal {
+
+template <bool alias>
+bool MergePartialFromImpl(StringPiece input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(StringPiece input,
+                                                 MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(StringPiece input,
+                                                MessageLite* msg);
+
+template <bool alias>
+bool MergePartialFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(io::ZeroCopyInputStream* input,
+                                                 MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(io::ZeroCopyInputStream* input,
+                                                MessageLite* msg);
+
+struct BoundedZCIS {
+  io::ZeroCopyInputStream* zcis;
+  int limit;
+};
+
+template <bool alias>
+bool MergePartialFromImpl(BoundedZCIS input, MessageLite* msg);
+extern template bool MergePartialFromImpl<false>(BoundedZCIS input,
+                                                 MessageLite* msg);
+extern template bool MergePartialFromImpl<true>(BoundedZCIS input,
+                                                MessageLite* msg);
+
+
+template <typename T>
+struct SourceWrapper;
+
+template <bool alias, typename T>
+bool MergePartialFromImpl(const SourceWrapper<T>& input, MessageLite* msg) {
+  return input.template MergePartialInto<alias>(msg);
+}
+
+}  // namespace internal
+
+template <MessageLite::ParseFlags flags, typename T>
+bool MessageLite::ParseFrom(const T& input) {
+  if (flags & kParse) Clear();
+  constexpr bool alias = flags & kMergeWithAliasing;
+  return internal::MergePartialFromImpl<alias>(input, this) &&
+         ((flags & kMergePartial) || IsInitializedWithErrors());
+}
+
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
new file mode 100644
index 0000000..3902637
--- /dev/null
+++ b/src/google/protobuf/parse_context.cc
@@ -0,0 +1,627 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/parse_context.h>
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/string_piece_field_support.h>
+#include <google/protobuf/wire_format_lite.h>
+#include "third_party/absl/strings/str_format.h"
+#include <google/protobuf/stubs/strutil.h>
+#include "util/coding/varint.h"
+#include "util/utf8/public/unilib.h"
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+bool ParseContext::ParseEndsInSlopRegion(const char* begin, int overrun) const {
+  ABSL_ASSERT(overrun >= 0);
+  ABSL_ASSERT(overrun <= kSlopBytes);
+  auto ptr = begin + overrun;
+  auto end = begin + kSlopBytes;
+  int n = end - ptr;
+  if (n == 0) return false;
+  // If limit_ != -1 then the parser will continue to parse at least limit_
+  // bytes (or more if on the stack there are further limits)
+  int d = depth_;
+  if (limit_ != -1) {
+    ABSL_ASSERT(d < start_depth_);  // Top-level never has a limit.
+    // rewind the stack until all limits disappear.
+    int limit = limit_;
+    if (limit >= n) return false;
+    while (d < start_depth_) {
+      int delta = stack_[d++].delta_or_group_num;
+      if (delta == -1) {
+        // We found the first limit that was pushed. We should inspect from
+        // this point on.
+        ptr += limit;
+        break;
+      } else if (delta >= 0) {
+        // We reached end of a length delimited subfield. Adjust limit
+        limit += delta;
+        if (limit >= n) return false;
+      } else {
+        // It's a group we assume the format is correct and this group
+        // is properly ended before the limit is reached.
+      }
+    }
+  }
+  d = start_depth_ - d;  // We just keep track of the depth from start.
+  // We verify that a generic parse of the buffer won't, validly, end the parse
+  // before end, due to ending the top-level on a 0 or end-group tag.
+  // IMPORTANT NOTE: we return false in failure cases. This is
+  // important because we could fail due to overrunning the buffer and read
+  // garbage data beyond the buffer (valid reads just left over garbage). So
+  // failure doesn't imply the parse will fail. So if this loops fails while
+  // the real parse would succeed it means the real parse will read beyond the
+  // boundary. If the real parse fails we can't reasonably continue the stream
+  // any way so we make no attempt to leave the stream at a well specified pos.
+  while (ptr < end) {
+    uint32 tag;
+    ptr = Varint::Parse32(ptr, &tag);
+    if (ptr == nullptr || ptr > end) return false;
+    // ending on 0 tag is allowed and is the major reason for the necessity of
+    // this function.
+    if (tag == 0) return true;
+    switch (tag & 7) {
+      case 0: {  // Varint
+        uint64 val;
+        ptr = Varint::Parse64(ptr, &val);
+        if (ptr == nullptr) return false;
+        break;
+      }
+      case 1: {  // fixed64
+        ptr += 8;
+        break;
+      }
+      case 2: {  // len delim
+        uint32 size;
+        ptr = Varint::Parse32(ptr, &size);
+        if (ptr == nullptr) return false;
+        ptr += size;
+        break;
+      }
+      case 3: {  // start group
+        d++;
+        break;
+      }
+      case 4: {                     // end group
+        if (--d < 0) return true;   // We exit early
+        break;
+      }
+      case 5: {  // fixed32
+        ptr += 4;
+        break;
+      }
+      default:
+        return false;  // Unknown wireformat
+    }
+  }
+  return false;
+}
+
+void ParseContext::SwitchStack() {
+  stack_ = new State[start_depth_];
+  std::memcpy(stack_ + inlined_depth_, inline_stack_, sizeof(inline_stack_));
+  inlined_depth_ = -1;  // Special value to indicate stack_ needs to be deleted
+}
+
+std::pair<bool, int> ParseContext::ParseRangeWithLimit(const char* begin,
+                                                       const char* end) {
+  auto ptr = begin;
+  do {
+    ABSL_ASSERT(ptr < end);
+    const char* limited_end;
+    if (limit_ == -1) {
+      limited_end = end;
+    } else {
+      ABSL_ASSERT(limit_ > 0);
+      limited_end = ptr + std::min(static_cast<int32>(end - ptr), limit_);
+      limit_ -= limited_end - ptr;
+    }
+    // Parse the range [ptr, limited_end). The only case (except for error) that
+    // the parser can return prematurely (before limited_end) is on encountering
+    // an end-group. If this is the case we continue parsing the range with
+    // the parent parser.
+    do {
+      ABSL_ASSERT(ptr < limited_end);
+      ptr = parser_(ptr, limited_end, this);
+      if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+        // Clear last_tag_minus_1_ so that the hard error encountered is not
+        // mistaken for ending on a tag.
+        last_tag_minus_1_ = 0;
+        return {};
+      }
+      if (!EndedOnTag()) {
+        // The parser ended still parsing the initial message. This can only
+        // happen because it crossed the end.
+        ABSL_ASSERT(ptr >= limited_end);
+        break;
+      }
+      // Child parser terminated on an end-group / 0 tag.
+      ABSL_ASSERT(depth_ <= start_depth_);
+      if (depth_ == start_depth_) {
+        // The parse was already at the top-level and there is no parent.
+        // This can happen due to encountering 0 or due to this parser being
+        // called for parsing a sub-group message in custom parsing code.
+        return {false, ptr - end};
+      }
+      auto state = Pop();
+      // Verify the ending tag is correct and continue parsing the range with
+      // the parent parser.
+      uint32 group_number = last_tag_minus_1_ >> 3;
+      // We need to clear last_tag_minus_1_, either for the next iteration
+      // or if the if statement below returns.
+      last_tag_minus_1_ = 0;
+      if (state.delta_or_group_num != ~group_number) return {};
+      parser_ = state.parser;  // Load parent parser
+    } while (ptr < limited_end);
+    int overrun = ptr - limited_end;
+    ABSL_ASSERT(overrun >= 0);
+    ABSL_ASSERT(overrun <= kSlopBytes);  // wireformat guarantees this limit
+    if (limit_ != -1) {
+      limit_ -= overrun;  // Adjust limit relative to new position.
+      if (limit_ < 0) return {};  // We overrun the limit
+      while (limit_ == 0) {
+        // We are at an actual ending of a length delimited field.
+        // The top level has no limit (ie. limit_ == -1) so we can assert
+        // that the stack is non-empty.
+        ABSL_ASSERT(depth_ < start_depth_);
+        // else continue parsing the parent message.
+        auto state = Pop();
+        parser_ = state.parser;
+        limit_ = state.delta_or_group_num;
+        // No group ending is possible here. Any group on the stack still
+        // needs to read its end-group tag and can't be on a limit_ == 0.
+        if (limit_ < -1) return {};
+      }
+    }
+  } while (ptr < end);
+  return {true, ptr - end};
+}
+
+const char* StringParser(const char* begin, const char* end, void* object,
+                         ParseContext*) {
+  auto str = static_cast<string*>(object);
+  str->append(begin, end - begin);
+  return end;
+}
+
+const char* CordParser(const char* begin, const char* end, void* object,
+                       ParseContext* ctx) {
+  auto cord = static_cast<Cord*>(object);
+  cord->Append(StringPiece(begin, end - begin));
+  return end;
+}
+
+void StringPieceField::Append(const char *begin, size_t chunk_size, int limit) {
+  if (size_ == 0) {
+    auto tot = chunk_size + limit;
+    if (tot > scratch_size_) {
+      auto old_scratch_size = scratch_size_;
+      scratch_size_ = tot;
+      // TODO(gerbens) Security against big
+      if (arena_ != NULL) {
+        scratch_ = ::google::protobuf::Arena::CreateArray<char>(arena_, scratch_size_);
+      } else {
+        std::allocator<char>().deallocate(scratch_, old_scratch_size);
+        scratch_ = std::allocator<char>().allocate(scratch_size_);
+      }
+    }
+    data_ = scratch_;
+  }
+  std::memcpy(scratch_ + size_, begin, chunk_size);
+  size_ += chunk_size;
+}
+
+const char* StringPieceParser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx) {
+  auto s = static_cast<StringPieceField*>(object);
+  auto limit = ctx->CurrentLimit();
+  s->Append(begin, end - begin, limit);
+  return end;
+}
+
+// Defined in wire_format_lite.cc
+void PrintUTF8ErrorLog(const char* field_name, const char* operation_str,
+                       bool emit_stacktrace);
+
+bool VerifyUTF8(StringPiece str, ParseContext* ctx) {
+  if (!IsStructurallyValidUTF8(str)) {
+    PrintUTF8ErrorLog(ctx->extra_parse_data().FieldName(), "parsing", false);
+    return false;
+  }
+  return true;
+}
+
+bool VerifyUTF8Cord(const Cord& value, ParseContext* ctx) {
+  if (!UniLib::CordIsStructurallyValid(value)) {
+    PrintUTF8ErrorLog(ctx->extra_parse_data().FieldName(), "parsing", false);
+    return false;
+  }
+  return true;
+}
+
+const char* StringParserUTF8(const char* begin, const char* end, void* object,
+                             ParseContext* ctx) {
+  StringParser(begin, end, object, ctx);
+  if (ctx->AtLimit()) {
+    auto str = static_cast<string*>(object);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
+  }
+  return end;
+}
+
+const char* CordParserUTF8(const char* begin, const char* end, void* object,
+                           ParseContext* ctx) {
+  CordParser(begin, end, object, ctx);
+  if (ctx->AtLimit()) {
+    auto str = static_cast<Cord*>(object);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8Cord(*str, ctx));
+  }
+  return end;
+}
+
+const char* StringPieceParserUTF8(const char* begin, const char* end,
+                                  void* object, ParseContext* ctx) {
+  StringPieceParser(begin, end, object, ctx);
+  if (ctx->AtLimit()) {
+    auto s = static_cast<StringPieceField*>(object);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(s->Get(), ctx));
+  }
+  return end;
+}
+
+const char* StringParserUTF8Verify(const char* begin, const char* end,
+                                   void* object, ParseContext* ctx) {
+  StringParser(begin, end, object, ctx);
+#ifndef NDEBUG
+  if (ctx->AtLimit()) {
+    auto str = static_cast<string*>(object);
+    VerifyUTF8(*str, ctx);
+  }
+#endif
+  return end;
+}
+
+const char* CordParserUTF8Verify(const char* begin, const char* end,
+                                 void* object, ParseContext* ctx) {
+  CordParser(begin, end, object, ctx);
+#ifndef NDEBUG
+  if (ctx->AtLimit()) {
+    auto str = static_cast<Cord*>(object);
+    VerifyUTF8Cord(*str, ctx);
+  }
+#endif
+  return end;
+}
+
+const char* StringPieceParserUTF8Verify(const char* begin, const char* end,
+                                        void* object, ParseContext* ctx) {
+  return StringPieceParser(begin, end, object, ctx);
+#ifndef NDEBUG
+  if (ctx->AtLimit()) {
+    auto s = static_cast<StringPieceField*>(object);
+    VerifyUTF8(s->Get(), ctx);
+  }
+#endif
+  return end;
+}
+
+const char* GreedyStringParser(const char* begin, const char* end, void* object,
+                         ParseContext* ctx) {
+  auto str = static_cast<string*>(object);
+  auto limit = ctx->CurrentLimit();
+  ABSL_ASSERT(limit != -1);  // Always length delimited
+  end += std::min<int>(limit, ParseContext::kSlopBytes);
+  str->append(begin, end - begin);
+  return end;
+}
+
+const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
+                             ParseContext* ctx) {
+  auto limit = ctx->CurrentLimit();
+  ABSL_ASSERT(limit != -1);  // Always length delimited
+  bool at_end;
+  if (limit <= ParseContext::kSlopBytes) {
+    end += limit;
+    at_end = true;
+  } else {
+    end += ParseContext::kSlopBytes;
+    at_end =false;
+  }
+  auto str = static_cast<string*>(object);
+  str->append(begin, end - begin);
+  if (at_end) {
+    GOOGLE_PROTOBUF_PARSER_ASSERT(VerifyUTF8(*str, ctx));
+  }
+  return end;
+}
+
+const char* GreedyStringParserUTF8Verify(const char* begin, const char* end, void* object,
+                             ParseContext* ctx) {
+  auto limit = ctx->CurrentLimit();
+  ABSL_ASSERT(limit != -1);  // Always length delimited
+  bool at_end;
+  if (limit <= ParseContext::kSlopBytes) {
+    end += limit;
+    at_end = true;
+  } else {
+    end += ParseContext::kSlopBytes;
+    at_end =false;
+  }
+  auto str = static_cast<string*>(object);
+  str->append(begin, end - begin);
+  if (at_end) {
+#ifndef NDEBUG
+    VerifyUTF8(*str, ctx);
+#endif
+  }
+  return end;
+}
+
+template <typename T, bool sign>
+const char* VarintParser(const char* begin, const char* end, void* object,
+                         ParseContext*) {
+  auto repeated_field = static_cast<RepeatedField<T>*>(object);
+  auto ptr = begin;
+  while (ptr < end) {
+    uint64 varint;
+    ptr = Varint::Parse64(ptr, &varint);
+    if (!ptr) return nullptr;
+    T val;
+    if (sign) {
+      if (sizeof(T) == 8) {
+        val = WireFormatLite::ZigZagDecode64(varint);
+      } else {
+        val = WireFormatLite::ZigZagDecode32(varint);
+      }
+    } else {
+      val = varint;
+    }
+    repeated_field->Add(val);
+  }
+  return ptr;
+}
+
+template <typename T>
+const char* FixedParser(const char* begin, const char* end, void* object,
+                        ParseContext*) {
+  auto repeated_field = static_cast<RepeatedField<T>*>(object);
+  int num = (end - begin + sizeof(T) - 1) / sizeof(T);
+
+  const int old_entries = repeated_field->size();
+  repeated_field->Reserve(old_entries + num);
+  std::memcpy(repeated_field->AddNAlreadyReserved(num), begin, num * sizeof(T));
+  return begin + num * sizeof(T);
+}
+
+const char* PackedInt32Parser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx) {
+  return VarintParser<int32, false>(begin, end, object, ctx);
+}
+const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx) {
+  return VarintParser<uint32, false>(begin, end, object, ctx);
+}
+const char* PackedInt64Parser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx) {
+  return VarintParser<int64, false>(begin, end, object, ctx);
+}
+const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx) {
+  return VarintParser<uint64, false>(begin, end, object, ctx);
+}
+const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx) {
+  return VarintParser<int32, true>(begin, end, object, ctx);
+}
+const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx) {
+  return VarintParser<int64, true>(begin, end, object, ctx);
+}
+
+const char* PackedEnumParser(const char* begin, const char* end, void* object,
+                             ParseContext* ctx) {
+  return VarintParser<int, false>(begin, end, object, ctx);
+}
+
+const char* PackedValidEnumParserLite(const char* begin, const char* end,
+                                      void* object, ParseContext* ctx) {
+  auto repeated_field = static_cast<RepeatedField<int>*>(object);
+  auto ptr = begin;
+  while (ptr < end) {
+    uint64 varint;
+    ptr = Varint::Parse64(ptr, &varint);
+    if (!ptr) return nullptr;
+    int val = varint;
+    if (ctx->extra_parse_data().ValidateEnum<string>(val))
+      repeated_field->Add(val);
+  }
+  return ptr;
+}
+
+const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
+                                         void* object, ParseContext* ctx) {
+  auto repeated_field = static_cast<RepeatedField<int>*>(object);
+  auto ptr = begin;
+  while (ptr < end) {
+    uint64 varint;
+    ptr = Varint::Parse64(ptr, &varint);
+    if (!ptr) return nullptr;
+    int val = varint;
+    if (ctx->extra_parse_data().ValidateEnumArg<string>(val))
+      repeated_field->Add(val);
+  }
+  return ptr;
+}
+
+const char* PackedBoolParser(const char* begin, const char* end, void* object,
+                             ParseContext* ctx) {
+  return VarintParser<bool, false>(begin, end, object, ctx);
+}
+
+const char* PackedFixed32Parser(const char* begin, const char* end,
+                                void* object, ParseContext* ctx) {
+  return FixedParser<uint32>(begin, end, object, ctx);
+}
+const char* PackedSFixed32Parser(const char* begin, const char* end,
+                                 void* object, ParseContext* ctx) {
+  return FixedParser<int32>(begin, end, object, ctx);
+}
+const char* PackedFixed64Parser(const char* begin, const char* end,
+                                void* object, ParseContext* ctx) {
+  return FixedParser<uint64>(begin, end, object, ctx);
+}
+const char* PackedSFixed64Parser(const char* begin, const char* end,
+                                 void* object, ParseContext* ctx) {
+  return FixedParser<int64>(begin, end, object, ctx);
+}
+const char* PackedFloatParser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx) {
+  return FixedParser<float>(begin, end, object, ctx);
+}
+const char* PackedDoubleParser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx) {
+  return FixedParser<double>(begin, end, object, ctx);
+}
+
+const char* NullParser(const char* begin, const char* end, void* object,
+                       ParseContext* ctx) {
+  return end;
+}
+
+void WriteVarint(uint64 val, string* s) {
+  while (val >= 128) {
+    uint8 c = val | 0x80;
+    s->push_back(c);
+    val >>= 7;
+  }
+  s->push_back(val);
+}
+
+void WriteVarint(uint32 num, uint64 val, string* s) {
+  WriteVarint(num << 3, s);
+  WriteVarint(val, s);
+}
+
+void WriteLengthDelimited(uint32 num, StringPiece val, string* s) {
+  WriteVarint((num << 3) + 2, s);
+  WriteVarint(val.size(), s);
+  s->append(val.data(), val.size());
+}
+
+class UnknownFieldLiteParserHelper {
+ public:
+  explicit UnknownFieldLiteParserHelper(string* unknown) : unknown_(unknown) {}
+
+  void AddVarint(uint32 num, uint64 value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8, unknown_);
+    WriteVarint(value, unknown_);
+  }
+  void AddFixed64(uint32 num, uint64 value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 1, unknown_);
+    char buffer[8];
+    std::memcpy(buffer, &value, 8);
+    unknown_->append(buffer, 8);
+  }
+  ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
+    if (unknown_ == nullptr) return {NullParser, nullptr};
+    WriteVarint(num * 8 + 2, unknown_);
+    WriteVarint(size, unknown_);
+    return {StringParser, unknown_};
+  }
+  ParseClosure StartGroup(uint32 num) {
+    if (unknown_ == nullptr) return {UnknownGroupLiteParse, nullptr};
+    WriteVarint(num * 8 + 3, unknown_);
+    return {UnknownGroupLiteParse, unknown_};
+  }
+  void EndGroup(uint32 num) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 4, unknown_);
+  }
+  void AddFixed32(uint32 num, uint32 value) {
+    if (unknown_ == nullptr) return;
+    WriteVarint(num * 8 + 5, unknown_);
+    char buffer[4];
+    std::memcpy(buffer, &value, 4);
+    unknown_->append(buffer, 4);
+  }
+
+ private:
+  string* unknown_;
+};
+
+const char* UnknownGroupLiteParse(const char* begin, const char* end,
+                                  void* object, ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(static_cast<string*>(object));
+  return WireFormatParser({UnknownGroupLiteParse, object}, field_parser, begin,
+                          end, ctx);
+}
+
+std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
+                                               const char* begin,
+                                               const char* end, string* unknown,
+                                               ParseContext* ctx) {
+  UnknownFieldLiteParserHelper field_parser(unknown);
+  return FieldParser(tag, parent, field_parser, begin, end, ctx);
+}
+
+const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
+                               internal::ParseContext* ctx) {
+  ctx->extra_parse_data().payload.append(begin, end - begin);
+  if (ctx->AtLimit()) {
+    // Move payload out of extra_parse_data. Parsing maps could trigger
+    // payload on recursive maps.
+    string to_parse = std::move(ctx->extra_parse_data().payload);
+    StringPiece chunk = to_parse;
+    if (!ctx->extra_parse_data().parse_map(chunk.begin(), chunk.end(), object,
+                                           ctx)) {
+      return nullptr;
+    }
+  }
+  return end;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
new file mode 100644
index 0000000..c7d37db
--- /dev/null
+++ b/src/google/protobuf/parse_context.h
@@ -0,0 +1,821 @@
+// 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_PARSE_CONTEXT_H__
+#define GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
+
+#include <string>
+
+#include <google/protobuf/port.h>
+
+#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/common.h>
+#include "third_party/absl/base/optimization.h"
+#include <google/protobuf/stubs/strutil.h>
+#include "util/coding/varint.h"
+
+#include <google/protobuf/port_def.inc>
+
+namespace google {
+namespace protobuf {
+
+class UnknownFieldSet;
+class DescriptorPool;
+class MessageFactory;
+
+namespace internal {
+
+// Template code below needs to know about the existence of these functions.
+void WriteVarint(uint32 num, uint64 val, std::string* s);
+void WriteLengthDelimited(uint32 num, StringPiece val, std::string* s);
+// Inline because it is just forwarding to s->WriteVarint
+inline void WriteVarint(uint32 num, uint64 val, UnknownFieldSet* s);
+inline void WriteLengthDelimited(uint32 num, StringPiece val,
+                                 UnknownFieldSet* s);
+
+
+// ParseContext contains state that needs to be preserved across buffer seams.
+
+class ParseContext;
+
+// The parser works by composing elementary parse functions, that are generated
+// by the compiler, together to perform the full parse. To accomplish this the
+// functionality of the elementary parse function is slightly increased which
+// allows it to become composable.
+
+// The basic abstraction ParseContext is designed for is a slight modification
+// of the ZeroCopyInputStream (ZCIS) abstraction. A ZCIS presents a serialized
+// stream as a series of buffers that concatenate to the full stream.
+// Pictorially a ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+//                      [----------------------------] chunk 2
+//                                          chunk 3 [--------------]
+//
+// Where the '-' represent the bytes which are vertically lined up with the
+// bytes of the stream.
+// ParseContext requires its input to be presented similarily with the extra
+// property that the last kSlopBytes of a chunk overlaps with the first
+// kSlopBytes of the next chunk, or if there is no next chunk at least its still
+// valid to read those bytes. Again, pictorially, we now have
+//
+// [---------------------------------------------------------------]
+// [-------------------....] chunk 1
+//                    [------------------------....] chunk 2
+//                                    chunk 3 [------------------..**]
+//                                                      chunk 4 [--****]
+// Here '-' mean the bytes of the stream or chunk and '.' means bytes past the
+// chunk that match up with the start of the next chunk. Above each chunk has
+// 4 '.' after the chunk. In the case these 'overflow' bytes represents bytes
+// past the stream, indicated by '*' above, their values are unspecified. It is
+// still legal to read them (ie. should not segfault). Reading past the
+// end should be detected by the user and indicated as an error.
+//
+// The reason for this, admittedly, unconventional invariant is to ruthlessly
+// optimize the protobuf parser. Having an overlap helps in two important ways.
+// Firstly it alleviates having to performing bounds checks, if a piece of code
+// will never read more than kSlopBytes. Secondly, and more importantly, the
+// protobuf wireformat is such that there is always a fresh start of a tag
+// within kSlopBytes. This allows the parser to exit parsing a chunk leaving
+// the parse on a position inside the overlap where a fresh tag starts.
+
+// The elementary parse function has the following signature
+
+typedef const char* (*ParseFunc)(const char* ptr, const char* end, void* object,
+                                 ParseContext* ctx);
+
+// which parses the serialized data stored in the range [ptr, end) into object.
+// A parse function together with its object forms a callable closure.
+struct ParseClosure {
+  ParseFunc func;
+  void* object;
+
+  // Pre-conditions
+  //   ptr < end is a non-empty range where ptr points to the start of a tag
+  //     and it's okay to read the bytes in [end, end + kSlopBytes).
+  //     Which will contain the bytes of the next chunk if the stream continues,
+  //     or undefined in which case the parse will be guaranteed to fail.
+  //
+  // Post-conditions
+  //   Parsed all tag/value pairs starting before end or if a group end
+  //   tag is encountered returns the pointer to that tag.
+  //   If a group end is encountered it verifies it matches the one that was
+  //   pushed and the stack is popped.
+  //   Otherwise it will parses the entire range pushing if end is inside one
+  //   of the children those are pushed on the stack.
+  //
+  //   If an element is popped from the stack it ended on the correct end group
+  //   returns pointer after end-group tag (posibly in overlap, but the start
+  //   of end-group tag will be before end).
+  //   If the stack is the same or deeper, returns pointer in overlap region
+  //   (end <= retval < end + kSlopBytes).
+  //   All tag/value pairs between in [begin, retval) are parsed and retval
+  //   points to start of a tag.
+  const char* operator()(const char* ptr, const char* end, ParseContext* ctx) {
+    ABSL_ASSERT(ptr < end);
+    return func(ptr, end, object, ctx);
+  }
+};
+
+// To fully parse a stream, a driver loop repeatedly calls the parse function
+// at the top of the stack, popping and resume parsing the parent message
+// according to the recursive structure of the wireformat. This loop will also
+// need to provide new buffer chunks and align the ptr correctly over the seams.
+// The point of this framework is that chunk refresh logic is located in the
+// outer loop, while the inner loop is almost free of it. The two code paths in
+// the parse code dealing with seams are located in fallback paths whose checks
+// are folded with input limit checks that are necessary anyway. In other words,
+// all the parser code that deals with seams is located in what would otherwise
+// be error paths of a parser that wouldn't need to deal with seams.
+
+class ParseContext {
+ public:
+  enum {
+    // Tag is atmost 5 bytes, varint is atmost 10 resulting in 15 bytes. We
+    // choose
+    // 16 bytes for the obvious reason of alignment.
+    kSlopBytes = 16,
+    // Inlined stack size
+    kInlinedDepth = 15,
+  };
+
+  // Arghh!!! here be tech-debt dragons
+  struct ExtraParseData {
+    const DescriptorPool* pool = nullptr;
+    MessageFactory* factory = nullptr;
+
+    // payload is used for MessageSetItem and maps
+    std::string payload;
+    bool (*parse_map)(const char* begin, const char* end, void* map_field,
+                      ParseContext* ctx);
+
+    void SetEnumValidator(bool (*validator)(int), void* unknown,
+                          int field_num) {
+      enum_validator = validator;
+      unknown_fields = unknown;
+      field_number = field_num;
+    }
+    void SetEnumValidatorArg(bool (*validator)(const void*, int),
+                             const void* arg, void* unknown, int field_num) {
+      arg_enum_validator = {validator, arg};
+      unknown_fields = unknown;
+      field_number = field_num;
+    }
+    template <typename Unknown>
+    bool ValidateEnum(int val) const {
+      if (enum_validator(val)) return true;
+      WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
+      return false;
+    }
+    template <typename Unknown>
+    bool ValidateEnumArg(int val) const {
+      if (arg_enum_validator(val)) return true;
+      WriteVarint(field_number, val, static_cast<Unknown*>(unknown_fields));
+      return false;
+    }
+
+    void SetFieldName(const void* name) {
+      unknown_fields = const_cast<void*>(name);
+    }
+    const char* FieldName() const {
+      return static_cast<const char*>(unknown_fields);
+    }
+
+    union {
+      bool (*enum_validator)(int);
+      struct {
+        bool operator()(int val) const { return validator(arg, val); }
+        bool (*validator)(const void*, int);
+        const void* arg;
+      } arg_enum_validator;
+    };
+    void* unknown_fields;
+    int field_number;
+    // 0 means no aliasing. If not zero aliasing is the delta between the
+    // ptr and the buffer that needs to be aliased. If the value is
+    // kNoDelta (1) this means delta is actually 0 (we're working directly in
+    // the buffer).
+    enum { kNoDelta = 1 };
+    std::uintptr_t aliasing = 0;
+  };
+
+  ExtraParseData& extra_parse_data() { return extra_parse_data_; }
+  const ExtraParseData& extra_parse_data() const { return extra_parse_data_; }
+
+  // Helpers to detect if a parse of length delimited field is completed.
+  bool AtLimit() const { return limit_ == 0; }
+  int32 CurrentLimit() const { return limit_; }
+
+  // Initializes ParseContext with a specific recursion limit (rec_limit)
+  explicit ParseContext(int rec_limit)
+      : depth_(rec_limit),
+        start_depth_(rec_limit),
+        stack_(inline_stack_ + kInlinedDepth - rec_limit),
+        inlined_depth_(std::max(0, rec_limit - kInlinedDepth)) {}
+
+  ~ParseContext() {
+    if (inlined_depth_ == -1) delete stack_;
+  }
+
+  void StartParse(ParseClosure parser) { parser_ = parser; }
+
+  // Parses a chunk of memory given the current state of parse context (ie.
+  // the active parser and stack) and overrun.
+  // Pre-condition:
+  //   chunk_ is not empty.
+  //   limit_ > 0 (limit from begin) or -1 (no limit)
+  // Post-condition:
+  //   returns true on success with overrun_ptr adjusted to the new value, or
+  //   false is the parse is finished. False means either a parse failure or
+  //   or because the top-level was terminated on a 0 or end-group tag in which
+  //   case overrun points to the position after the ending tag. You can call
+  //   EndedOnTag() to find if the parse failed due to an error or ended on
+  //   terminating tag.
+  bool ParseRange(StringPiece chunk, int* overrun_ptr) {
+    ABSL_ASSERT(!chunk.empty());
+    int& overrun = *overrun_ptr;
+    if (overrun >= chunk.size()) {
+      // This case can easily happen in patch buffers and we like to inline
+      // this case.
+      overrun -= chunk.size();
+      return true;
+    }
+    auto res = ParseRangeWithLimit(chunk.begin() + overrun, chunk.end());
+    overrun = res.second;
+    return res.first;
+  }
+
+  bool ValidEnd(int overrun) { return depth_ == start_depth_ && overrun == 0; }
+  bool EndedOnTag() const { return last_tag_minus_1_ != 0; }
+  uint32 LastTag() const { return last_tag_minus_1_ + 1; }
+
+  // Generically verifies for the slop region [begin, begin + kSlopBytes) if
+  // the parse will be terminated by 0 or end-group tag. If true than you can
+  // safely parse the slop region without having to load more data.
+  bool ParseEndsInSlopRegion(const char* begin, int overrun) const;
+
+  // Should only be called by Parse code.
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Fast path helpers. These helpers maintain the state in parse context
+  // through recursive calls. The whole design is to make this as minimal as
+  // possible. Only recursion depth and limit are maintained at every recursion.
+  //////////////////////////////////////////////////////////////////////////////
+
+  bool ParseExactRange(ParseClosure parser, const char* begin,
+                       const char* end) {
+    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
+    auto old_limit = limit_;
+    limit_ = 0;
+    auto ptr = begin;
+    if (ptr < end) ptr = parser(ptr, end, this);
+    if (ptr != end || EndedOnTag()) return false;
+    limit_ = old_limit;
+    ++depth_;
+    return true;
+  }
+
+  // Returns a pair of the pointer the parse is left and a boolean indicating
+  // if the group is still continuing.
+  std::pair<const char*, bool> ParseGroup(uint32 tag, ParseClosure parser,
+                                          const char* begin, const char* end,
+                                          int* depth) {
+    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return {};
+    *depth = depth_;
+    auto ptr = begin;
+    if (ptr < end) ptr = parser(ptr, end, this);
+    if (ptr == nullptr) return {};
+    if (!EndedOnTag()) {
+      // The group hasn't been terminated by an end-group and thus continues,
+      // hence it must have ended because it crossed "end".
+      ABSL_ASSERT(ptr >= end);
+      return {ptr, true};
+    }
+    // Verify that the terminating tag matches the start group tag. As an extra
+    // subtlety it could have been terminated by an end-group tag but in a
+    // length delimited sub field of the group. So we must also check that depth
+    // matches, if it doesn't match it means a length delimited subfield got
+    // terminated by an end group which is an error.
+    if (tag != last_tag_minus_1_ || *depth != depth_) return {};
+    last_tag_minus_1_ = 0;  // It must always be cleared.
+    ++depth_;
+    return {ptr, false};
+  }
+
+  void EndGroup(uint32 tag) {
+    ABSL_ASSERT(tag == 0 || (tag & 7) == 4);
+    // Because of the above assert last_tag_minus_1 is never set to 0, and the
+    // caller can verify the child parser was terminated, by comparing to 0.
+    last_tag_minus_1_ = tag - 1;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Slow path helper functions when a child crosses the "end" of range.
+  // This is either an error (if limit_ = 0) OR we need to store state.
+  // These functions manage the task of updating the state correctly.
+  //////////////////////////////////////////////////////////////////////////////
+
+  // Helper function called by generated code in case of a length delimited
+  // field that is going to cross the boundary.
+  const char* StoreAndTailCall(const char* ptr, const char* end,
+                               ParseClosure current_parser,
+                               ParseClosure child_parser, int32 size) {
+    // if size was bigger than 2GB we should fail
+    if (size < 0) return nullptr;
+    // At this point ptr could be past end. Hence a malicious size could
+    // overflow.
+    int64 safe_new_limit = size - static_cast<int64>(end - ptr);
+    if (safe_new_limit > INT_MAX) return nullptr;
+    ABSL_ASSERT(safe_new_limit > 0);  // only call this if it's crossing end
+    int32 new_limit = static_cast<int32>(safe_new_limit);
+    int32 delta;
+    if (limit_ != -1) {
+      if (PROTOBUF_PREDICT_FALSE(new_limit > limit_)) return nullptr;
+      delta = limit_ - new_limit;
+    } else {
+      delta = -1;  // special value
+    }
+    limit_ = new_limit;
+    // Save the current closure on the stack.
+    if (!Push(current_parser, delta)) return nullptr;
+    // Ensure the active state is set correctly.
+    parser_ = child_parser;
+    return ptr < end ? child_parser(ptr, end, this) : ptr;
+  }
+
+  // Helper function for a child group that has crossed the boundary.
+  bool StoreGroup(ParseClosure current_parser, ParseClosure child_parser,
+                  int depth, uint32 tag) {
+    // The group must still read an end-group tag, so it can't be at a limit.
+    // By having this check we ensure that when limit_ = 0 we can't end in some
+    // deeper recursion. Hence ParseExactRange does not need to check for
+    // matching depth.
+    if (limit_ == 0) return false;
+    if (depth == depth_) {
+      // This child group is the active parser. The fast path code assumes
+      // everything will be parsed within a chunk and doesn't modify
+      // parse context in this case. We need to make the child parser active.
+      parser_ = child_parser;
+    }
+    if (ABSL_PREDICT_FALSE(depth < inlined_depth_)) SwitchStack();
+    stack_[depth] = {current_parser, static_cast<int32>(~(tag >> 3))};
+    return true;
+  }
+
+ private:
+  // This the "active" or current parser.
+  ParseClosure parser_;
+  // The context keeps an internal stack to keep track of the recursive
+  // part of the parse state.
+  // Current depth of the active parser, depth counts down.
+  // This is used to limit recursion depth (to prevent overflow on malicious
+  // data), but is also used to index in stack_ to store the current state.
+  int depth_;
+  int32 limit_ = -1;
+
+  // A state is on the stack to save it, in order to continue parsing after
+  // child is done.
+  struct State {
+    ParseClosure parser;
+    // This element describes how to adjust the parse state after finishing
+    // the child. If the child was a length delimited field, delta describes
+    // the limit relative to the child's limit (hence >= 0).
+    // If child was a sub group limit contains ~field num (hence < 0) in order
+    // to verify the group ended on a correct end tag. No limit adjusting.
+    // Note above the sign of delta is meaningful
+    int32 delta_or_group_num;
+  };
+  int start_depth_;
+  // This is used to return the end group (or 0 tag) that terminated the parse.
+  // Actually it contains last_tag minus 1. Which is either the start group tag
+  // or -1. This member should always be zero and the caller should immediately
+  // check this member to verify what state the parser ended on and clear its
+  // value.
+  uint32 last_tag_minus_1_ = 0;
+
+  ExtraParseData extra_parse_data_;
+  State* stack_;
+  State inline_stack_[kInlinedDepth];
+  int inlined_depth_;
+
+  bool Push(ParseClosure parser, int32 delta) {
+    ABSL_ASSERT(delta >= -1);  // Make sure it's a valid len-delim
+    if (PROTOBUF_PREDICT_FALSE(--depth_ < 0)) return false;
+    if (ABSL_PREDICT_FALSE(depth_ < inlined_depth_)) SwitchStack();
+    stack_[depth_] = {parser, delta};
+    return true;
+  }
+
+  State Pop() { return stack_[depth_++]; }
+
+  void SwitchStack();
+
+  // Parses a chunk of memory given the current state of parse context (ie.
+  // the active parser and stack).
+  // Pre-condition:
+  //   begin < end (non-empty range)
+  //   limit_ > 0 (limit from begin) or -1 (no limit)
+  // Post-condition:
+  //   returns either (true, overrun) for a successful parse that can continue,
+  //   or (false, overrun) for a parse that can't continue. Either due to a
+  //   corrupt data (parse failure) or because the top-level was terminated on a
+  //   0 or end-group tag in which case overrun points to the position after the
+  //   end.
+  std::pair<bool, int> ParseRangeWithLimit(const char* begin, const char* end);
+};
+
+// This is wrapper to parse a sequence of buffers without the overlap property,
+// like the sequence given by ZeroCopyInputStream (ZCIS) or ByteSource. This is
+// done by copying data around the seams, hence the name EpsCopyParser.
+// Pictorially if ZCIS presents a stream in chunks like so
+// [---------------------------------------------------------------]
+// [---------------------] chunk 1
+//                      [----------------------------] chunk 2
+//                                          chunk 3 [--------------]
+// where '-' depicts bytes of the stream or chunks vertically alligned with the
+// corresponding bytes between stream and chunk.
+//
+// This class will present chunks to the ParseContext like this
+// [-----------------....] chunk 1
+//                  [----....] patch
+//                      [------------------------....] chunk 2
+//                                              [----....] patch
+//                                          chunk 3 [----------....]
+//                                                      patch [----****]
+// by using a fixed size buffer to patch over the seams. This requires
+// copying of an "epsilon" neighboorhood around the seams. In the picture above
+// dots mean bytes beyond the end of the new chunks. Each chunk is kSlopBytes
+// smalller as its original chunk (above depicted as 4 dots) and the number of
+// of chunks is doubled because each seam in the original stream introduces a
+// new patch.
+//
+// The algorithm is simple but not entirely trivial. Two complications arise
+// 1) The original chunk could be less than kSlopBytes. Hence we can't simply
+// chop the last kSlopBytes of a chunk.
+// 2) In some (infrequent) use cases, we don't necessarily parse unitl the end
+// of a stream, but instead the parse is terminated by 0 or end-group tag. If
+// this is allowed we must take care to leave the underlying stream at a
+// position precisely after the terminating tag. If this happens in the slop
+// region of a buffer we will already have loaded the next buffer. Not all
+// streams allow backing up to a previous buffer blocking us from leaving the
+// stream in the proper state. If terminating on 0 is allowed (in the old parser
+// this means a call to MergePartialFromCodedStream without a subsequent call to
+// ConsumedEntireMessage), this algorithm needs to ensure the parse won't end
+// in the slop region before moving the next buffer.
+//
+// The core idea of EpsCopyParser is to parse ranges except the last kSlopBytes
+// and store those in the patch buffer, until the next parse provides additional
+// data to fill the slop region. So parsing a range means first parsing the slop
+// bytes of the previous range using the new range to provide slop bytes for the
+// patch, followed by parsing the actual range except the last kSlopBytes and
+// store those. If no more data is available a call to Done finishes the parse
+// by parsing the remaining slopbytes.
+//
+// In order to deal with problem 1, we need to deal with the case that a new
+// chunk can be less or equal than kSlopBytes big. We can just copy the chunk
+// to the end and return (buffer, chunk->size). Pictorially
+// [--------] chunk 1
+//         [--] chunk 2
+//           [---] chunk 3
+// will become
+// [----....] chunk 1
+//     [--....] patch (not full range of the patch buffer, only two hyphens)
+//         [--] chunk 2 (too small so never parsed directly)
+//       [---....] patch (not full range of the buffer, only three hyphens)
+//           [---] chunk 3 (too small so never parsed directly)
+//          [----****] patch (full range, last bytes are garbage)
+// Because of this the source (the dots in above) can overlap with the
+// destination buffer and so we have to use memmove.
+//
+// To solve problem 2, we use a generic parser together with knowledge of the
+// nesting from the side stack to verify if the parse will be terminated in the
+// slop region. If it terminates inside the slop region, we just parse it as
+// well. See ParseEndsInSlopRegion in ParseContext for the implementation. This
+// is only done if ensure_non_negative_skip is true, if it's false Skip() could
+// return a negative number.
+template <bool ensure_non_negative_skip>
+class EpsCopyParser {
+ public:
+  EpsCopyParser(ParseClosure parser, ParseContext* ctx) : ctx_(ctx) {
+    ctx_->StartParse(parser);
+  }
+
+  // Parse the bytes as provided by the non-empty range.
+  // Returns true on a successful parse ready to accept more data, if there is
+  // no more data call Done() to finish the parse.
+  // Returns false if the parse is terminated. Termination is either due to a
+  // parse error or due to termination on an end-group or 0 tag. You can call
+  // EndedOnTag() on the underlying ParseContext to find out if the parse ended
+  // correctly on a terminating tag.
+  bool Parse(StringPiece range) {
+    ABSL_ASSERT(!range.empty());
+    auto size = range.size();
+    if (size > kSlopBytes) {
+      // The buffer is large enough to be able to parse the (size - kSlopBytes)
+      // prefix directly. However we still need to parse the data in buffer_,
+      // that holds the slop region of the previous buffer.
+      if (overrun_ == kSlopBytes) {
+        // We overrun the whole slop region of the previous buffer.
+        // Optimization, we can skip the patch buffer.
+        overrun_ = 0;
+      } else {
+        std::memcpy(buffer_ + kSlopBytes, range.begin(), kSlopBytes);
+        if (!ParseRange({buffer_, kSlopBytes}, 0)) return false;
+      }
+      range.remove_suffix(kSlopBytes);
+    } else {
+      std::memcpy(buffer_ + kSlopBytes, range.begin(), size);
+      range = {buffer_, size};
+    }
+    if (!ParseRange(range, size - kSlopBytes)) return false;
+    std::memmove(buffer_, range.end(), kSlopBytes);
+    if (ensure_non_negative_skip &&
+        ctx_->ParseEndsInSlopRegion(buffer_, overrun_)) {
+      // We care about leaving the stream at the right place and the stream will
+      // indeed terminate, so just parse it.
+      auto res = ParseRange({buffer_, kSlopBytes}, size);
+      ABSL_ASSERT(!res);
+      return false;
+    }
+    return true;
+  }
+
+  // Finish the parse by parsing the remaining data and verify success.
+  bool Done() {
+    return ParseRange({buffer_, kSlopBytes}, 0) && ctx_->ValidEnd(overrun_);
+  }
+
+  // If the parse was terminated by a end-group or 0 tag. Skip returns the
+  // offset where the parse left off relative to the start of the last range
+  // parsed.
+  // NOTE: This could be negative unless ensure_non_negative_skip is true.
+  int Skip() {
+    // The reason of ensure_non_negative_skip and ParseEndsInSlopRegion is that
+    // the following assert holds. Which implies the stream doesn't need to
+    // backup.
+    ABSL_ASSERT(!ensure_non_negative_skip || overrun_ >= 0);
+    return overrun_;
+  }
+
+ private:
+  constexpr static int kSlopBytes = ParseContext::kSlopBytes;
+  // overrun_ stores where in the slop region of the previous parse the parse
+  // was left off. This is used to start the parse of the next region at the
+  // correct point. Initially overrun_ should be set to kSlopBytes which means
+  // that the parse starts at precisely the beginning of new buffer provided.
+  int overrun_ = kSlopBytes;
+  // The first kSlopBytes of buffer_ contains the slop region of the previous
+  // parsed region.
+  char buffer_[2 * kSlopBytes] = {};
+  ParseContext* ctx_;
+
+  bool ParseRange(StringPiece range, int delta) {
+    auto res = ctx_->ParseRange(range, &overrun_);
+    if (!res) overrun_ += delta;
+    return res;
+  }
+};
+
+// Add any of the following lines to debug which parse function is failing.
+
+#define GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, ret) \
+  if (!(predicate)) {                                  \
+    /*  raise(SIGINT); */                              \
+    /*  GOOGLE_LOG(ERROR) << "Parse failure"; */              \
+    return ret;                                        \
+  }
+
+#define GOOGLE_PROTOBUF_PARSER_ASSERT(predicate) \
+    GOOGLE_PROTOBUF_ASSERT_RETURN(predicate, nullptr)
+
+template <typename T>
+std::pair<const char*, bool> FieldParser(uint64 tag, ParseClosure parent,
+                                         T field_parser, const char* begin,
+                                         const char* end, ParseContext* ctx) {
+  auto ptr = begin;
+  uint32 number = tag >> 3;
+  if (ABSL_PREDICT_FALSE(number == 0)) {
+    GOOGLE_PROTOBUF_ASSERT_RETURN(tag == 0, {});
+    // Special case scenario of 0 termination.
+    ctx->EndGroup(tag);
+    return {ptr, true};
+  }
+  using WireType = internal::WireFormatLite::WireType;
+  switch (tag & 7) {
+    case WireType::WIRETYPE_VARINT: {
+      uint64 value;
+      ptr = Varint::Parse64(ptr, &value);
+      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+      field_parser.AddVarint(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_FIXED64: {
+      uint64 value = io::UnalignedLoad<uint64>(ptr);
+      ptr += 8;
+      field_parser.AddFixed64(number, value);
+      break;
+    }
+    case WireType::WIRETYPE_LENGTH_DELIMITED: {
+      uint32 size;
+      ptr = Varint::Parse32(ptr, &size);
+      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+      ParseClosure child = field_parser.AddLengthDelimited(number, size);
+      if (size > end - ptr) {
+        return {ctx->StoreAndTailCall(ptr, end, parent, child, size), true};
+      }
+      auto newend = ptr + size;
+      GOOGLE_PROTOBUF_ASSERT_RETURN(ctx->ParseExactRange(child, ptr, newend),
+                                     {});
+      ptr = newend;
+      break;
+    }
+    case WireType::WIRETYPE_START_GROUP: {
+      int depth;
+      ParseClosure child = field_parser.StartGroup(number);
+      auto res = ctx->ParseGroup(tag, child, ptr, end, &depth);
+      ptr = res.first;
+      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr != nullptr, {});
+      if (res.second) {
+        GOOGLE_PROTOBUF_ASSERT_RETURN(
+            ctx->StoreGroup(parent, child, depth, tag), {});
+        return {ptr, true};
+      }
+      break;
+    }
+    case WireType::WIRETYPE_END_GROUP: {
+      field_parser.EndGroup(number);
+      ctx->EndGroup(tag);
+      return {ptr, true};
+    }
+    case WireType::WIRETYPE_FIXED32: {
+      uint32 value = io::UnalignedLoad<uint32>(ptr);
+      ptr += 4;
+      field_parser.AddFixed32(number, value);
+      break;
+    }
+    default:
+      GOOGLE_PROTOBUF_ASSERT_RETURN(false, {});
+  }
+  ABSL_ASSERT(ptr != nullptr);
+  return {ptr, false};
+}
+
+template <typename T>
+const char* WireFormatParser(ParseClosure parent, T field_parser,
+                             const char* begin, const char* end,
+                             ParseContext* ctx) {
+  auto ptr = begin;
+  while (ptr < end) {
+    uint32 tag;
+    ptr = Varint::Parse32(ptr, &tag);
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+    auto res = FieldParser(tag, parent, field_parser, ptr, end, ctx);
+    ptr = res.first;
+    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
+    if (res.second) return ptr;
+  }
+  return ptr;
+}
+
+// Here are the elementary parsers for length delimited subfields that contain
+// plain data (ie not a protobuf). These are trivial as they don't recurse,
+// except for the UnknownGroupLiteParse that parses a group into a string.
+// Some functions need extra arguments that the function signature allows,
+// these are passed through variables in ParseContext::ExtraParseData that the
+// caller needs to set prior to the call.
+
+// The null parser does not do anything, but is useful as a substitute.
+const char* NullParser(const char* begin, const char* end, void* object,
+                       ParseContext*);
+
+// Helper for verification of utf8
+bool VerifyUTF8(StringPiece s, ParseContext* ctx);
+// All the string parsers with or without UTF checking and for all CTypes.
+const char* StringParser(const char* begin, const char* end, void* object,
+                         ParseContext*);
+const char* CordParser(const char* begin, const char* end, void* object,
+                       ParseContext*);
+const char* StringPieceParser(const char* begin, const char* end, void* object,
+                              ParseContext*);
+const char* StringParserUTF8(const char* begin, const char* end, void* object,
+                             ParseContext*);
+const char* CordParserUTF8(const char* begin, const char* end, void* object,
+                           ParseContext*);
+const char* StringPieceParserUTF8(const char* begin, const char* end,
+                                  void* object, ParseContext*);
+const char* StringParserUTF8Verify(const char* begin, const char* end,
+                                   void* object, ParseContext*);
+const char* CordParserUTF8Verify(const char* begin, const char* end,
+                                 void* object, ParseContext*);
+const char* StringPieceParserUTF8Verify(const char* begin, const char* end,
+                                        void* object, ParseContext*);
+// Parsers that also eat the slopbytes if possible. Can only be called in a
+// ParseContext where limit_ is set properly.
+const char* GreedyStringParser(const char* begin, const char* end, void* object,
+                         ParseContext*);
+const char* GreedyStringParserUTF8(const char* begin, const char* end, void* object,
+                             ParseContext*);
+const char* GreedyStringParserUTF8Verify(const char* begin, const char* end,
+                                   void* object, ParseContext*);
+
+// This is the only recursive parser.
+const char* UnknownGroupLiteParse(const char* begin, const char* end,
+                                  void* object, ParseContext* ctx);
+// This is a helper to for the UnknownGroupLiteParse but is actually also
+// useful in the generated code. It uses overload on string* vs
+// UnknownFieldSet* to make the generated code isomorphic between full and lite.
+std::pair<const char*, bool> UnknownFieldParse(uint32 tag, ParseClosure parent,
+                                               const char* begin,
+                                               const char* end, std::string* unknown,
+                                               ParseContext* ctx);
+
+// The packed parsers parse repeated numeric primitives directly into  the
+// corresponding field
+
+// These are packed varints
+const char* PackedInt32Parser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx);
+const char* PackedUInt32Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx);
+const char* PackedInt64Parser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx);
+const char* PackedUInt64Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx);
+const char* PackedSInt32Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx);
+const char* PackedSInt64Parser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx);
+const char* PackedBoolParser(const char* begin, const char* end, void* object,
+                             ParseContext* ctx);
+
+// Enums in proto3 do not require verification
+const char* PackedEnumParser(const char* begin, const char* end, void* object,
+                             ParseContext* ctx);
+// Enums in proto2 require verification. So an additional verification function
+// needs to be passed into ExtraParseData.
+// If it's a generated verification function we only need the function pointer.
+const char* PackedValidEnumParserLite(const char* begin, const char* end,
+                                      void* object, ParseContext* ctx);
+// If it's reflective we need a function that takes an additional argument.
+const char* PackedValidEnumParserLiteArg(const char* begin, const char* end,
+                                         void* object, ParseContext* ctx);
+
+// These are the packed fixed field parsers.
+const char* PackedFixed32Parser(const char* begin, const char* end,
+                                void* object, ParseContext* ctx);
+const char* PackedSFixed32Parser(const char* begin, const char* end,
+                                 void* object, ParseContext* ctx);
+const char* PackedFixed64Parser(const char* begin, const char* end,
+                                void* object, ParseContext* ctx);
+const char* PackedSFixed64Parser(const char* begin, const char* end,
+                                 void* object, ParseContext* ctx);
+const char* PackedFloatParser(const char* begin, const char* end, void* object,
+                              ParseContext* ctx);
+const char* PackedDoubleParser(const char* begin, const char* end, void* object,
+                               ParseContext* ctx);
+
+// Maps key/value's are stored in a MapEntry length delimited field. If this
+// crosses a seam we fallback to first store in payload. The object points
+// to a MapField in which we parse the payload upon done (we detect this when
+// this function is called with limit_ == 0), by calling parse_map (also stored
+// in ctx) on the resulting string.
+const char* SlowMapEntryParser(const char* begin, const char* end, void* object,
+                               internal::ParseContext* ctx);
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#include <google/protobuf/port_undef.inc>
+
+#endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
+#endif  // GOOGLE_PROTOBUF_PARSE_CONTEXT_H__
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 113605f..65d0821 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -82,6 +82,9 @@
 #ifdef PROTOBUF_RETURNS_NONNULL
 #error PROTOBUF_RETURNS_NONNULL was previously defined
 #endif
+#ifdef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#error PROTOBUF_ATTRIBUTE_REINITIALIZES was previously defined
+#endif
 #ifdef PROTOBUF_RTTI
 #error PROTOBUF_RTTI was previously defined
 #endif
@@ -206,9 +209,20 @@
 #else
 #ifdef __GNUC__
 #define PROTOBUF_RETURNS_NONNULL __attribute__((returns_nonnull))
+#else
+#define PROTOBUF_RETURNS_NONNULL
 #endif
 #endif
 
+#if defined(__has_cpp_attribute)
+#if __has_cpp_attribute(clang::reinitializes)
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#endif
+#endif
+#ifndef PROTOBUF_ATTRIBUTE_REINITIALIZES
+#define PROTOBUF_ATTRIBUTE_REINITIALIZES
+#endif
+
 #define PROTOBUF_GUARDED_BY(x)
 #define PROTOBUF_COLD
 
@@ -306,3 +320,10 @@
 #pragma push_macro("GetMessage")
 #undef GetMessage
 #endif
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+// TODO(gerbens) ideally we cleanup the code. But a cursory try shows many
+// violations. So let's ignore for now.
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index 84eecf5..b3177cd 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -31,6 +31,9 @@
 // #undefs all macros defined in port_def.inc.  See comments in port_def.inc
 // for more info.
 
+#ifndef PROTOBUF_NAMESPACE
+#error "port_undef.inc must be included after port_def.inc"
+#endif
 #undef PROTOBUF_NAMESPACE
 #undef PROTOBUF_NAMESPACE_ID
 #undef PROTOBUF_ALWAYS_INLINE
@@ -41,6 +44,7 @@
 #undef PROTOBUF_DEPRECATED_MSG
 #undef PROTOBUF_FUNC_ALIGN
 #undef PROTOBUF_RETURNS_NONNULL
+#undef PROTOBUF_ATTRIBUTE_REINITIALIZES
 #undef PROTOBUF_RTTI
 #undef PROTOBUF_VERSION
 #undef PROTOBUF_VERSION_SUFFIX
@@ -60,3 +64,7 @@
 #ifdef _MSC_VER
 #pragma pop_macro("GetMessage")
 #endif
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc
index f028b2b..233ba7d 100644
--- a/src/google/protobuf/reflection_ops.cc
+++ b/src/google/protobuf/reflection_ops.cc
@@ -84,6 +84,19 @@
     const FieldDescriptor* field = fields[i];
 
     if (field->is_repeated()) {
+      if (field->is_map()) {
+        MapFieldBase* from_field =
+            from_reflection->MapData(const_cast<Message*>(&from), field);
+        MapFieldBase* to_field =
+            to_reflection->MapData(const_cast<Message*>(to), field);
+        // Use map reflection if both are in map status and have the
+        // same map type to avoid sync with repeated field.
+        if (to_field->IsMapValid() && from_field->IsMapValid()
+            && typeid(*from_field) == typeid(*to_field)) {
+          to_field->MergeFrom(*from_field);
+          continue;
+        }
+      }
       int count = from_reflection->FieldSize(from, field);
       for (int j = 0; j < count; j++) {
         switch (field->cpp_type()) {
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index a3dd41d..1ebde35 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -68,8 +68,7 @@
   file_level_metadata_google_2fprotobuf_2fsource_5fcontext_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto, file_level_service_descriptors_google_2fprotobuf_2fsource_5fcontext_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fsource_5fcontext_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto[] =
   "\n$google/protobuf/source_context.proto\022\017"
   "google.protobuf\"\"\n\rSourceContext\022\021\n\tfile"
   "_name\030\001 \001(\tB\225\001\n\023com.google.protobufB\022Sou"
@@ -77,7 +76,10 @@
   "proto/protobuf/source_context;source_con"
   "text\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTy"
   "pesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fsource_5fcontext_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fsource_5fcontext_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fsource_5fcontext_2eproto,
   "google/protobuf/source_context.proto", &assign_descriptors_table_google_2fprotobuf_2fsource_5fcontext_2eproto, 251,
 };
 
@@ -161,10 +163,10 @@
   auto msg = static_cast<SourceContext*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -174,26 +176,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.SourceContext.file_name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_file_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_file_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -204,7 +209,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index b6fed22..5c5fe86 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -118,7 +118,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const SourceContext& from);
   void MergeFrom(const SourceContext& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 10e33ca..6472923 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -137,8 +137,7 @@
   file_level_metadata_google_2fprotobuf_2fstruct_2eproto, 4, file_level_enum_descriptors_google_2fprotobuf_2fstruct_2eproto, file_level_service_descriptors_google_2fprotobuf_2fstruct_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fstruct_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto[] =
   "\n\034google/protobuf/struct.proto\022\017google.p"
   "rotobuf\"\204\001\n\006Struct\0223\n\006fields\030\001 \003(\0132#.goo"
   "gle.protobuf.Struct.FieldsEntry\032E\n\013Field"
@@ -156,7 +155,10 @@
   "protobuf/ptypes/struct;structpb\370\001\001\242\002\003GPB"
   "\252\002\036Google.Protobuf.WellKnownTypesb\006proto"
   "3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fstruct_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fstruct_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fstruct_2eproto,
   "google/protobuf/struct.proto", &assign_descriptors_table_google_2fprotobuf_2fstruct_2eproto, 641,
 };
 
@@ -300,10 +302,10 @@
   auto msg = static_cast<Struct*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -329,13 +331,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -346,7 +348,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -849,10 +851,10 @@
   auto msg = static_cast<Value*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -881,14 +883,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Value.string_value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_string_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_string_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // bool bool_value = 4;
@@ -934,13 +939,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -951,7 +956,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1413,10 +1418,10 @@
   auto msg = static_cast<ListValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1441,13 +1446,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1458,7 +1463,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 224fe81..3aa798a 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -185,7 +185,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Struct& from);
   void MergeFrom(const Struct& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -330,7 +330,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Value& from);
   void MergeFrom(const Value& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -548,7 +548,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const ListValue& from);
   void MergeFrom(const ListValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h
index 7cce442..ab4a3aa 100644
--- a/src/google/protobuf/stubs/callback.h
+++ b/src/google/protobuf/stubs/callback.h
@@ -373,12 +373,12 @@
 };
 
 template <typename R, typename T, typename P1, typename P2, typename P3,
-          typename P4, typename P5, typename A1, typename A2>
-class MethodResultCallback_5_2 : public ResultCallback2<R, A1, A2> {
+          typename P4, typename P5, typename P6, typename A1, typename A2>
+class MethodResultCallback_6_2 : public ResultCallback2<R, A1, A2> {
  public:
-  typedef R (T::*MethodType)(P1, P2, P3, P4, P5, A1, A2);
-  MethodResultCallback_5_2(T* object, MethodType method, bool self_deleting,
-                           P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
+  typedef R (T::*MethodType)(P1, P2, P3, P4, P5, P6, A1, A2);
+  MethodResultCallback_6_2(T* object, MethodType method, bool self_deleting,
+                           P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
       : object_(object),
         method_(method),
         self_deleting_(self_deleting),
@@ -386,12 +386,13 @@
         p2_(p2),
         p3_(p3),
         p4_(p4),
-        p5_(p5) {}
-  ~MethodResultCallback_5_2() {}
+        p5_(p5),
+        p6_(p6) {}
+  ~MethodResultCallback_6_2() {}
 
   R Run(A1 a1, A2 a2) override {
     bool needs_delete = self_deleting_;
-    R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, a1, a2);
+    R result = (object_->*method_)(p1_, p2_, p3_, p4_, p5_, p6_, a1, a2);
     if (needs_delete) delete this;
     return result;
   }
@@ -405,6 +406,7 @@
   typename std::remove_reference<P3>::type p3_;
   typename std::remove_reference<P4>::type p4_;
   typename std::remove_reference<P5>::type p5_;
+  typename std::remove_reference<P6>::type p6_;
 };
 
 }  // namespace internal
@@ -553,19 +555,20 @@
   return new internal::MethodResultCallback_0_0<R, T1>(object, function, false);
 }
 
-// See MethodResultCallback_5_2
+// See MethodResultCallback_6_2
 template <typename R, typename T, typename P1, typename P2, typename P3,
-          typename P4, typename P5, typename A1, typename A2>
+          typename P4, typename P5, typename P6, typename A1, typename A2>
 inline ResultCallback2<R, A1, A2>* NewPermanentCallback(
-    T* object, R (T::*function)(P1, P2, P3, P4, P5, A1, A2),
+    T* object, R (T::*function)(P1, P2, P3, P4, P5, P6, A1, A2),
     typename internal::InternalConstRef<P1>::type p1,
     typename internal::InternalConstRef<P2>::type p2,
     typename internal::InternalConstRef<P3>::type p3,
     typename internal::InternalConstRef<P4>::type p4,
-    typename internal::InternalConstRef<P5>::type p5) {
-  return new internal::MethodResultCallback_5_2<R, T, P1, P2, P3, P4, P5, A1,
-                                                A2>(object, function, false, p1,
-                                                    p2, p3, p4, p5);
+    typename internal::InternalConstRef<P5>::type p5,
+    typename internal::InternalConstRef<P6>::type p6) {
+  return new internal::MethodResultCallback_6_2<R, T, P1, P2, P3, P4, P5, P6,
+                                                A1, A2>(object, function, false,
+                                                        p1, p2, p3, p4, p5, p6);
 }
 
 // A function which does nothing.  Useful for creating no-op callbacks, e.g.:
diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc
index f1a688d..8e330e0 100644
--- a/src/google/protobuf/stubs/common.cc
+++ b/src/google/protobuf/stubs/common.cc
@@ -32,6 +32,7 @@
 
 #include <google/protobuf/stubs/common.h>
 
+#include <atomic>
 #include <errno.h>
 #include <sstream>
 #include <stdio.h>
@@ -180,22 +181,7 @@
 }
 
 static LogHandler* log_handler_ = &DefaultLogHandler;
-static int log_silencer_count_ = 0;
-
-static Mutex* log_silencer_count_mutex_ = nullptr;
-GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_);
-
-void DeleteLogSilencerCount() {
-  delete log_silencer_count_mutex_;
-  log_silencer_count_mutex_ = nullptr;
-}
-void InitLogSilencerCount() {
-  log_silencer_count_mutex_ = new Mutex;
-  OnShutdown(&DeleteLogSilencerCount);
-}
-void InitLogSilencerCountOnce() {
-  GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
-}
+static std::atomic<int> log_silencer_count_ = ATOMIC_VAR_INIT(0);
 
 LogMessage& LogMessage::operator<<(const string& value) {
   message_ += value;
@@ -261,8 +247,6 @@
   bool suppress = false;
 
   if (level_ != LOGLEVEL_FATAL) {
-    InitLogSilencerCountOnce();
-    MutexLock lock(log_silencer_count_mutex_);
     suppress = log_silencer_count_ > 0;
   }
 
@@ -299,14 +283,10 @@
 }
 
 LogSilencer::LogSilencer() {
-  internal::InitLogSilencerCountOnce();
-  MutexLock lock(internal::log_silencer_count_mutex_);
   ++internal::log_silencer_count_;
 };
 
 LogSilencer::~LogSilencer() {
-  internal::InitLogSilencerCountOnce();
-  MutexLock lock(internal::log_silencer_count_mutex_);
   --internal::log_silencer_count_;
 };
 
diff --git a/src/google/protobuf/stubs/io_win32.h b/src/google/protobuf/stubs/io_win32.h
index afa5de3..69924dc 100644
--- a/src/google/protobuf/stubs/io_win32.h
+++ b/src/google/protobuf/stubs/io_win32.h
@@ -111,8 +111,8 @@
 #define STDOUT_FILENO 1
 #endif
 
-#endif  // defined(_WIN32)
-
 #include <google/protobuf/port_undef.inc>
 
+#endif  // defined(_WIN32)
+
 #endif  // GOOGLE_PROTOBUF_STUBS_IO_WIN32_H__
diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h
index f3835cc..feb71c1 100644
--- a/src/google/protobuf/stubs/once.h
+++ b/src/google/protobuf/stubs/once.h
@@ -28,53 +28,6 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Author: kenton@google.com (Kenton Varda)
-//
-// emulates google3/base/once.h
-//
-// This header is intended to be included only by internal .cc files and
-// generated .pb.cc files.  Users should not use this directly.
-//
-// This is basically a portable version of pthread_once().
-//
-// This header declares:
-// * A type called ProtobufOnceType.
-// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
-//   ProtobufOnceType.  This is the only legal way to declare such a variable.
-//   The macro may only be used at the global scope (you cannot create local or
-//   class member variables of this type).
-// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
-//   This function, when invoked multiple times given the same ProtobufOnceType
-//   object, will invoke init_func on the first call only, and will make sure
-//   none of the calls return before that first call to init_func has finished.
-// * The user can provide a parameter which GoogleOnceInit() forwards to the
-//   user-provided function when it is called. Usage example:
-//     int a = 10;
-//     GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
-// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
-//   static initializer generated).
-//
-// This implements a way to perform lazy initialization.  It's more efficient
-// than using mutexes as no lock is needed if initialization has already
-// happened.
-//
-// Example usage:
-//   void Init();
-//   GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
-//
-//   // Calls Init() exactly once.
-//   void InitOnce() {
-//     GoogleOnceInit(&once_init, &Init);
-//   }
-//
-// Note that if GoogleOnceInit() is called before main() has begun, it must
-// only be called by the thread that will eventually call main() -- that is,
-// the thread that performs dynamic initialization.  In general this is a safe
-// assumption since people don't usually construct threads before main() starts,
-// but it is technically not guaranteed.  Unfortunately, Win32 provides no way
-// whatsoever to statically-initialize its synchronization primitives, so our
-// only choice is to assume that dynamic initialization is single-threaded.
-
 #ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
 #define GOOGLE_PROTOBUF_STUBS_ONCE_H__
 
@@ -93,37 +46,6 @@
 
 }  // namespace internal
 
-// TODO(gerbens) remove this once third_party is fully extracted
-using ProtobufOnceType = internal::once_flag;
-
-inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
-  std::call_once(*once, init_func);
-}
-
-template <typename Arg>
-inline void GoogleOnceInitArg(ProtobufOnceType* once, void (*init_func)(Arg*),
-                              Arg* arg) {
-  std::call_once(*once, init_func, arg);
-}
-
-class GoogleOnceDynamic {
- public:
-  // If this->Init() has not been called before by any thread,
-  // execute (*func_with_arg)(arg) then return.
-  // Otherwise, wait until that prior invocation has finished
-  // executing its function, then return.
-  template<typename T>
-  void Init(void (*func_with_arg)(T*), T* arg) {
-    GoogleOnceInitArg<T>(&this->state_, func_with_arg, arg);
-  }
- private:
-  ProtobufOnceType state_;
-};
-
-#define GOOGLE_PROTOBUF_ONCE_TYPE ::google::protobuf::ProtobufOnceType
-#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
-  ::google::protobuf::ProtobufOnceType NAME
-
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/stubs/status.h b/src/google/protobuf/stubs/status.h
index 008416e..440a0ed 100644
--- a/src/google/protobuf/stubs/status.h
+++ b/src/google/protobuf/stubs/status.h
@@ -90,9 +90,15 @@
   int error_code() const {
     return error_code_;
   }
+  error::Code code() const {
+    return error_code_;
+  }
   StringPiece error_message() const {
     return error_message_;
   }
+  StringPiece message() const {
+    return error_message_;
+  }
 
   bool operator==(const Status& x) const;
   bool operator!=(const Status& x) const {
diff --git a/src/google/protobuf/stubs/status_test.cc b/src/google/protobuf/stubs/status_test.cc
index c70c33c..9a18778 100644
--- a/src/google/protobuf/stubs/status_test.cc
+++ b/src/google/protobuf/stubs/status_test.cc
@@ -40,13 +40,17 @@
 TEST(Status, Empty) {
   util::Status status;
   EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+  EXPECT_EQ(util::error::OK, util::Status::OK.code());
   EXPECT_EQ("OK", util::Status::OK.ToString());
 }
 
 TEST(Status, GenericCodes) {
   EXPECT_EQ(util::error::OK, util::Status::OK.error_code());
+  EXPECT_EQ(util::error::OK, util::Status::OK.code());
   EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.error_code());
+  EXPECT_EQ(util::error::CANCELLED, util::Status::CANCELLED.code());
   EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.error_code());
+  EXPECT_EQ(util::error::UNKNOWN, util::Status::UNKNOWN.code());
 }
 
 TEST(Status, ConstructorZero) {
@@ -66,14 +70,17 @@
   util::Status status(util::error::INVALID_ARGUMENT, "");
   EXPECT_FALSE(status.ok());
   EXPECT_EQ("", status.error_message().ToString());
+  EXPECT_EQ("", status.message().ToString());
   EXPECT_EQ("INVALID_ARGUMENT", status.ToString());
   status = util::Status(util::error::INVALID_ARGUMENT, "msg");
   EXPECT_FALSE(status.ok());
   EXPECT_EQ("msg", status.error_message().ToString());
+  EXPECT_EQ("msg", status.message().ToString());
   EXPECT_EQ("INVALID_ARGUMENT:msg", status.ToString());
   status = util::Status(util::error::OK, "msg");
   EXPECT_TRUE(status.ok());
   EXPECT_EQ("", status.error_message().ToString());
+  EXPECT_EQ("", status.message().ToString());
   EXPECT_EQ("OK", status.ToString());
 }
 
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index c8de875..a434509 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -32,17 +32,16 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
-#include <algorithm>
-#include <climits>
+#include <google/protobuf/text_format.h>
+
 #include <float.h>
 #include <math.h>
 #include <stdio.h>
-#include <stack>
+#include <algorithm>
+#include <climits>
 #include <limits>
 #include <vector>
 
-#include <google/protobuf/text_format.h>
-
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/any.h>
 #include <google/protobuf/descriptor.pb.h>
@@ -61,7 +60,6 @@
 
 
 
-
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 
@@ -446,8 +444,8 @@
                       descriptor->full_name() + "\".");
           return false;
         } else {
-          ReportWarning("Extension \"" + field_name + "\" is not defined or "
-                        "is not an extension of \"" +
+          ReportWarning("Ignoring extension \"" + field_name +
+                        "\" which is not defined or is not an extension of \"" +
                         descriptor->full_name() + "\".");
         }
       }
@@ -847,6 +845,8 @@
     if (!LookingAtType(io::Tokenizer::TYPE_INTEGER) &&
         !LookingAtType(io::Tokenizer::TYPE_FLOAT) &&
         !LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+      string text = tokenizer_.current().text;
+      ReportError("Cannot skip field value, unexpected token: " + text);
       return false;
     }
     // Combination of '-' and TYPE_IDENTIFIER may result in an invalid field
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 4a962e3..04684b6 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -69,15 +69,17 @@
   file_level_metadata_google_2fprotobuf_2ftimestamp_2eproto, 1, file_level_enum_descriptors_google_2fprotobuf_2ftimestamp_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftimestamp_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2ftimestamp_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto[] =
   "\n\037google/protobuf/timestamp.proto\022\017googl"
   "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003"
   "\022\r\n\005nanos\030\002 \001(\005B~\n\023com.google.protobufB\016"
   "TimestampProtoP\001Z+github.com/golang/prot"
   "obuf/ptypes/timestamp\370\001\001\242\002\003GPB\252\002\036Google."
   "Protobuf.WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftimestamp_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2ftimestamp_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2ftimestamp_2eproto,
   "google/protobuf/timestamp.proto", &assign_descriptors_table_google_2fprotobuf_2ftimestamp_2eproto, 231,
 };
 
@@ -176,10 +178,10 @@
   auto msg = static_cast<Timestamp*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -206,13 +208,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -223,7 +225,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 9839e92..2335796 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -125,7 +125,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Timestamp& from);
   void MergeFrom(const Timestamp& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto
index 05d988a..2b9e26a 100644
--- a/src/google/protobuf/timestamp.proto
+++ b/src/google/protobuf/timestamp.proto
@@ -113,7 +113,7 @@
 // 01:30 UTC on January 15, 2017.
 //
 // In JavaScript, one can convert a Date object to this format using the
-// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
+// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
 // method. In Python, a standard `datetime.datetime` object can be converted
 // to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
 // with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 2d00a8f..01b86a5 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -211,8 +211,7 @@
   file_level_metadata_google_2fprotobuf_2ftype_2eproto, 5, file_level_enum_descriptors_google_2fprotobuf_2ftype_2eproto, file_level_service_descriptors_google_2fprotobuf_2ftype_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2ftype_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] =
   "\n\032google/protobuf/type.proto\022\017google.pro"
   "tobuf\032\031google/protobuf/any.proto\032$google"
   "/protobuf/source_context.proto\"\327\001\n\004Type\022"
@@ -253,7 +252,10 @@
   "ufB\tTypeProtoP\001Z/google.golang.org/genpr"
   "oto/protobuf/ptype;ptype\370\001\001\242\002\003GPB\252\002\036Goog"
   "le.Protobuf.WellKnownTypesb\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2ftype_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
   "google/protobuf/type.proto", &assign_descriptors_table_google_2fprotobuf_2ftype_2eproto, 1594,
 };
 
@@ -503,10 +505,10 @@
   auto msg = static_cast<Type*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -516,14 +518,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Type.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.Field fields = 2;
@@ -551,14 +556,17 @@
           ptr = Varint::Parse32Inline(ptr, &size);
           GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
           ctx->extra_parse_data().SetFieldName("google.protobuf.Type.oneofs");
-          parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-          ::std::string* str = msg->add_oneofs();
-          str->clear();
-          object = str;
-          if (size > end - ptr) goto len_delim_till_end;
-          auto newend = ptr + size;
-          if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+          auto str = msg->add_oneofs();
+          if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+            object = str;
+            str->clear();
+            str->reserve(size);
+            parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+            goto len_delim_till_end;
+          }
+          GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+          ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+          ptr += size;
           if (ptr >= end) break;
         } while ((::google::protobuf::io::UnalignedLoad<::google::protobuf::uint64>(ptr) & 255) == 26 && (ptr += 1));
         break;
@@ -609,13 +617,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -626,7 +634,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1154,10 +1162,10 @@
   auto msg = static_cast<Field*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1197,14 +1205,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Field.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // string type_url = 6;
@@ -1213,14 +1224,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Field.type_url");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_type_url();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_type_url();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // int32 oneof_index = 7;
@@ -1267,14 +1281,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Field.json_name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_json_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_json_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // string default_value = 11;
@@ -1283,26 +1300,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Field.default_value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_default_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_default_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1313,7 +1333,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2005,10 +2025,10 @@
   auto msg = static_cast<Enum*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -2018,14 +2038,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Enum.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // repeated .google.protobuf.EnumValue enumvalue = 2;
@@ -2092,13 +2115,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2109,7 +2132,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2554,10 +2577,10 @@
   auto msg = static_cast<EnumValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -2567,14 +2590,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.EnumValue.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // int32 number = 2;
@@ -2608,13 +2634,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2625,7 +2651,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -3022,10 +3048,10 @@
   auto msg = static_cast<Option*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -3035,14 +3061,17 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.Option.name");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_name();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_name();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       // .google.protobuf.Any value = 2;
@@ -3063,13 +3092,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -3080,7 +3109,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 63d71e6..3c72010 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -226,7 +226,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Type& from);
   void MergeFrom(const Type& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -438,7 +438,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Field& from);
   void MergeFrom(const Field& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -791,7 +791,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Enum& from);
   void MergeFrom(const Enum& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -980,7 +980,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const EnumValue& from);
   void MergeFrom(const EnumValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1143,7 +1143,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Option& from);
   void MergeFrom(const Option& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 0226c76..fe3c825 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -352,23 +352,38 @@
   return ptr;
 }
 
+class UnknownFieldParserHelper {
+ public:
+  explicit UnknownFieldParserHelper(UnknownFieldSet* unknown)
+      : unknown_(unknown) {}
+
+  void AddVarint(uint32 num, uint64 value) { unknown_->AddVarint(num, value); }
+  void AddFixed64(uint32 num, uint64 value) {
+    unknown_->AddFixed64(num, value);
+  }
+  ParseClosure AddLengthDelimited(uint32 num, uint32 size) {
+    string* s = unknown_->AddLengthDelimited(num);
+    // TODO(gerbens) SECURITY: add security
+    s->reserve(size);
+    return {GreedyStringParser, s};
+  }
+  ParseClosure StartGroup(uint32 num) {
+    return {UnknownGroupParse, unknown_->AddGroup(num)};
+  }
+  void EndGroup(uint32 num) {}
+  void AddFixed32(uint32 num, uint32 value) {
+    unknown_->AddFixed32(num, value);
+  }
+
+ private:
+  UnknownFieldSet* unknown_;
+};
+
 const char* UnknownGroupParse(const char* begin, const char* end, void* object,
                               ParseContext* ctx) {
-  auto unknown = static_cast<UnknownFieldSet*>(object);
-
-  auto ptr = begin;
-  while (ptr < end) {
-    uint32 tag;
-    ptr = Varint::Parse32Inline(ptr, &tag);
-    GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-    GOOGLE_PROTOBUF_PARSER_ASSERT((tag >> 3) != 0);
-
-    auto res = UnknownFieldParse(tag, {UnknownGroupParse, unknown}, ptr, end,
-                                 unknown, ctx);
-    ptr = res.first;
-    if (res.second) break;
-  }
-  return ptr;
+  UnknownFieldParserHelper field_parser(static_cast<UnknownFieldSet*>(object));
+  return WireFormatParser({UnknownGroupParse, object}, field_parser, begin, end,
+                          ctx);
 }
 
 std::pair<const char*, bool> UnknownFieldParse(uint64 tag, ParseClosure parent,
@@ -376,73 +391,8 @@
                                                const char* end,
                                                UnknownFieldSet* unknown,
                                                ParseContext* ctx) {
-  uint32 size;
-  int depth;
-  void* object;
-  auto ptr = begin;
-
-  uint32 field_num = tag >> 3;
-  GOOGLE_PROTOBUF_ASSERT_RETURN(field_num != 0, std::make_pair(nullptr, true));
-  switch (tag & 7) {
-    case 0: {
-      uint64 val;
-      ptr = Varint::Parse64(ptr, &val);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-      unknown->AddVarint(field_num, val);
-      break;
-    }
-    case 1: {
-      uint64 val = UNALIGNED_LOAD64(ptr);
-      ptr = ptr + 8;
-      unknown->AddFixed64(field_num, val);
-      break;
-    }
-    case 2: {
-      ptr = Varint::Parse32Inline(ptr, &size);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-      object = unknown->AddLengthDelimited(field_num);
-      if (size > end - ptr) goto len_delim_till_end;
-      auto newend = ptr + size;
-      bool ok = ctx->ParseExactRange({StringParser, object}, ptr, newend);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-      ptr = newend;
-      break;
-    }
-    case 3: {
-      object = unknown->AddGroup(field_num);
-      bool ok = ctx->PrepareGroup(tag, &depth);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-      ptr = UnknownGroupParse(ptr, end, object, ctx);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ptr, std::make_pair(nullptr, true));
-      if (ctx->GroupContinues(depth)) goto group_continues;
-      break;
-    }
-    case 4: {
-      bool ok = ctx->ValidEndGroup(tag);
-      GOOGLE_PROTOBUF_ASSERT_RETURN(ok, std::make_pair(nullptr, true));
-      return std::make_pair(ptr, true);
-    }
-    case 5: {
-      uint32 val = UNALIGNED_LOAD32(ptr);
-      ptr = ptr + 4;
-      unknown->AddFixed32(field_num, val);
-      break;
-    }
-    default:
-      GOOGLE_PROTOBUF_ASSERT_RETURN(false, std::make_pair(nullptr, true));
-  }
-  return std::make_pair(ptr, false);
-len_delim_till_end:
-  // Length delimited field crosses end
-  return std::make_pair(
-      ctx->StoreAndTailCall(ptr, end, parent, {StringParser, object}, size),
-      true);
-group_continues:
-  GOOGLE_DCHECK(ptr >= end);
-  // Group crossed end and must be continued. Either this a parse failure
-  // or we need to resume on the next chunk and thus save the state.
-  ctx->StoreGroup(parent, {UnknownGroupParse, object}, depth);
-  return std::make_pair(ptr, true);
+  UnknownFieldParserHelper field_parser(unknown);
+  return FieldParser(tag, parent, field_parser, begin, end, ctx);
 }
 
 }  // namespace internal
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 7ba33da..0193b27 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -43,16 +43,13 @@
 #include <vector>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/parse_context.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/port.h>
 
 #include <google/protobuf/port_def.inc>
 
-#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-#include <google/protobuf/parse_context.h>
-#endif
-
 #ifdef SWIG
 #error "You cannot SWIG proto headers"
 #endif
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index 72b7d17..30060fe 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -367,7 +367,7 @@
       WebSafeBase64Escape(*dest, &encoded);
       // Remove trailing padding '=' characters before comparison.
       StringPiece src_no_padding = StringPiece(src).substr(
-          0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
                                       : src.length());
       return encoded == src_no_padding;
     }
@@ -381,7 +381,7 @@
           reinterpret_cast<const unsigned char*>(dest->data()), dest->length(),
           &encoded, false);
       StringPiece src_no_padding = StringPiece(src).substr(
-          0, StringEndsWith(src, "=") ? src.find_last_not_of('=') + 1
+          0, HasSuffixString(src, "=") ? src.find_last_not_of('=') + 1
                                       : src.length());
       return encoded == src_no_padding;
     }
diff --git a/src/google/protobuf/util/internal/expecting_objectwriter.h b/src/google/protobuf/util/internal/expecting_objectwriter.h
index 108a15b..7bc47a3 100644
--- a/src/google/protobuf/util/internal/expecting_objectwriter.h
+++ b/src/google/protobuf/util/internal/expecting_objectwriter.h
@@ -53,7 +53,7 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/util/internal/object_writer.h>
 #include <gmock/gmock.h>
-
+#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc
index b019012..669c051 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.cc
+++ b/src/google/protobuf/util/internal/field_mask_utility.cc
@@ -42,10 +42,6 @@
 namespace converter {
 
 namespace {
-inline util::Status CallPathSink(PathSinkCallback path_sink,
-                                   StringPiece arg) {
-  return path_sink->Run(arg);
-}
 
 // Appends a FieldMask path segment to a prefix.
 string AppendPathSegmentToPrefix(StringPiece prefix,
@@ -57,7 +53,7 @@
     return string(prefix);
   }
   // If the segment is a map key, appends it to the prefix without the ".".
-  if (StringStartsWith(segment, "[\"")) {
+  if (HasPrefixString(segment, "[\"")) {
     return StrCat(prefix, segment);
   }
   return StrCat(prefix, ".", segment);
@@ -192,8 +188,8 @@
       // When the current charactor is ')', ',' or the current position has
       // passed the end of the input, builds and outputs a new paths by
       // concatenating the last prefix with the current segment.
-      RETURN_IF_ERROR(CallPathSink(
-          path_sink, AppendPathSegmentToPrefix(current_prefix, segment)));
+      RETURN_IF_ERROR(
+          path_sink(AppendPathSegmentToPrefix(current_prefix, segment)));
     }
 
     // Removes the last prefix after seeing a ')'.
diff --git a/src/google/protobuf/util/internal/field_mask_utility.h b/src/google/protobuf/util/internal/field_mask_utility.h
index c2afbd5..a10b1ec 100644
--- a/src/google/protobuf/util/internal/field_mask_utility.h
+++ b/src/google/protobuf/util/internal/field_mask_utility.h
@@ -46,8 +46,8 @@
 namespace util {
 namespace converter {
 
-typedef std::string (*ConverterCallback)(StringPiece);
-typedef ResultCallback1<util::Status, StringPiece>* PathSinkCallback;
+typedef std::function<std::string(StringPiece)> ConverterCallback;
+typedef std::function<util::Status(StringPiece)> PathSinkCallback;
 
 // Applies a 'converter' to each segment of a FieldMask path and returns the
 // result. Quoted strings in the 'path' are copied to the output as-is without
diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc
index e272bbd..687f9e7 100644
--- a/src/google/protobuf/util/internal/json_stream_parser.cc
+++ b/src/google/protobuf/util/internal/json_stream_parser.cc
@@ -249,7 +249,8 @@
     }
     if (!result.ok()) {
       // If we were cancelled, save our state and try again later.
-      if (!finishing_ && result == util::Status(error::CANCELLED, "")) {
+      if (!finishing_ &&
+          result == util::Status(util::error::CANCELLED, "")) {
         stack_.push(type);
         // If we have a key we still need to render, make sure to save off the
         // contents in our own storage.
@@ -293,7 +294,7 @@
       // don't know if the next char would be e, completing it, or something
       // else, making it invalid.
       if (!finishing_ && p_.length() < false_len) {
-        return util::Status(error::CANCELLED, "");
+        return util::Status(util::error::CANCELLED, "");
       }
       return ReportFailure("Unexpected token.");
     }
@@ -331,7 +332,7 @@
       // depending on if we expect more data later.
       if (p_.length() == 1) {
         if (!finishing_) {
-          return util::Status(error::CANCELLED, "");
+          return util::Status(util::error::CANCELLED, "");
         }
         return ReportFailure("Closing quote expected in string.");
       }
@@ -399,7 +400,7 @@
   }
   // If we didn't find the closing quote but we expect more data, cancel for now
   if (!finishing_) {
-    return util::Status(error::CANCELLED, "");
+    return util::Status(util::error::CANCELLED, "");
   }
   // End of string reached without a closing quote, report an error.
   string_open_ = 0;
@@ -416,7 +417,7 @@
 util::Status JsonStreamParser::ParseUnicodeEscape() {
   if (p_.length() < kUnicodeEscapedLength) {
     if (!finishing_) {
-      return util::Status(error::CANCELLED, "");
+      return util::Status(util::error::CANCELLED, "");
     }
     return ReportFailure("Illegal hex string.");
   }
@@ -433,7 +434,7 @@
       code <= JsonEscaping::kMaxHighSurrogate) {
     if (p_.length() < 2 * kUnicodeEscapedLength) {
       if (!finishing_) {
-        return util::Status(error::CANCELLED, "");
+        return util::Status(util::error::CANCELLED, "");
       }
       if (!coerce_to_utf8_) {
         return ReportFailure("Missing low surrogate.");
@@ -540,7 +541,7 @@
   // If the entire input is a valid number, and we may have more content in the
   // future, we abort for now and resume when we know more.
   if (index == length && !finishing_) {
-    return util::Status(error::CANCELLED, "");
+    return util::Status(util::error::CANCELLED, "");
   }
 
   // Create a string containing just the number, so we can use safe_strtoX
@@ -708,7 +709,7 @@
   // empty-null array value is relying on this ARRAY_MID token.
   stack_.push(ARRAY_MID);
   util::Status result = ParseValue(type);
-  if (result == util::Status(error::CANCELLED, "")) {
+  if (result == util::Status(util::error::CANCELLED, "")) {
     // If we were cancelled, pop back off the ARRAY_MID so we don't try to
     // push it on again when we try over.
     stack_.pop();
@@ -787,7 +788,7 @@
 util::Status JsonStreamParser::ReportUnknown(StringPiece message) {
   // If we aren't finishing the parse, cancel parsing and try later.
   if (!finishing_) {
-    return util::Status(error::CANCELLED, "");
+    return util::Status(util::error::CANCELLED, "");
   }
   if (p_.empty()) {
     return ReportFailure(StrCat("Unexpected end of string. ", message));
@@ -828,7 +829,7 @@
   // we can't know if the key was complete or not.
   if (!finishing_ && p_.empty()) {
     p_ = original;
-    return util::Status(error::CANCELLED, "");
+    return util::Status(util::error::CANCELLED, "");
   }
   // Since we aren't using the key storage, clear it out.
   key_storage_.clear();
diff --git a/src/google/protobuf/util/internal/mock_error_listener.h b/src/google/protobuf/util/internal/mock_error_listener.h
index 1f1321f..53e5876 100644
--- a/src/google/protobuf/util/internal/mock_error_listener.h
+++ b/src/google/protobuf/util/internal/mock_error_listener.h
@@ -34,7 +34,7 @@
 #include <google/protobuf/util/internal/error_listener.h>
 #include <google/protobuf/util/internal/location_tracker.h>
 #include <gmock/gmock.h>
-
+#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 56ee774..391c32e 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -386,27 +386,45 @@
 }
 
 string ProtoWriter::ProtoElement::ToString() const {
-  if (parent() == nullptr) return "";
-  string loc = parent()->ToString();
-  if (!ow_->IsRepeated(*parent_field_) ||
-      parent()->parent_field_ != parent_field_) {
-    string name = parent_field_->name();
-    int i = 0;
-    while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
-    if (i > 0 && i == name.size()) {  // safe field name
-      if (loc.empty()) {
-        loc = name;
+  string loc = "";
+
+  // first populate a stack with the nodes since we need to process them
+  // from root to leaf when generating the string location
+  const ProtoWriter::ProtoElement* now = this;
+  std::stack<const ProtoWriter::ProtoElement*> element_stack;
+  while (now->parent() != nullptr) {
+    element_stack.push(now);
+    now = now->parent();
+  }
+
+  // now pop each node from the stack and append to the location string
+  while (!element_stack.empty()) {
+    now = element_stack.top();
+    element_stack.pop();
+
+    if (!ow_->IsRepeated(*(now->parent_field_)) ||
+        now->parent()->parent_field_ != now->parent_field_) {
+      string name = now->parent_field_->name();
+      int i = 0;
+      while (i < name.size() && (ascii_isalnum(name[i]) || name[i] == '_')) ++i;
+      if (i > 0 && i == name.size()) {  // safe field name
+        if (loc.empty()) {
+          loc = name;
+        } else {
+          StrAppend(&loc, ".", name);
+        }
       } else {
-        StrAppend(&loc, ".", name);
+        StrAppend(&loc, "[\"", CEscape(name), "\"]");
       }
-    } else {
-      StrAppend(&loc, "[\"", CEscape(name), "\"]");
+    }
+
+    int array_index_now = now->array_index_;
+    if (ow_->IsRepeated(*(now->parent_field_)) && array_index_now > 0) {
+      StrAppend(&loc, "[", array_index_now - 1, "]");
     }
   }
-  if (ow_->IsRepeated(*parent_field_) && array_index_ > 0) {
-    StrAppend(&loc, "[", array_index_ - 1, "]");
-  }
-  return loc.empty() ? "." : loc;
+
+  return loc;
 }
 
 bool ProtoWriter::ProtoElement::IsOneofIndexTaken(int32 index) {
@@ -678,7 +696,8 @@
       break;
     }
     default:  // TYPE_GROUP or TYPE_MESSAGE
-      status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie());
+      status = Status(util::error::INVALID_ARGUMENT,
+                      data.ToString().ValueOrDie());
   }
 
   if (!status.ok()) {
@@ -687,7 +706,7 @@
       element_.reset(new ProtoElement(element_.release(), &field, type, false));
     }
     InvalidValue(google::protobuf::Field_Kind_Name(field.kind()),
-                 status.error_message());
+                 status.message());
     element_.reset(element()->pop());
     return this;
   }
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 97a8bb4..55e8e4b 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -49,7 +49,6 @@
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/casts.h>
 
-
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/status_macros.h>
 
@@ -128,7 +127,8 @@
       max_recursion_depth_(kDefaultMaxRecursionDepth),
       render_unknown_fields_(false),
       render_unknown_enum_values_(true),
-      add_trailing_zeros_for_timestamp_and_duration_(false) {
+      add_trailing_zeros_for_timestamp_and_duration_(false),
+      suppress_empty_object_(false) {
   GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
 }
 
@@ -146,7 +146,8 @@
       max_recursion_depth_(kDefaultMaxRecursionDepth),
       render_unknown_fields_(false),
       render_unknown_enum_values_(true),
-      add_trailing_zeros_for_timestamp_and_duration_(false) {
+      add_trailing_zeros_for_timestamp_and_duration_(false),
+      suppress_empty_object_(false) {
   GOOGLE_LOG_IF(DFATAL, stream == nullptr) << "Input stream is nullptr.";
 }
 
@@ -198,6 +199,10 @@
   uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
   UnknownFieldSet unknown_fields;
 
+  if (tag == end_tag && suppress_empty_object_) {
+    return util::Status();
+  }
+
   if (include_start_and_end) {
     ow->StartObject(name);
   }
@@ -640,7 +645,7 @@
     // Convert into an internal error, since this means the backend gave us
     // an invalid response (missing or invalid type information).
     return util::Status(util::error::INTERNAL,
-                        resolved_type.status().error_message());
+                        resolved_type.status().message());
   }
   // nested_type cannot be null at this time.
   const google::protobuf::Type* nested_type = resolved_type.ValueOrDie();
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index c254987..5ff8327 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -325,6 +325,11 @@
   // Whether to add trailing zeros for timestamp and duration.
   bool add_trailing_zeros_for_timestamp_and_duration_;
 
+  // Whether output the empty object or not. If false, output JSON string like:
+  // "'objectName' : {}". If true, then no outputs. This only happens when all
+  // the fields of the message are filtered out by field mask.
+  bool suppress_empty_object_;
+
   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
 };
 
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 9c52116..f2f0f3f 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -59,6 +59,7 @@
 using util::Status;
 using util::StatusOr;
 using util::error::INVALID_ARGUMENT;
+using std::placeholders::_1;
 
 
 ProtoStreamObjectWriter::ProtoStreamObjectWriter(
@@ -139,14 +140,14 @@
   // conversion to 'nanos', rather than a double, so that there is no
   // loss of precision.
   if (!s_nanos.empty() && !safe_strto32(s_nanos, &i_nanos)) {
-    return Status(INVALID_ARGUMENT, parse_failure_message);
+    return Status(util::error::INVALID_ARGUMENT, parse_failure_message);
   }
   if (i_nanos > kNanosPerSecond || i_nanos < 0) {
-    return Status(INVALID_ARGUMENT, exceeded_limit_message);
+    return Status(util::error::INVALID_ARGUMENT, exceeded_limit_message);
   }
   // s_nanos should only have digits. No whitespace.
   if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
-    return Status(INVALID_ARGUMENT, parse_failure_message);
+    return Status(util::error::INVALID_ARGUMENT, parse_failure_message);
   }
 
   if (i_nanos > 0) {
@@ -186,7 +187,8 @@
         conversion = 1;
         break;
       default:
-        return Status(INVALID_ARGUMENT, exceeded_limit_message);
+        return Status(util::error::INVALID_ARGUMENT,
+                      exceeded_limit_message);
     }
     *nanos = i_nanos * conversion;
   }
@@ -311,7 +313,7 @@
     } else {
       ow_->ProtoWriter::StartObject("");
       Status status = (*well_known_type_render_)(ow_.get(), value);
-      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
+      if (!status.ok()) ow_->InvalidValue("Any", status.message());
       ow_->ProtoWriter::EndObject();
     }
   } else {
@@ -327,7 +329,7 @@
   } else {
     StatusOr<string> s = value.ToString();
     if (!s.ok()) {
-      parent_->InvalidValue("String", s.status().error_message());
+      parent_->InvalidValue("String", s.status().message());
       invalid_ = true;
       return;
     }
@@ -337,7 +339,7 @@
   StatusOr<const google::protobuf::Type*> resolved_type =
       parent_->typeinfo()->ResolveTypeUrl(type_url_);
   if (!resolved_type.ok()) {
-    parent_->InvalidValue("Any", resolved_type.status().error_message());
+    parent_->InvalidValue("Any", resolved_type.status().message());
     invalid_ = true;
     return;
   }
@@ -354,8 +356,9 @@
 
   // Create our object writer and initialize it with the first StartObject
   // call.
-  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
-                                        parent_->listener(), parent_->options_));
+  ow_.reset(new ProtoStreamObjectWriter(
+      parent_->typeinfo(), *type, &output_, parent_->listener(),
+      parent_->options_));
 
   // Don't call StartObject() for well-known types yet. Depending on the
   // type of actual data, we may not need to call StartObject(). For
@@ -930,7 +933,7 @@
       break;
     }
     default: {
-      return Status(INVALID_ARGUMENT,
+      return Status(util::error::INVALID_ARGUMENT,
                     "Invalid struct data type. Only number, string, boolean or "
                     "null values are supported.");
     }
@@ -943,7 +946,7 @@
                                                 const DataPiece& data) {
   if (data.type() == DataPiece::TYPE_NULL) return Status();
   if (data.type() != DataPiece::TYPE_STRING) {
-    return Status(INVALID_ARGUMENT,
+    return Status(util::error::INVALID_ARGUMENT,
                   StrCat("Invalid data type for timestamp, value is ",
                                data.ValueAsStringOrDefault("")));
   }
@@ -974,7 +977,7 @@
                                                 const DataPiece& data) {
   if (data.type() == DataPiece::TYPE_NULL) return Status();
   if (data.type() != DataPiece::TYPE_STRING) {
-    return Status(INVALID_ARGUMENT,
+    return Status(util::error::INVALID_ARGUMENT,
                   StrCat("Invalid data type for field mask, value is ",
                                data.ValueAsStringOrDefault("")));
   }
@@ -982,29 +985,28 @@
 // TODO(tsun): figure out how to do proto descriptor based snake case
 // conversions as much as possible. Because ToSnakeCase sometimes returns the
 // wrong value.
-  std::unique_ptr<ResultCallback1<util::Status, StringPiece>> callback(
-      ::google::protobuf::NewPermanentCallback(&RenderOneFieldPath, ow));
-  return DecodeCompactFieldMaskPaths(data.str(), callback.get());
+  return DecodeCompactFieldMaskPaths(data.str(),
+                                     std::bind(&RenderOneFieldPath, ow, _1));
 }
 
 Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
                                                const DataPiece& data) {
   if (data.type() == DataPiece::TYPE_NULL) return Status();
   if (data.type() != DataPiece::TYPE_STRING) {
-    return Status(INVALID_ARGUMENT,
+    return Status(util::error::INVALID_ARGUMENT,
                   StrCat("Invalid data type for duration, value is ",
                                data.ValueAsStringOrDefault("")));
   }
 
   StringPiece value(data.str());
 
-  if (!StringEndsWith(value, "s")) {
-    return Status(INVALID_ARGUMENT,
+  if (!HasSuffixString(value, "s")) {
+    return Status(util::error::INVALID_ARGUMENT,
                   "Illegal duration format; duration must end with 's'");
   }
   value = value.substr(0, value.size() - 1);
   int sign = 1;
-  if (StringStartsWith(value, "-")) {
+  if (HasPrefixString(value, "-")) {
     sign = -1;
     value = value.substr(1);
   }
@@ -1013,7 +1015,7 @@
   SplitSecondsAndNanos(value, &s_secs, &s_nanos);
   uint64 unsigned_seconds;
   if (!safe_strtou64(s_secs, &unsigned_seconds)) {
-    return Status(INVALID_ARGUMENT,
+    return Status(util::error::INVALID_ARGUMENT,
                   "Invalid duration format, failed to parse seconds");
   }
 
@@ -1029,7 +1031,8 @@
   int64 seconds = sign * unsigned_seconds;
   if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
       nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
-    return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
+    return Status(util::error::INVALID_ARGUMENT,
+                  "Duration value exceeds limits");
   }
 
   ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
@@ -1063,8 +1066,8 @@
     ProtoWriter::StartObject(name);
     status = (*type_renderer)(this, data);
     if (!status.ok()) {
-      InvalidValue(master_type_.name(), StrCat("Field '", name, "', ",
-                                                     status.error_message()));
+      InvalidValue(master_type_.name(),
+                   StrCat("Field '", name, "', ", status.message()));
     }
     ProtoWriter::EndObject();
     return this;
@@ -1109,8 +1112,8 @@
       Push("value", Item::MESSAGE, true, false);
       status = (*type_renderer)(this, data);
       if (!status.ok()) {
-        InvalidValue(field->type_url(), StrCat("Field '", name, "', ",
-                                                     status.error_message()));
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.message()));
       }
       Pop();
       return this;
@@ -1143,8 +1146,8 @@
       Push(name, Item::MESSAGE, false, false);
       status = (*type_renderer)(this, data);
       if (!status.ok()) {
-        InvalidValue(field->type_url(), StrCat("Field '", name, "', ",
-                                                     status.error_message()));
+        InvalidValue(field->type_url(),
+                     StrCat("Field '", name, "', ", status.message()));
       }
       Pop();
     }
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index fe8170d..bdb70c7 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -330,7 +330,7 @@
                           const google::protobuf::Type& type,
                           strings::ByteSink* output, ErrorListener* listener);
 
- ProtoStreamObjectWriter(const TypeInfo* typeinfo,
+  ProtoStreamObjectWriter(const TypeInfo* typeinfo,
                           const google::protobuf::Type& type,
                           strings::ByteSink* output, ErrorListener* listener,
                           const ProtoStreamObjectWriter::Options& options);
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
index 66a8f00..c464696 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
@@ -58,7 +58,6 @@
 #include <gtest/gtest.h>
 
 
-
 namespace google {
 namespace protobuf {
 namespace util {
diff --git a/src/google/protobuf/util/internal/testdata/anys.proto b/src/google/protobuf/util/internal/testdata/anys.proto
index 77c1043..4749b77 100644
--- a/src/google/protobuf/util/internal/testdata/anys.proto
+++ b/src/google/protobuf/util/internal/testdata/anys.proto
@@ -58,9 +58,13 @@
   AnyWrapper any_with_message_containing_repeated_message = 14;
   AnyWrapper recursive_any_with_type_field_at_end = 15;
   AnyWrapper repeated_any = 16;
+  AnyWrapper empty_any_with_null_type_url = 17;
 
   google.protobuf.Any top_level_any = 50;
   google.protobuf.Any top_level_any_with_type_field_at_end = 51;
+  google.protobuf.Any top_level_any_with_pivot_one = 52;
+  google.protobuf.Any top_level_any_with_pivot_two = 53;
+  google.protobuf.Any top_level_any_unordered = 54;
 }
 
 message AnyWrapper {
diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto
index 812474b..6068ce6 100644
--- a/src/google/protobuf/util/internal/testdata/books.proto
+++ b/src/google/protobuf/util/internal/testdata/books.proto
@@ -39,6 +39,8 @@
 
 package google.protobuf.testing;
 
+import "google/protobuf/util/internal/testdata/anys.proto";
+
 // A book
 message Book {
   optional string title = 1;
@@ -72,6 +74,13 @@
   // Useful for testing JSON snake/camel-case conversions.
   optional string snake_field = 12;
 
+  // Used to test type not found in type info. Messages defined in other files
+  // are not added when adding Book to type info.
+  optional AnyWrapper type_not_found = 13;
+
+  // Used to test invalid value inside of primitive repeated fields.
+  repeated int32 primitive_repeated = 14;
+
   extensions 200 to 499;
 }
 
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index 7c7e3f1..49e85a1 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -408,13 +408,6 @@
   return true;
 }
 
-bool StringStartsWith(StringPiece text, StringPiece prefix) {
-  return text.starts_with(prefix);
-}
-
-bool StringEndsWith(StringPiece text, StringPiece suffix) {
-  return text.ends_with(suffix);
-}
 }  // namespace converter
 }  // namespace util
 }  // namespace protobuf
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 6fe8295..29935d6 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -204,11 +204,6 @@
 // value fits into double but not float (e.g., DBL_MAX).
 PROTOBUF_EXPORT bool SafeStrToFloat(StringPiece str, float* value);
 
-// Returns whether a StringPiece begins with the provided prefix.
-bool StringStartsWith(StringPiece text, StringPiece prefix);
-
-// Returns whether a StringPiece ends with the provided suffix.
-bool StringEndsWith(StringPiece text, StringPiece suffix);
 }  // namespace converter
 }  // namespace util
 }  // namespace protobuf
diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto
index 40b040e..767611f 100644
--- a/src/google/protobuf/util/json_format.proto
+++ b/src/google/protobuf/util/json_format.proto
@@ -107,3 +107,7 @@
   optional int32 value = 1;
   optional TestRecursion child = 2;
 }
+
+message TestStringMap {
+  map<string, string> string_map = 1;
+}
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index 19e20a4..0d2173c 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -44,7 +44,7 @@
 #include <google/protobuf/util/type_resolver_util.h>
 #include <google/protobuf/stubs/bytestream.h>
 
-
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/status_macros.h>
 
 #include <google/protobuf/port_def.inc>
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index f62e7f0..015ca58 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -36,7 +36,7 @@
 #include <google/protobuf/message.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/stubs/bytestream.h>
-
+#include <google/protobuf/stubs/strutil.h>
 
 #include <google/protobuf/port_def.inc>
 
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc
index 125d4d4..23da45b 100644
--- a/src/google/protobuf/util/json_util_test.cc
+++ b/src/google/protobuf/util/json_util_test.cc
@@ -363,11 +363,11 @@
       "{\n"
       "  \"value\": {\n"
       "    \"@type\": \"type.googleapis.com/proto3.TestMessage\",\n"
-      "    \"unknown_field\": \"UNKOWN_VALUE\",\n"
+      "    \"unknown_field\": \"UNKNOWN_VALUE\",\n"
       "    \"string_value\": \"expected_value\"\n"
       "  }\n"
       "}";
-      
+
   TestAny m;
   JsonParseOptions options;
   EXPECT_FALSE(FromJson(input, &m, options));
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index 8a09400..3e00d07 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -58,6 +58,38 @@
 
 namespace util {
 
+// A reporter to report the total number of diffs.
+// TODO(ykzhu): we can improve this to take into account the value differencers.
+class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Reporter {
+ public:
+  NumDiffsReporter() : num_diffs_(0) {}
+
+  // Returns the total number of diffs.
+  int32 GetNumDiffs() const { return num_diffs_; }
+  void Reset() { num_diffs_ = 0; }
+
+  // Report that a field has been added into Message2.
+  void ReportAdded(
+      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+          field_path) override { ++num_diffs_; }
+
+  // Report that a field has been deleted from Message1.
+  void ReportDeleted(
+      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+          field_path) override { ++num_diffs_; }
+
+  // Report that the value of a field has been modified.
+  void ReportModified(
+      const google::protobuf::Message& message1, const google::protobuf::Message& message2,
+      const std::vector<google::protobuf::util::MessageDifferencer::SpecificField>&
+          field_path) override { ++num_diffs_; }
+
+ private:
+  int32 num_diffs_;
+};
+
 // When comparing a repeated field as map, MultipleFieldMapKeyComparator can
 // be used to specify multiple fields as key for key comparison.
 // Two elements of a repeated field will be regarded as having the same key
@@ -144,6 +176,27 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator);
 };
 
+// Preserve the order when treating repeated field as SMART_LIST. The current
+// implementation is to find the longest matching sequence from the first
+// element. The optimal solution requires to use //util/diff/lcs.h, which is
+// not open sourced yet. Overwrite this method if you want to have that.
+// TODO(ykzhu): change to use LCS once it is open sourced.
+void MatchIndicesPostProcessorForSmartList(
+    std::vector<int>* match_list1, std::vector<int>* match_list2) {
+  int last_matched_index = -1;
+  for (int i = 0; i < match_list1->size(); ++i) {
+    if (match_list1->at(i) < 0) {
+      continue;
+    }
+    if (last_matched_index < 0 || match_list1->at(i) > last_matched_index) {
+      last_matched_index = match_list1->at(i);
+    } else {
+      match_list2->at(match_list1->at(i)) = -1;
+      match_list1->at(i) = -1;
+    }
+  }
+}
+
 MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator(
     MessageDifferencer* message_differencer)
     : message_differencer_(message_differencer) {}
@@ -215,7 +268,9 @@
       report_matches_(false),
       report_moves_(true),
       report_ignores_(true),
-      output_string_(NULL) {}
+      output_string_(nullptr),
+      match_indices_for_smart_list_callback_(
+          MatchIndicesPostProcessorForSmartList) {}
 
 MessageDifferencer::~MessageDifferencer() {
   for (int i = 0; i < owned_key_comparators_.size(); ++i) {
@@ -255,36 +310,55 @@
   repeated_field_comparison_ = comparison;
 }
 
-void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+void MessageDifferencer::CheckRepeatedFieldComparisons(
+    const FieldDescriptor* field,
+    const RepeatedFieldComparison& new_comparison) {
   GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
                                << field->full_name();
   const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
   GOOGLE_CHECK(key_comparator == NULL)
-      << "Cannot treat this repeated field as both Map and Set for"
+      << "Cannot treat this repeated field as both MAP and "
+      << new_comparison
+      << " for"
       << " comparison.  Field name is: " << field->full_name();
-  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
-      << "Cannot treat the same field as both SET and LIST. Field name is: "
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end() ||
+        repeated_field_comparisons_[field] == new_comparison)
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and "
+      << new_comparison
+      <<". Field name is: "
       << field->full_name();
-  set_fields_.insert(field);
+}
+
+void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SET);
+  repeated_field_comparisons_[field] = AS_SET;
+}
+
+void MessageDifferencer::TreatAsSmartSet(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_SET);
+  repeated_field_comparisons_[field] = AS_SMART_SET;
+}
+
+void MessageDifferencer::SetMatchIndicesForSmartListCallback(
+    std::function<void(std::vector<int>*, std::vector<int>*)> callback) {
+  match_indices_for_smart_list_callback_ = callback;
 }
 
 void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
-  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
-                              << field->full_name();
-  const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
-  GOOGLE_CHECK(key_comparator == NULL)
-      << "Cannot treat this repeated field as both Map and Set for"
-      << " comparison.  Field name is: " << field->full_name();
-  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
-      << "Cannot treat the same field as both SET and LIST. Field name is: "
-      << field->full_name();
-  list_fields_.insert(field);
+  CheckRepeatedFieldComparisons(field, AS_LIST);
+  repeated_field_comparisons_[field] = AS_LIST;
+}
+
+void MessageDifferencer::TreatAsSmartList(const FieldDescriptor* field) {
+  CheckRepeatedFieldComparisons(field, AS_SMART_LIST);
+  repeated_field_comparisons_[field] = AS_SMART_LIST;
 }
 
 void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
                                     const FieldDescriptor* key) {
-  GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
-                               << field->full_name();
   GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
       << "Field has to be message type.  Field name is: "
       << field->full_name();
@@ -292,12 +366,12 @@
       << key->full_name()
       << " must be a direct subfield within the repeated field "
       << field->full_name() << ", not " << key->containing_type()->full_name();
-  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
-      << "Cannot treat this repeated field as both Map and Set for "
-      << "comparison.";
-  GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
-      << "Cannot treat this repeated field as both Map and List for "
-      << "comparison.";
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: "
+      << field->full_name();
   MapKeyComparator* key_comparator =
       new MultipleFieldsMapKeyComparator(this, key);
   owned_key_comparators_.push_back(key_comparator);
@@ -343,9 +417,12 @@
       }
     }
   }
-  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
-      << "Cannot treat this repeated field as both Map and Set for "
-      << "comparison.";
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+    << "Cannot treat the same field as both "
+    << repeated_field_comparisons_[field]
+    << " and MAP. Field name is: "
+    << field->full_name();
   MapKeyComparator* key_comparator =
       new MultipleFieldsMapKeyComparator(this, key_field_paths);
   owned_key_comparators_.push_back(key_comparator);
@@ -357,9 +434,12 @@
     const MapKeyComparator* key_comparator) {
   GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
                                << field->full_name();
-  GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
-      << "Cannot treat this repeated field as both Map and Set for "
-      << "comparison.";
+  GOOGLE_CHECK(repeated_field_comparisons_.find(field) ==
+        repeated_field_comparisons_.end())
+      << "Cannot treat the same field as both "
+      << repeated_field_comparisons_[field]
+      << " and MAP. Field name is: "
+      << field->full_name();
   map_field_key_comparator_[field] = key_comparator;
 }
 
@@ -795,7 +875,7 @@
     const FieldDescriptor* repeated_field,
     const MapKeyComparator* key_comparator, const Message* message1,
     const Message* message2, const std::vector<SpecificField>& parent_fields,
-    int index1, int index2) {
+    Reporter* reporter, int index1, int index2) {
   std::vector<SpecificField> current_parent_fields(parent_fields);
   if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
     return CompareFieldValueUsingParentFields(
@@ -806,7 +886,7 @@
   // following code.
   Reporter* backup_reporter = reporter_;
   string* output_string = output_string_;
-  reporter_ = NULL;
+  reporter_ = reporter;
   output_string_ = NULL;
   bool match;
 
@@ -876,10 +956,38 @@
 
   // At this point, we have already matched pairs of fields (with the reporting
   // to be done later). Now to check if the paired elements are different.
+  int next_unmatched_index = 0;
   for (int i = 0; i < count1; i++) {
-    if (match_list1[i] == -1) continue;
+    if (match_list1[i] == -1) {
+      if (IsTreatedAsSmartList(repeated_field)) {
+        if (reporter_ == nullptr) return false;
+        specific_field.index = i;
+        parent_fields->push_back(specific_field);
+        reporter_->ReportDeleted(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list1[i] = -2;
+      }
+      continue;
+    }
+    if (IsTreatedAsSmartList(repeated_field)) {
+      for (int j = next_unmatched_index; j < match_list1[i]; ++j) {
+        GOOGLE_CHECK_LE(0, j);
+        if (reporter_ == nullptr) return false;
+        specific_field.index = j;
+        specific_field.new_index = j;
+        parent_fields->push_back(specific_field);
+        reporter_->ReportAdded(message1, message2, *parent_fields);
+        parent_fields->pop_back();
+        fieldDifferent = true;
+        // Use -2 to mark this element has been reported.
+        match_list2[j] = -2;
+      }
+    }
     specific_field.index = i;
     specific_field.new_index = match_list1[i];
+    next_unmatched_index = match_list1[i] + 1;
 
     const bool result = CompareFieldValueUsingParentFields(
         message1, message2, repeated_field, i, specific_field.new_index,
@@ -996,9 +1104,29 @@
 
 bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
   if (!field->is_repeated()) return false;
-  if (repeated_field_comparison_ == AS_SET)
-    return list_fields_.find(field) == list_fields_.end();
-  return (set_fields_.find(field) != set_fields_.end());
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SET;
+  }
+  return repeated_field_comparison_ == AS_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartSet(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_SET;
+  }
+  return repeated_field_comparison_ == AS_SMART_SET;
+}
+
+bool MessageDifferencer::IsTreatedAsSmartList(const FieldDescriptor* field) {
+  if (!field->is_repeated()) return false;
+  if (repeated_field_comparisons_.find(field) !=
+      repeated_field_comparisons_.end()) {
+    return repeated_field_comparisons_[field] == AS_SMART_LIST;
+  }
+  return repeated_field_comparison_ == AS_SMART_LIST;
 }
 
 bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
@@ -1443,10 +1571,18 @@
   // before returning.
   Reporter* reporter = reporter_;
   reporter_ = NULL;
+  NumDiffsReporter num_diffs_reporter;
+  std::vector<int32> num_diffs_list1;
+  if (IsTreatedAsSmartSet(repeated_field)) {
+    num_diffs_list1.assign(count1, kint32max);
+  }
 
   bool success = true;
   // Find potential match if this is a special repeated field.
-  if (key_comparator != NULL || IsTreatedAsSet(repeated_field)) {
+  if (key_comparator != nullptr ||
+      IsTreatedAsSet(repeated_field) ||
+      IsTreatedAsSmartSet(repeated_field) ||
+      IsTreatedAsSmartList(repeated_field)) {
     if (scope_ == PARTIAL) {
       // When partial matching is enabled, Compare(a, b) && Compare(a, c)
       // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
@@ -1456,7 +1592,7 @@
           ::google::protobuf::NewPermanentCallback(
               this, &MessageDifferencer::IsMatch,
               repeated_field, key_comparator,
-              &message1, &message2, parent_fields);
+              &message1, &message2, parent_fields, nullptr);
       MaximumMatcher matcher(count1, count2, callback, match_list1,
                              match_list2);
       // If diff info is not needed, we should end the matching process as
@@ -1469,11 +1605,13 @@
       int start_offset = 0;
       // If the two repeated fields are treated as sets, optimize for the case
       // where both start with same items stored in the same order.
-      if (IsTreatedAsSet(repeated_field)) {
+      if (IsTreatedAsSet(repeated_field) ||
+          IsTreatedAsSmartSet(repeated_field) ||
+          IsTreatedAsSmartList(repeated_field)) {
         start_offset = std::min(count1, count2);
         for (int i = 0; i < count1 && i < count2; i++) {
           if (IsMatch(repeated_field, key_comparator, &message1, &message2,
-                      parent_fields, i, i)) {
+                      parent_fields, nullptr, i, i)) {
             match_list1->at(i) = i;
             match_list2->at(i) = i;
           } else {
@@ -1487,15 +1625,45 @@
         bool match = false;
 
         for (int j = start_offset; j < count2; j++) {
-          if (match_list2->at(j) != -1) continue;
+          if (match_list2->at(j) != -1) {
+            if (!IsTreatedAsSmartSet(repeated_field) ||
+                num_diffs_list1[i] == 0) {
+              continue;
+            }
+          }
 
-          match = IsMatch(repeated_field, key_comparator,
-                          &message1, &message2, parent_fields, i, j);
+          if (IsTreatedAsSmartSet(repeated_field)) {
+            num_diffs_reporter.Reset();
+            match = IsMatch(repeated_field, key_comparator,
+                            &message1, &message2, parent_fields,
+                            &num_diffs_reporter, i, j);
+          } else {
+            match = IsMatch(repeated_field, key_comparator,
+                            &message1, &message2, parent_fields,
+                            nullptr, i, j);
+          }
+
+          if (IsTreatedAsSmartSet(repeated_field)) {
+            if (match) {
+              num_diffs_list1[i] = 0;
+            } else if (repeated_field->cpp_type() ==
+                       FieldDescriptor::CPPTYPE_MESSAGE) {
+              // Replace with the one with fewer diffs.
+              const int32 num_diffs = num_diffs_reporter.GetNumDiffs();
+              if (num_diffs < num_diffs_list1[i]) {
+                num_diffs_list1[i] = num_diffs;
+                match = true;
+              }
+            }
+          }
 
           if (match) {
             match_list1->at(i) = j;
             match_list2->at(j) = i;
-            break;
+            if (!IsTreatedAsSmartSet(repeated_field)
+                || num_diffs_list1[i] == 0) {
+              break;
+            }
           }
         }
         if (!match && reporter == NULL) return false;
@@ -1510,6 +1678,10 @@
     }
   }
 
+  if (IsTreatedAsSmartList(repeated_field)) {
+    match_indices_for_smart_list_callback_(match_list1, match_list2);
+  }
+
   reporter_ = reporter;
 
   return success;
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 9419267..96d0f0c 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -42,6 +42,7 @@
 #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
 #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
 
+#include <functional>
 #include <map>
 #include <set>
 #include <string>
@@ -69,6 +70,7 @@
 class DefaultFieldComparator;
 class FieldContext;  // declared below MessageDifferencer
 
+
 // A basic differencer that can be used to determine
 // the differences between two specified Protocol Messages. If any differences
 // are found, the Compare method will return false, and any differencer reporter
@@ -368,13 +370,18 @@
   };
 
   enum RepeatedFieldComparison {
-    AS_LIST,     // Repeated fields are compared in order.  Differing values at
-                 // the same index are reported using ReportModified().  If the
-                 // repeated fields have different numbers of elements, the
-                 // unpaired elements are reported using ReportAdded() or
-                 // ReportDeleted().
-    AS_SET,      // Treat all the repeated fields as sets.
-                 // See TreatAsSet(), as below.
+    AS_LIST,      // Repeated fields are compared in order.  Differing values at
+                  // the same index are reported using ReportModified().  If the
+                  // repeated fields have different numbers of elements, the
+                  // unpaired elements are reported using ReportAdded() or
+                  // ReportDeleted().
+    AS_SET,       // Treat all the repeated fields as sets.
+                  // See TreatAsSet(), as below.
+    AS_SMART_LIST,  // Similar to AS_SET, but preserve the order and find the
+                    // longest matching sequence from the first matching
+                    // element. To use an optimal solution, call
+                    // SetMatchIndicesForSmartListCallback() to pass it in.
+    AS_SMART_SET,   // Similar to AS_SET, but match elements with fewest diffs.
   };
 
   // The elements of the given repeated field will be treated as a set for
@@ -406,6 +413,7 @@
   //
   // REQUIRES:  field->is_repeated() and field not registered with TreatAsList
   void TreatAsSet(const FieldDescriptor* field);
+  void TreatAsSmartSet(const FieldDescriptor* field);
 
   // The elements of the given repeated field will be treated as a list for
   // diffing purposes, so different orderings of the same elements will NOT be
@@ -413,6 +421,8 @@
   //
   // REQUIRED: field->is_repeated() and field not registered with TreatAsSet
   void TreatAsList(const FieldDescriptor* field);
+  // Note that the complexity is similar to treating as SET.
+  void TreatAsSmartList(const FieldDescriptor* field);
 
   // The elements of the given repeated field will be treated as a map for
   // diffing purposes, with |key| being the map key.  Thus, elements with the
@@ -778,11 +788,20 @@
                const MapKeyComparator* key_comparator,
                const Message* message1, const Message* message2,
                const std::vector<SpecificField>& parent_fields,
-               int index1, int index2);
+               Reporter* reporter, int index1, int index2);
 
   // Returns true when this repeated field has been configured to be treated
-  // as a set.
+  // as a Set / SmartSet / SmartList.
   bool IsTreatedAsSet(const FieldDescriptor* field);
+  bool IsTreatedAsSmartSet(const FieldDescriptor* field);
+
+  bool IsTreatedAsSmartList(const FieldDescriptor* field);
+  // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList
+  // by default to find the longest matching sequence from the first matching
+  // element. The callback takes two vectors showing the matching indices from
+  // the other vector, where -1 means an unmatch.
+  void SetMatchIndicesForSmartListCallback(
+      std::function<void(std::vector<int>*, std::vector<int>*)> callback);
 
   // Returns true when this repeated field is to be compared as a subset, ie.
   // has been configured to be treated as a set or map and scope is set to
@@ -830,6 +849,12 @@
   // Checks if index is equal to new_index in all the specific fields.
   static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields);
 
+  // CHECKs that the given repeated field can be compared according to
+  // new_comparison.
+  void CheckRepeatedFieldComparisons(
+      const FieldDescriptor* field,
+      const RepeatedFieldComparison& new_comparison);
+
   // Defines a map between field descriptors and their MapKeyComparators.
   // Used for repeated fields when they are configured as TreatAsMap.
   typedef std::map<const FieldDescriptor*,
@@ -838,6 +863,7 @@
   // Defines a set to store field descriptors.  Used for repeated fields when
   // they are configured as TreatAsSet.
   typedef std::set<const FieldDescriptor*> FieldSet;
+  typedef std::map<const FieldDescriptor*, RepeatedFieldComparison> FieldMap;
 
   Reporter* reporter_;
   DefaultFieldComparator default_field_comparator_;
@@ -846,8 +872,7 @@
   Scope scope_;
   RepeatedFieldComparison repeated_field_comparison_;
 
-  FieldSet set_fields_;
-  FieldSet list_fields_;
+  FieldMap repeated_field_comparisons_;
   // Keeps track of MapKeyComparators that are created within
   // MessageDifferencer. These MapKeyComparators should be deleted
   // before MessageDifferencer is destroyed.
@@ -867,6 +892,10 @@
 
   std::string* output_string_;
 
+  // Callback to post-process the matched indices to support SMART_LIST.
+  std::function<void(std::vector<int>*,
+                     std::vector<int>*)> match_indices_for_smart_list_callback_;
+
   std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer);
 };
diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc
index 848290b..24c05c6 100644
--- a/src/google/protobuf/util/message_differencer_unittest.cc
+++ b/src/google/protobuf/util/message_differencer_unittest.cc
@@ -1049,6 +1049,132 @@
   EXPECT_TRUE(differencer.CompareWithFields(msg1, msg2, fields1, fields2));
 }
 
+TEST(MessageDifferencerTest, RepeatedFieldSmartListTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  msg1.add_rv(1);
+  msg1.add_rv(2);
+  msg1.add_rv(3);
+  msg1.add_rv(9);
+  msg1.add_rv(4);
+  msg1.add_rv(5);
+  msg1.add_rv(7);
+  msg1.add_rv(2);
+  msg2.add_rv(9);
+  msg2.add_rv(0);
+  msg2.add_rv(2);
+  msg2.add_rv(7);
+  msg2.add_rv(3);
+  msg2.add_rv(4);
+  msg2.add_rv(5);
+  msg2.add_rv(6);
+  msg2.add_rv(2);
+  // Compare
+  // a: 1,      2,    3, 9, 4, 5, 7,   2
+  // b:   9, 0, 2, 7, 3,    4, 5,   6, 2
+  string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_LIST);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("deleted: rv[0]: 1\n"
+            "added: rv[0]: 9\n"
+            "added: rv[1]: 0\n"
+            "moved: rv[1] -> rv[2] : 2\n"
+            "added: rv[3]: 7\n"
+            "moved: rv[2] -> rv[4] : 3\n"
+            "deleted: rv[3]: 9\n"
+            "moved: rv[4] -> rv[5] : 4\n"
+            "moved: rv[5] -> rv[6] : 5\n"
+            "deleted: rv[6]: 7\n"
+            "added: rv[7]: 6\n"
+            "moved: rv[7] -> rv[8] : 2\n", diff_report);
+
+  // Compare two sub messages
+  // a: 1, 2, 3,    4, 5
+  // b:    2,    6, 4,
+  msg1.Clear();
+  msg2.Clear();
+  msg1.add_rm()->set_a(1);
+  msg1.add_rm()->set_a(2);
+  msg1.add_rm()->set_a(3);
+  msg1.add_rm()->set_a(4);
+  msg1.add_rm()->set_a(5);
+  msg2.add_rm()->set_a(2);
+  msg2.add_rm()->set_a(6);
+  msg2.add_rm()->set_a(4);
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_LIST);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("deleted: rm[0]: { a: 1 }\n"
+            "moved: rm[1] -> rm[0] : { a: 2 }\n"
+            "deleted: rm[2]: { a: 3 }\n"
+            "added: rm[1]: { a: 6 }\n"
+            "moved: rm[3] -> rm[2] : { a: 4 }\n"
+            "deleted: rm[4]: { a: 5 }\n", diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSetTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+  protobuf_unittest::TestField elem1_1, elem2_1, elem3_1;
+  protobuf_unittest::TestField elem1_2, elem2_2, elem3_2;
+
+  // Only one field is different for each pair of elememts
+  elem1_1.set_a(1);  elem1_2.set_a(0);
+  elem1_1.set_b(1);  elem1_2.set_b(1);
+  elem1_1.set_c(1);  elem1_2.set_c(1);
+  elem2_1.set_a(2);  elem2_2.set_a(2);
+  elem2_1.set_b(2);  elem2_2.set_b(0);
+  elem2_1.set_c(2);  elem2_2.set_c(2);
+  elem3_1.set_a(3);  elem3_2.set_a(3);
+  elem3_1.set_b(3);  elem3_2.set_b(0);
+  elem3_1.set_c(3);  elem3_2.set_c(3);
+
+  *msg1.add_rm() = elem1_1;
+  *msg1.add_rm() = elem2_1;
+  *msg1.add_rm() = elem3_1;
+  // Change the order of those elements for the second message.
+  *msg2.add_rm() = elem3_2;
+  *msg2.add_rm() = elem1_2;
+  *msg2.add_rm() = elem2_2;
+
+  string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_FALSE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("modified: rm[0].a -> rm[1].a: 1 -> 0\n"
+            "modified: rm[1].b -> rm[2].b: 2 -> 0\n"
+            "modified: rm[2].b -> rm[0].b: 3 -> 0\n", diff_report);
+}
+
+TEST(MessageDifferencerTest, RepeatedFieldSmartSet_NonMessageTypeTest) {
+  // Create the testing protos
+  protobuf_unittest::TestDiffMessage msg1;
+  protobuf_unittest::TestDiffMessage msg2;
+
+  // Create 3 elements, but in different order.
+  msg1.add_rw("b");  msg2.add_rw("a");
+  msg1.add_rw("x");  msg2.add_rw("x");
+  msg1.add_rw("a");  msg2.add_rw("b");
+
+  string diff_report;
+  util::MessageDifferencer differencer;
+  differencer.ReportDifferencesToString(&diff_report);
+  differencer.set_repeated_field_comparison(
+      util::MessageDifferencer::AS_SMART_SET);
+  EXPECT_TRUE(differencer.Compare(msg1, msg2));
+  EXPECT_EQ("moved: rw[0] -> rw[2] : \"b\"\n"
+            "moved: rw[2] -> rw[0] : \"a\"\n", diff_report);
+}
+
 TEST(MessageDifferencerTest, RepeatedFieldSetTest_SetOfSet) {
   // Create the testing protos
   protobuf_unittest::TestDiffMessage msg1;
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index 3a3eba4..f40ce94 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -44,12 +44,21 @@
 namespace protobuf {
 namespace util {
 namespace {
+using google::protobuf::Any;
 using google::protobuf::BoolValue;
+using google::protobuf::BytesValue;
+using google::protobuf::DoubleValue;
 using google::protobuf::Enum;
 using google::protobuf::EnumValue;
 using google::protobuf::Field;
+using google::protobuf::FloatValue;
+using google::protobuf::Int32Value;
+using google::protobuf::Int64Value;
 using google::protobuf::Option;
+using google::protobuf::StringValue;
 using google::protobuf::Type;
+using google::protobuf::UInt32Value;
+using google::protobuf::UInt64Value;
 
 using util::Status;
 using util::error::INVALID_ARGUMENT;
@@ -70,7 +79,8 @@
 
     const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
     if (descriptor == NULL) {
-      return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
+      return Status(util::error::NOT_FOUND,
+                    "Invalid type URL, unknown type: " + type_name);
     }
     ConvertDescriptor(descriptor, type);
     return Status();
@@ -85,7 +95,8 @@
 
     const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
     if (descriptor == NULL) {
-      return Status(NOT_FOUND, "Invalid type URL, unknown type: " + type_name);
+      return Status(util::error::NOT_FOUND,
+                    "Invalid type URL, unknown type: " + type_name);
     }
     ConvertEnumDescriptor(descriptor, enum_type);
     return Status();
@@ -107,15 +118,104 @@
 
   void ConvertMessageOptions(const MessageOptions& options,
                              RepeatedPtrField<Option>* output) {
-    if (options.map_entry()) {
-      Option* option = output->Add();
-      option->set_name("map_entry");
-      BoolValue value;
-      value.set_value(true);
-      option->mutable_value()->PackFrom(value);
+    const Reflection* reflection = options.GetReflection();
+    std::vector<const FieldDescriptor*> fields;
+    reflection->ListFields(options, &fields);
+    for (const FieldDescriptor* field : fields) {
+      if (field->is_repeated()) {
+        const int size = reflection->FieldSize(options, field);
+        for (int i = 0; i < size; i++) {
+          ConvertMessageOption(reflection, options, field, i, output->Add());
+        }
+      } else {
+        ConvertMessageOption(reflection, options, field, -1, output->Add());
+      }
     }
+  }
 
-    // TODO(xiaofeng): Set other "options"?
+  static void ConvertMessageOption(const Reflection* reflection,
+                                   const MessageOptions& options,
+                                   const FieldDescriptor* field, int index,
+                                   Option* out) {
+    out->set_name(field->is_extension() ? field->full_name() : field->name());
+    Any* value = out->mutable_value();
+    switch (field->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        value->PackFrom(
+            field->is_repeated()
+                ? reflection->GetRepeatedMessage(options, field, index)
+                : reflection->GetMessage(options, field));
+        return;
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        value->PackFrom(WrapValue<DoubleValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedDouble(options, field, index)
+                : reflection->GetDouble(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        value->PackFrom(WrapValue<FloatValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedFloat(options, field, index)
+                : reflection->GetFloat(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT64:
+        value->PackFrom(WrapValue<Int64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt64(options, field, index)
+                : reflection->GetInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT64:
+        value->PackFrom(WrapValue<UInt64Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt64(options, field, index)
+                : reflection->GetUInt64(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_INT32:
+        value->PackFrom(WrapValue<Int32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedInt32(options, field, index)
+                : reflection->GetInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_UINT32:
+        value->PackFrom(WrapValue<UInt32Value>(
+            field->is_repeated()
+                ? reflection->GetRepeatedUInt32(options, field, index)
+                : reflection->GetUInt32(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_BOOL:
+        value->PackFrom(WrapValue<BoolValue>(
+            field->is_repeated()
+                ? reflection->GetRepeatedBool(options, field, index)
+                : reflection->GetBool(options, field)));
+        return;
+      case FieldDescriptor::CPPTYPE_STRING: {
+        const string& val =
+            field->is_repeated()
+                ? reflection->GetRepeatedString(options, field, index)
+                : reflection->GetString(options, field);
+        if (field->type() == FieldDescriptor::TYPE_STRING) {
+          value->PackFrom(WrapValue<StringValue>(val));
+        } else {
+          value->PackFrom(WrapValue<BytesValue>(val));
+        }
+        return;
+      }
+      case FieldDescriptor::CPPTYPE_ENUM: {
+        const EnumValueDescriptor* val =
+            field->is_repeated()
+                ? reflection->GetRepeatedEnum(options, field, index)
+                : reflection->GetEnum(options, field);
+        value->PackFrom(WrapValue<Int32Value>(val->number()));
+        return;
+      }
+    }
+  }
+
+  template <typename WrapperT, typename T>
+  static WrapperT WrapValue(T value) {
+    WrapperT wrapper;
+    wrapper.set_value(value);
+    return wrapper;
   }
 
   void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
@@ -181,7 +281,7 @@
   Status ParseTypeUrl(const string& type_url, string* type_name) {
     if (type_url.substr(0, url_prefix_.size() + 1) != url_prefix_ + "/") {
       return Status(
-          INVALID_ARGUMENT,
+          util::error::INVALID_ARGUMENT,
           StrCat("Invalid type URL, type URLs must be of the form '",
                        url_prefix_, "/<typename>', got: ", type_url));
     }
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index 9dea17a..fa06037 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -40,6 +40,7 @@
 #include <google/protobuf/map_unittest.pb.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_custom_options.pb.h>
 #include <google/protobuf/util/json_format_proto3.pb.h>
 #include <google/protobuf/util/type_resolver.h>
 #include <google/protobuf/testing/googletest.h>
@@ -49,11 +50,12 @@
 namespace protobuf {
 namespace util {
 namespace {
-using google::protobuf::Type;
+using google::protobuf::BoolValue;
 using google::protobuf::Enum;
 using google::protobuf::Field;
+using google::protobuf::Int32Value;
 using google::protobuf::Option;
-using google::protobuf::BoolValue;
+using google::protobuf::Type;
 
 static const char kUrlPrefix[] = "type.googleapis.com";
 
@@ -127,12 +129,21 @@
 
   bool HasBoolOption(const RepeatedPtrField<Option>& options,
                      const string& name, bool value) {
-    for (int i = 0; i < options.size(); ++i) {
-      const Option& option = options.Get(i);
+    return HasOption<BoolValue>(options, name, value);
+  }
+
+  bool HasInt32Option(const RepeatedPtrField<Option>& options,
+                      const string& name, int32 value) {
+    return HasOption<Int32Value>(options, name, value);
+  }
+
+  template <typename WrapperT, typename T>
+  bool HasOption(const RepeatedPtrField<Option>& options, const string& name,
+                 T value) {
+    for (const Option& option : options) {
       if (option.name() == name) {
-        BoolValue bool_value;
-        if (option.value().UnpackTo(&bool_value) &&
-            bool_value.value() == value) {
+        WrapperT wrapper;
+        if (option.value().UnpackTo(&wrapper) && wrapper.value() == value) {
           return true;
         }
       }
@@ -327,6 +338,18 @@
   EXPECT_TRUE(HasBoolOption(type.options(), "map_entry", true));
 }
 
+TEST_F(DescriptorPoolTypeResolverTest, TestCustomOptions) {
+  Type type;
+  ASSERT_TRUE(
+      resolver_
+          ->ResolveMessageType(
+              GetTypeUrl<protobuf_unittest::TestMessageWithCustomOptions>(),
+              &type)
+          .ok());
+  EXPECT_TRUE(
+      HasInt32Option(type.options(), "protobuf_unittest.message_opt1", -56));
+}
+
 TEST_F(DescriptorPoolTypeResolverTest, TestEnum) {
   Enum type;
   ASSERT_TRUE(resolver_->ResolveEnumType(
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 60cadae..f576875 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -768,7 +768,7 @@
  public:
   explicit CodedOutputStreamFieldSkipper(io::CodedOutputStream* unknown_fields)
       : unknown_fields_(unknown_fields) {}
-  virtual ~CodedOutputStreamFieldSkipper() {}
+  ~CodedOutputStreamFieldSkipper() override {}
 
   // implements FieldSkipper -----------------------------------------
   bool SkipField(io::CodedInputStream* input, uint32 tag) override;
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index babdcc6..114e883 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -49,6 +49,7 @@
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 #include <google/protobuf/stubs/casts.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 #include <google/protobuf/port_def.inc>
@@ -1148,10 +1149,6 @@
   return message->ParseFromArray(wire_buffer.data(), wire_buffer.size());
 }
 
-bool StartsWith(const string& s, const string& prefix) {
-  return s.substr(0, prefix.length()) == prefix;
-}
-
 class Utf8ValidationTest : public ::testing::Test {
  protected:
   Utf8ValidationTest() {}
@@ -1172,11 +1169,12 @@
   }
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(StartsWith(errors[0],
-                         "String field 'protobuf_unittest.OneString.data' "
-                         "contains invalid UTF-8 data when "
-                         "serializing a protocol buffer. Use the "
-                         "'bytes' type if you intend to send raw bytes."));
+  EXPECT_TRUE(
+      HasPrefixString(errors[0],
+                       "String field 'protobuf_unittest.OneString.data' "
+                       "contains invalid UTF-8 data when "
+                       "serializing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
 #else
   ASSERT_EQ(0, errors.size());
 #endif  // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
@@ -1196,11 +1194,12 @@
   }
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(StartsWith(errors[0],
-                         "String field 'protobuf_unittest.OneString.data' "
-                         "contains invalid UTF-8 data when "
-                         "parsing a protocol buffer. Use the "
-                         "'bytes' type if you intend to send raw bytes."));
+  EXPECT_TRUE(
+      HasPrefixString(errors[0],
+                       "String field 'protobuf_unittest.OneString.data' "
+                       "contains invalid UTF-8 data when "
+                       "parsing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
 
 #else
   ASSERT_EQ(0, errors.size());
@@ -1299,10 +1298,11 @@
   }
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   ASSERT_EQ(1, errors.size());
-  EXPECT_TRUE(StartsWith(errors[0],
-                         "String field contains invalid UTF-8 data when "
-                         "serializing a protocol buffer. Use the "
-                         "'bytes' type if you intend to send raw bytes."));
+  EXPECT_TRUE(
+      HasPrefixString(errors[0],
+                       "String field contains invalid UTF-8 data when "
+                       "serializing a protocol buffer. Use the "
+                       "'bytes' type if you intend to send raw bytes."));
 #else
   ASSERT_EQ(0, errors.size());
 #endif
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 3d7e7cb..f3a92a4 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -284,8 +284,7 @@
   file_level_metadata_google_2fprotobuf_2fwrappers_2eproto, 9, file_level_enum_descriptors_google_2fprotobuf_2fwrappers_2eproto, file_level_service_descriptors_google_2fprotobuf_2fwrappers_2eproto,
 };
 
-::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
-  false, InitDefaults_google_2fprotobuf_2fwrappers_2eproto, 
+const char descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto[] =
   "\n\036google/protobuf/wrappers.proto\022\017google"
   ".protobuf\"\034\n\013DoubleValue\022\r\n\005value\030\001 \001(\001\""
   "\033\n\nFloatValue\022\r\n\005value\030\001 \001(\002\"\033\n\nInt64Val"
@@ -298,7 +297,10 @@
   "b.com/golang/protobuf/ptypes/wrappers\370\001\001"
   "\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb"
   "\006proto3"
-,
+  ;
+::google::protobuf::internal::DescriptorTable descriptor_table_google_2fprotobuf_2fwrappers_2eproto = {
+  false, InitDefaults_google_2fprotobuf_2fwrappers_2eproto, 
+  descriptor_table_protodef_google_2fprotobuf_2fwrappers_2eproto,
   "google/protobuf/wrappers.proto", &assign_descriptors_table_google_2fprotobuf_2fwrappers_2eproto, 447,
 };
 
@@ -390,10 +392,10 @@
   auto msg = static_cast<DoubleValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -409,13 +411,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -426,7 +428,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -687,10 +689,10 @@
   auto msg = static_cast<FloatValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -706,13 +708,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -723,7 +725,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -984,10 +986,10 @@
   auto msg = static_cast<Int64Value*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1004,13 +1006,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1021,7 +1023,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1284,10 +1286,10 @@
   auto msg = static_cast<UInt64Value*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1304,13 +1306,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1321,7 +1323,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1584,10 +1586,10 @@
   auto msg = static_cast<Int32Value*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1604,13 +1606,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1621,7 +1623,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -1884,10 +1886,10 @@
   auto msg = static_cast<UInt32Value*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -1904,13 +1906,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -1921,7 +1923,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2184,10 +2186,10 @@
   auto msg = static_cast<BoolValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -2204,13 +2206,13 @@
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2221,7 +2223,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2489,10 +2491,10 @@
   auto msg = static_cast<StringValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -2502,26 +2504,29 @@
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
         ctx->extra_parse_data().SetFieldName("google.protobuf.StringValue.value");
-        parser_till_end = ::google::protobuf::internal::StringParserUTF8;
-        ::std::string* str = msg->mutable_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        auto newend = ptr + size;
-        if (size) ptr = parser_till_end(ptr, newend, object, ctx);
-        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr == newend);
+        auto str = msg->mutable_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParserUTF8;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheckUTF8(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
+        ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2532,7 +2537,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
@@ -2816,10 +2821,10 @@
   auto msg = static_cast<BytesValue*>(object);
   ::google::protobuf::uint32 size; (void)size;
   int depth; (void)depth;
+  ::google::protobuf::uint32 tag;
   ::google::protobuf::internal::ParseFunc parser_till_end; (void)parser_till_end;
   auto ptr = begin;
   while (ptr < end) {
-    ::google::protobuf::uint32 tag;
     ptr = Varint::Parse32Inline(ptr, &tag);
     GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
     switch (tag >> 3) {
@@ -2828,25 +2833,29 @@
         if (static_cast<::google::protobuf::uint8>(tag) != 10) goto handle_unusual;
         ptr = Varint::Parse32Inline(ptr, &size);
         GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
-        parser_till_end = ::google::protobuf::internal::StringParser;
-        ::std::string* str = msg->mutable_value();
-        str->clear();
-        object = str;
-        if (size > end - ptr) goto len_delim_till_end;
-        str->append(ptr, size);
+        auto str = msg->mutable_value();
+        if (size > end - ptr + ::google::protobuf::internal::ParseContext::kSlopBytes) {
+          object = str;
+          str->clear();
+          str->reserve(size);
+          parser_till_end = ::google::protobuf::internal::GreedyStringParser;
+          goto len_delim_till_end;
+        }
+        GOOGLE_PROTOBUF_PARSER_ASSERT(::google::protobuf::internal::StringCheck(ptr, size, ctx));
+        ::google::protobuf::internal::InlineGreedyStringParser(str, ptr, size, ctx);
         ptr += size;
         break;
       }
       default: {
       handle_unusual: (void)&&handle_unusual;
         if ((tag & 7) == 4 || tag == 0) {
-          bool ok = ctx->ValidEndGroup(tag);
-          GOOGLE_PROTOBUF_PARSER_ASSERT(ok);
+          ctx->EndGroup(tag);
           return ptr;
         }
         auto res = UnknownFieldParse(tag, {_InternalParse, msg},
           ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), ctx);
         ptr = res.first;
+        GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr);
         if (res.second) return ptr;
       }
     }  // switch
@@ -2857,7 +2866,7 @@
                                  {parser_till_end, object}, size);
 group_continues: (void)&&group_continues;
   GOOGLE_DCHECK(ptr >= end);
-  ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth);
+  GOOGLE_PROTOBUF_PARSER_ASSERT(ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, depth, tag));
   return ptr;
 }
 #else  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 5b1d70a..7dbe49e 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -157,7 +157,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const DoubleValue& from);
   void MergeFrom(const DoubleValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -283,7 +283,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const FloatValue& from);
   void MergeFrom(const FloatValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -409,7 +409,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Int64Value& from);
   void MergeFrom(const Int64Value& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -535,7 +535,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const UInt64Value& from);
   void MergeFrom(const UInt64Value& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -661,7 +661,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const Int32Value& from);
   void MergeFrom(const Int32Value& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -787,7 +787,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const UInt32Value& from);
   void MergeFrom(const UInt32Value& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -913,7 +913,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const BoolValue& from);
   void MergeFrom(const BoolValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1039,7 +1039,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const StringValue& from);
   void MergeFrom(const StringValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;
@@ -1182,7 +1182,7 @@
   void MergeFrom(const ::google::protobuf::Message& from) final;
   void CopyFrom(const BytesValue& from);
   void MergeFrom(const BytesValue& from);
-  void Clear() final;
+  PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;
   bool IsInitialized() const final;
 
   size_t ByteSizeLong() const final;