Merge pull request #6308 from haon4/201906261101

Down integrate to GitHub
diff --git a/BUILD b/BUILD
index 44beeb2..9a2258b 100644
--- a/BUILD
+++ b/BUILD
@@ -490,7 +490,6 @@
 COMMON_TEST_SRCS = [
     # AUTOGEN(common_test_srcs)
     "src/google/protobuf/arena_test_util.cc",
-    "src/google/protobuf/map_test_util.cc",
     "src/google/protobuf/test_util.cc",
     "src/google/protobuf/test_util.inc",
     "src/google/protobuf/testing/file.cc",
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 7226961..5c25acc 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -114,7 +114,7 @@
 
 set(common_test_files
   ${protobuf_source_dir}/src/google/protobuf/arena_test_util.cc
-  ${protobuf_source_dir}/src/google/protobuf/map_test_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/map_test_util.inc
   ${protobuf_source_dir}/src/google/protobuf/test_util.cc
   ${protobuf_source_dir}/src/google/protobuf/test_util.inc
   ${protobuf_source_dir}/src/google/protobuf/testing/file.cc
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index 5ddb3a9..9c34b42 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -1978,14 +1978,12 @@
       })",
       "repeated_timestamp: {seconds: -62135596800}"
       "repeated_timestamp: {seconds: 253402300799 nanos: 999999999}");
-  RunValidJsonTest(
-      "TimestampWithPositiveOffset", REQUIRED,
-      R"({"optionalTimestamp": "1970-01-01T08:00:01+08:00"})",
-      "optional_timestamp: {seconds: 1}");
-  RunValidJsonTest(
-      "TimestampWithNegativeOffset", REQUIRED,
-      R"({"optionalTimestamp": "1969-12-31T16:00:01-08:00"})",
-      "optional_timestamp: {seconds: 1}");
+  RunValidJsonTest("TimestampWithPositiveOffset", REQUIRED,
+                   R"({"optionalTimestamp": "1970-01-01T08:00:01+08:00"})",
+                   "optional_timestamp: {seconds: 1}");
+  RunValidJsonTest("TimestampWithNegativeOffset", REQUIRED,
+                   R"({"optionalTimestamp": "1969-12-31T16:00:01-08:00"})",
+                   "optional_timestamp: {seconds: 1}");
   RunValidJsonTest(
       "TimestampNull", REQUIRED,
       R"({"optionalTimestamp": null})",
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 2a41cf1..65dcd53 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(new boolean[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -161,6 +160,12 @@
   }
 
   @Override
+  public boolean add(Boolean element) {
+    addBoolean(element);
+    return true;
+  }
+
+  @Override
   public void add(int index, Boolean element) {
     addBoolean(index, element);
   }
@@ -168,7 +173,17 @@
   /** Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */
   @Override
   public void addBoolean(boolean element) {
-    addBoolean(size, element);
+    ensureIsMutable();
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      boolean[] newArray = new boolean[length];
+
+      System.arraycopy(array, 0, newArray, 0, size);
+      array = newArray;
+    }
+
+    array[size++] = element;
   }
 
   /** Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element. */
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 87c6837..f2c7cc4 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -483,7 +483,9 @@
   /**
    * Returns true if the stream has reached the end of the input. This is the case if either the end
    * of the underlying input source has been reached or if the stream has reached a limit created
-   * using {@link #pushLimit(int)}.
+   * using {@link #pushLimit(int)}. This function may get blocked when using StreamDecoder as it
+   * invokes {@link #StreamDecoder.tryRefillBuffer(int)} in this function which will try to read
+   * bytes from input.
    */
   public abstract boolean isAtEnd() throws IOException;
 
diff --git a/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
index fefa636..c2378ad 100644
--- a/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
+++ b/java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java
@@ -34,7 +34,7 @@
 public final class DiscardUnknownFieldsParser {
 
   /**
-   * Warps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
+   * Wraps a given {@link Parser} into a new {@link Parser} that discards unknown fields during
    * parsing.
    *
    * <p>Usage example:
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 d4f63d6..ac14949 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(new double[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -161,6 +160,12 @@
   }
 
   @Override
+  public boolean add(Double element) {
+    addDouble(element);
+    return true;
+  }
+
+  @Override
   public void add(int index, Double element) {
     addDouble(index, element);
   }
@@ -168,7 +173,17 @@
   /** Like {@link #add(Double)} but more efficient in that it doesn't box the element. */
   @Override
   public void addDouble(double element) {
-    addDouble(size, element);
+    ensureIsMutable();
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      double[] newArray = new double[length];
+
+      System.arraycopy(array, 0, newArray, 0, size);
+      array = newArray;
+    }
+
+    array[size++] = element;
   }
 
   /** Like {@link #add(int, Double)} but more efficient in that it doesn't box the element. */
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 ac20de8..9d2ab71 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(new float[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@
   }
 
   @Override
+  public boolean add(Float element) {
+    addFloat(element);
+    return true;
+  }
+
+  @Override
   public void add(int index, Float element) {
     addFloat(index, element);
   }
@@ -167,7 +172,17 @@
   /** Like {@link #add(Float)} but more efficient in that it doesn't box the element. */
   @Override
   public void addFloat(float element) {
-    addFloat(size, element);
+    ensureIsMutable();
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      float[] newArray = new float[length];
+
+      System.arraycopy(array, 0, newArray, 0, size);
+      array = newArray;
+    }
+
+    array[size++] = element;
   }
 
   /** Like {@link #add(int, Float)} but more efficient in that it doesn't box the element. */
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index af86e13..bea008c 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -58,6 +58,8 @@
 import java.io.InputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -79,6 +81,12 @@
 public abstract class GeneratedMessageV3 extends AbstractMessage
     implements Serializable {
   private static final long serialVersionUID = 1L;
+  // Whether to use reflection for FieldAccessor
+  private static boolean forTestUseReflection = false;
+
+  static void setForTestUseReflection(boolean useReflection) {
+    forTestUseReflection = useReflection;
+  }
 
   /**
    * For testing. Allows a test to disable the optimization that avoids using
@@ -105,13 +113,20 @@
   }
 
  /**
-  * For testing. Allows a test to disable the optimization that avoids using
-  * field builders for nested messages until they are requested. By disabling
-  * this optimization, existing tests can be reused to test the field builders.
-  * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
+  * @see #setAlwaysUseFieldBuildersForTesting(boolean)
   */
   static void enableAlwaysUseFieldBuildersForTesting() {
-    alwaysUseFieldBuilders = true;
+    setAlwaysUseFieldBuildersForTesting(true);
+  }
+
+  /**
+   * For testing. Allows a test to disable/re-enable the optimization that avoids
+   * using field builders for nested messages until they are requested. By disabling
+   * this optimization, existing tests can be reused to test the field builders.
+   * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
+   */
+  static void setAlwaysUseFieldBuildersForTesting(boolean useBuilders) {
+    alwaysUseFieldBuilders = useBuilders;
   }
 
   /**
@@ -1795,6 +1810,22 @@
     }
   }
 
+  /** Calls invoke and throws a RuntimeException if it fails. */
+  private static RuntimeException handleException(Throwable e) {
+    if (e instanceof ClassCastException) {
+      // Reflection throws a bad param type as an IllegalArgumentException, whereas MethodHandle
+      // throws it as a ClassCastException; convert for backwards compatibility
+      throw new IllegalArgumentException(e);
+    } else if (e instanceof RuntimeException) {
+      throw (RuntimeException) e;
+    } else if (e instanceof Error) {
+      throw (Error) e;
+    } else {
+      throw new RuntimeException(
+          "Unexpected exception thrown by generated accessor method.", e);
+    }
+  }
+
   /**
    * Gets the map field with the given field number. This method should be
    * overridden in the generated message class if the message contains map
@@ -2041,61 +2072,250 @@
     // ---------------------------------------------------------------
 
     private static class SingularFieldAccessor implements FieldAccessor {
+      private interface MethodInvoker {
+        Object get(final GeneratedMessageV3 message);
+
+        Object get(GeneratedMessageV3.Builder<?> builder);
+
+        int getOneofFieldNumber(final GeneratedMessageV3 message);
+
+        int getOneofFieldNumber(final GeneratedMessageV3.Builder<?> builder);
+
+        void set(final GeneratedMessageV3.Builder<?> builder, final Object value);
+
+        boolean has(final GeneratedMessageV3 message);
+
+        boolean has(GeneratedMessageV3.Builder<?> builder);
+
+        void clear(final GeneratedMessageV3.Builder<?> builder);
+      }
+
+      private static final class ReflectionInvoker implements MethodInvoker {
+        protected final Method getMethod;
+        protected final Method getMethodBuilder;
+        protected final Method setMethod;
+        protected final Method hasMethod;
+        protected final Method hasMethodBuilder;
+        protected final Method clearMethod;
+        protected final Method caseMethod;
+        protected final Method caseMethodBuilder;
+
+        ReflectionInvoker(
+            final FieldDescriptor descriptor,
+            final String camelCaseName,
+            final Class<? extends GeneratedMessageV3> messageClass,
+            final Class<? extends Builder> builderClass,
+            final String containingOneofCamelCaseName,
+            boolean isOneofField,
+            boolean hasHasMethod) {
+          getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+          getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
+          Class<?> type = getMethod.getReturnType();
+          setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+          hasMethod = hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
+          hasMethodBuilder =
+              hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
+          clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+          caseMethod =
+              isOneofField
+                  ? getMethodOrDie(messageClass, "get" + containingOneofCamelCaseName + "Case")
+                  : null;
+          caseMethodBuilder =
+              isOneofField
+                  ? getMethodOrDie(builderClass, "get" + containingOneofCamelCaseName + "Case")
+                  : null;
+        }
+
+        @Override
+        public Object get(final GeneratedMessageV3 message) {
+          return invokeOrDie(getMethod, message);
+        }
+
+        @Override
+        public Object get(GeneratedMessageV3.Builder<?> builder) {
+          return invokeOrDie(getMethodBuilder, builder);
+        }
+
+        @Override
+        public int getOneofFieldNumber(final GeneratedMessageV3 message) {
+          return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
+        }
+
+        @Override
+        public int getOneofFieldNumber(final GeneratedMessageV3.Builder<?> builder) {
+          return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
+        }
+
+        @Override
+        public void set(final GeneratedMessageV3.Builder<?> builder, final Object value) {
+          invokeOrDie(setMethod, builder, value);
+        }
+
+        @Override
+        public boolean has(final GeneratedMessageV3 message) {
+          return (Boolean) invokeOrDie(hasMethod, message);
+        }
+
+        @Override
+        public boolean has(GeneratedMessageV3.Builder<?> builder) {
+          return (Boolean) invokeOrDie(hasMethodBuilder, builder);
+        }
+
+        @Override
+        public void clear(final GeneratedMessageV3.Builder<?> builder) {
+          invokeOrDie(clearMethod, builder);
+        }
+      }
+
+      private static final class MethodHandleInvoker implements MethodInvoker {
+        protected final MethodHandle getMethod;
+        protected final MethodHandle getMethodBuilder;
+        protected final MethodHandle setMethod;
+        protected final MethodHandle hasMethod;
+        protected final MethodHandle hasMethodBuilder;
+        protected final MethodHandle clearMethod;
+        protected final MethodHandle caseMethod;
+        protected final MethodHandle caseMethodBuilder;
+
+        MethodHandleInvoker(ReflectionInvoker accessor) throws IllegalAccessException {
+          MethodHandles.Lookup lookup = MethodHandles.publicLookup();
+
+          this.getMethod = lookup.unreflect(accessor.getMethod);
+          this.getMethodBuilder = lookup.unreflect(accessor.getMethodBuilder);
+          this.setMethod = lookup.unreflect(accessor.setMethod);
+          this.hasMethod =
+              (accessor.hasMethod != null) ? lookup.unreflect(accessor.hasMethod) : null;
+          this.hasMethodBuilder = (accessor.hasMethodBuilder != null)
+              ? lookup.unreflect(accessor.hasMethodBuilder) : null;
+          this.clearMethod = lookup.unreflect(accessor.clearMethod);
+          this.caseMethod =
+              (accessor.caseMethod != null) ? lookup.unreflect(accessor.caseMethod) : null;
+          this.caseMethodBuilder = (accessor.caseMethodBuilder != null)
+              ? lookup.unreflect(accessor.caseMethodBuilder) : null;
+        }
+
+        @Override
+        public Object get(final GeneratedMessageV3 message) {
+          try {
+            return getMethod.invoke(message);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public Object get(GeneratedMessageV3.Builder<?> builder) {
+          try {
+            return getMethodBuilder.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public int getOneofFieldNumber(final GeneratedMessageV3 message) {
+          try {
+            return ((Internal.EnumLite) caseMethod.invoke(message)).getNumber();
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public int getOneofFieldNumber(final GeneratedMessageV3.Builder<?> builder) {
+          try {
+            return ((Internal.EnumLite) caseMethodBuilder.invoke(builder)).getNumber();
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public void set(final GeneratedMessageV3.Builder<?> builder, final Object value) {
+          try {
+            setMethod.invoke(builder, value);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public boolean has(final GeneratedMessageV3 message) {
+          try {
+            return (Boolean) hasMethod.invoke(message);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public boolean has(GeneratedMessageV3.Builder<?> builder) {
+          try {
+            return (Boolean) hasMethodBuilder.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public void clear(final GeneratedMessageV3.Builder<?> builder) {
+          try {
+            clearMethod.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+      }
+
       SingularFieldAccessor(
           final FieldDescriptor descriptor, final String camelCaseName,
           final Class<? extends GeneratedMessageV3> messageClass,
           final Class<? extends Builder> builderClass,
           final String containingOneofCamelCaseName) {
-        field = descriptor;
         isOneofField = descriptor.getContainingOneof() != null;
         hasHasMethod = supportFieldPresence(descriptor.getFile())
             || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
-        getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
-        getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
-        type = getMethod.getReturnType();
-        setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
-        hasMethod =
-            hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
-        hasMethodBuilder =
-            hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
-        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
-        caseMethod = isOneofField ? getMethodOrDie(
-            messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
-        caseMethodBuilder = isOneofField ? getMethodOrDie(
-            builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
+        ReflectionInvoker reflectionInvoker =
+            new ReflectionInvoker(
+                descriptor,
+                camelCaseName,
+                messageClass,
+                builderClass,
+                containingOneofCamelCaseName,
+                isOneofField,
+                hasHasMethod);
+        field = descriptor;
+        type = reflectionInvoker.getMethod.getReturnType();
+        invoker = tryGetMethodHandleInvoke(reflectionInvoker);
+      }
+
+      static MethodInvoker tryGetMethodHandleInvoke(ReflectionInvoker accessor) {
+        if (forTestUseReflection) {
+          return accessor;
+        }
+        try {
+          return new MethodHandleInvoker(accessor);
+        } catch (IllegalAccessException e) {
+          throw new RuntimeException(e);
+        }
       }
 
       // Note:  We use Java reflection to call public methods rather than
       //   access private fields directly as this avoids runtime security
       //   checks.
       protected final Class<?> type;
-      protected final Method getMethod;
-      protected final Method getMethodBuilder;
-      protected final Method setMethod;
-      protected final Method hasMethod;
-      protected final Method hasMethodBuilder;
-      protected final Method clearMethod;
-      protected final Method caseMethod;
-      protected final Method caseMethodBuilder;
       protected final FieldDescriptor field;
       protected final boolean isOneofField;
       protected final boolean hasHasMethod;
-
-      private int getOneofFieldNumber(final GeneratedMessageV3 message) {
-        return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
-      }
-
-      private int getOneofFieldNumber(final GeneratedMessageV3.Builder builder) {
-        return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
-      }
+      protected final MethodInvoker invoker;
 
       @Override
       public Object get(final GeneratedMessageV3 message) {
-        return invokeOrDie(getMethod, message);
+        return invoker.get(message);
       }
       @Override
       public Object get(GeneratedMessageV3.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
+        return invoker.get(builder);
       }
       @Override
       public Object getRaw(final GeneratedMessageV3 message) {
@@ -2107,134 +2327,324 @@
       }
       @Override
       public void set(final Builder builder, final Object value) {
-        invokeOrDie(setMethod, builder, value);
+        invoker.set(builder, value);
       }
       @Override
       public Object getRepeated(final GeneratedMessageV3 message, final int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedField() called on a singular field.");
+        throw new UnsupportedOperationException("getRepeatedField() called on a singular field.");
       }
       @Override
       public Object getRepeatedRaw(final GeneratedMessageV3 message, final int index) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldRaw() called on a singular field.");
+            "getRepeatedFieldRaw() called on a singular field.");
       }
       @Override
       public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
-        throw new UnsupportedOperationException(
-          "getRepeatedField() called on a singular field.");
+        throw new UnsupportedOperationException("getRepeatedField() called on a singular field.");
       }
       @Override
       public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldRaw() called on a singular field.");
+            "getRepeatedFieldRaw() called on a singular field.");
       }
       @Override
       public void setRepeated(final Builder builder, final int index, final Object value) {
-        throw new UnsupportedOperationException(
-          "setRepeatedField() called on a singular field.");
+        throw new UnsupportedOperationException("setRepeatedField() called on a singular field.");
       }
       @Override
       public void addRepeated(final Builder builder, final Object value) {
-        throw new UnsupportedOperationException(
-          "addRepeatedField() called on a singular field.");
+        throw new UnsupportedOperationException("addRepeatedField() called on a singular field.");
       }
       @Override
       public boolean has(final GeneratedMessageV3 message) {
         if (!hasHasMethod) {
           if (isOneofField) {
-            return getOneofFieldNumber(message) == field.getNumber();
+            return invoker.getOneofFieldNumber(message) == field.getNumber();
           }
           return !get(message).equals(field.getDefaultValue());
         }
-        return (Boolean) invokeOrDie(hasMethod, message);
+        return invoker.has(message);
       }
       @Override
       public boolean has(GeneratedMessageV3.Builder builder) {
         if (!hasHasMethod) {
           if (isOneofField) {
-            return getOneofFieldNumber(builder) == field.getNumber();
+            return invoker.getOneofFieldNumber(builder) == field.getNumber();
           }
           return !get(builder).equals(field.getDefaultValue());
         }
-        return (Boolean) invokeOrDie(hasMethodBuilder, builder);
+        return invoker.has(builder);
       }
       @Override
       public int getRepeatedCount(final GeneratedMessageV3 message) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldSize() called on a singular field.");
+            "getRepeatedFieldSize() called on a singular field.");
       }
       @Override
       public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldSize() called on a singular field.");
+            "getRepeatedFieldSize() called on a singular field.");
       }
       @Override
       public void clear(final Builder builder) {
-        invokeOrDie(clearMethod, builder);
+        invoker.clear(builder);
       }
       @Override
       public Message.Builder newBuilder() {
         throw new UnsupportedOperationException(
-          "newBuilderForField() called on a non-Message type.");
+            "newBuilderForField() called on a non-Message type.");
       }
       @Override
       public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
-        throw new UnsupportedOperationException(
-          "getFieldBuilder() called on a non-Message type.");
+        throw new UnsupportedOperationException("getFieldBuilder() called on a non-Message type.");
       }
       @Override
       public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldBuilder() called on a non-Message type.");
+            "getRepeatedFieldBuilder() called on a non-Message type.");
       }
     }
 
     private static class RepeatedFieldAccessor implements FieldAccessor {
+      interface MethodInvoker {
+        public Object get(final GeneratedMessageV3 message);
+
+        public Object get(GeneratedMessageV3.Builder<?> builder);
+
+        Object getRepeated(final GeneratedMessageV3 message, final int index);
+
+        Object getRepeated(GeneratedMessageV3.Builder<?> builder, int index);
+
+        void setRepeated(
+            final GeneratedMessageV3.Builder<?> builder, final int index, final Object value);
+
+        void addRepeated(final GeneratedMessageV3.Builder<?> builder, final Object value);
+
+        int getRepeatedCount(final GeneratedMessageV3 message);
+
+        int getRepeatedCount(GeneratedMessageV3.Builder<?> builder);
+
+        void clear(final GeneratedMessageV3.Builder<?> builder);
+      }
+
+      private static final class ReflectionInvoker implements MethodInvoker {
+        protected final Method getMethod;
+        protected final Method getMethodBuilder;
+        protected final Method getRepeatedMethod;
+        protected final Method getRepeatedMethodBuilder;
+        protected final Method setRepeatedMethod;
+        protected final Method addRepeatedMethod;
+        protected final Method getCountMethod;
+        protected final Method getCountMethodBuilder;
+        protected final Method clearMethod;
+
+        ReflectionInvoker(
+            final FieldDescriptor descriptor,
+            final String camelCaseName,
+            final Class<? extends GeneratedMessageV3> messageClass,
+            final Class<? extends Builder> builderClass) {
+          getMethod = getMethodOrDie(messageClass, "get" + camelCaseName + "List");
+          getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName + "List");
+          getRepeatedMethod = getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+          getRepeatedMethodBuilder =
+              getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
+          Class<?> type = getRepeatedMethod.getReturnType();
+          setRepeatedMethod =
+              getMethodOrDie(builderClass, "set" + camelCaseName, Integer.TYPE, type);
+          addRepeatedMethod = getMethodOrDie(builderClass, "add" + camelCaseName, type);
+          getCountMethod = getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+          getCountMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
+          clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+        }
+
+        @Override
+        public Object get(final GeneratedMessageV3 message) {
+          return invokeOrDie(getMethod, message);
+        }
+
+        @Override
+        public Object get(GeneratedMessageV3.Builder<?> builder) {
+          return invokeOrDie(getMethodBuilder, builder);
+        }
+
+        @Override
+        public Object getRepeated(
+            final GeneratedMessageV3 message, final int index) {
+          return invokeOrDie(getRepeatedMethod, message, index);
+        }
+
+        @Override
+        public Object getRepeated(GeneratedMessageV3.Builder<?> builder, int index) {
+          return invokeOrDie(getRepeatedMethodBuilder, builder, index);
+        }
+
+        @Override
+        public void setRepeated(
+            final GeneratedMessageV3.Builder<?> builder, final int index, final Object value) {
+          invokeOrDie(setRepeatedMethod, builder, index, value);
+        }
+
+        @Override
+        public void addRepeated(
+            final GeneratedMessageV3.Builder<?> builder, final Object value) {
+          invokeOrDie(addRepeatedMethod, builder, value);
+        }
+
+        @Override
+        public int getRepeatedCount(final GeneratedMessageV3 message) {
+          return (Integer) invokeOrDie(getCountMethod, message);
+        }
+
+        @Override
+        public int getRepeatedCount(GeneratedMessageV3.Builder<?> builder) {
+          return (Integer) invokeOrDie(getCountMethodBuilder, builder);
+        }
+
+        @Override
+        public void clear(final GeneratedMessageV3.Builder<?> builder) {
+          invokeOrDie(clearMethod, builder);
+        }
+      }
+
+      private static final class MethodHandleInvoker implements MethodInvoker {
+        protected final MethodHandle getMethod;
+        protected final MethodHandle getMethodBuilder;
+        protected final MethodHandle getRepeatedMethod;
+        protected final MethodHandle getRepeatedMethodBuilder;
+        protected final MethodHandle setRepeatedMethod;
+        protected final MethodHandle addRepeatedMethod;
+        protected final MethodHandle getCountMethod;
+        protected final MethodHandle getCountMethodBuilder;
+        protected final MethodHandle clearMethod;
+
+        MethodHandleInvoker(ReflectionInvoker accessor) throws IllegalAccessException {
+          MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+          this.getMethod = lookup.unreflect(accessor.getMethod);
+          this.getMethodBuilder = lookup.unreflect(accessor.getMethodBuilder);
+          this.getRepeatedMethod = lookup.unreflect(accessor.getRepeatedMethod);
+          this.getRepeatedMethodBuilder = lookup.unreflect(accessor.getRepeatedMethodBuilder);
+          this.setRepeatedMethod = lookup.unreflect(accessor.setRepeatedMethod);
+          this.addRepeatedMethod = lookup.unreflect(accessor.addRepeatedMethod);
+          this.getCountMethod = lookup.unreflect(accessor.getCountMethod);
+          this.getCountMethodBuilder = lookup.unreflect(accessor.getCountMethodBuilder);
+          this.clearMethod = lookup.unreflect(accessor.clearMethod);
+        }
+
+        @Override
+        public Object get(final GeneratedMessageV3 message) {
+          try {
+            return getMethod.invoke(message);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public Object get(GeneratedMessageV3.Builder<?> builder) {
+          try {
+            return getMethodBuilder.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public Object getRepeated(final GeneratedMessageV3 message, final int index) {
+          try {
+            return getRepeatedMethod.invoke(message, index);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public Object getRepeated(GeneratedMessageV3.Builder<?> builder, int index) {
+          try {
+            return getRepeatedMethodBuilder.invoke(builder, index);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public void setRepeated(
+            final GeneratedMessageV3.Builder<?> builder, final int index, final Object value) {
+          try {
+            setRepeatedMethod.invoke(builder, index, value);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public void addRepeated(final GeneratedMessageV3.Builder<?> builder, final Object value) {
+          try {
+            addRepeatedMethod.invoke(builder, value);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public int getRepeatedCount(final GeneratedMessageV3 message) {
+          try {
+            return (Integer) getCountMethod.invoke(message);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public int getRepeatedCount(GeneratedMessageV3.Builder<?> builder) {
+          try {
+            return (Integer) getCountMethodBuilder.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+
+        @Override
+        public void clear(final GeneratedMessageV3.Builder<?> builder) {
+          try {
+            clearMethod.invoke(builder);
+          } catch (Throwable e) {
+            throw handleException(e);
+          }
+        }
+      }
+
       protected final Class type;
-      protected final Method getMethod;
-      protected final Method getMethodBuilder;
-      protected final Method getRepeatedMethod;
-      protected final Method getRepeatedMethodBuilder;
-      protected final Method setRepeatedMethod;
-      protected final Method addRepeatedMethod;
-      protected final Method getCountMethod;
-      protected final Method getCountMethodBuilder;
-      protected final Method clearMethod;
+      protected final MethodInvoker invoker;
 
       RepeatedFieldAccessor(
           final FieldDescriptor descriptor, final String camelCaseName,
           final Class<? extends GeneratedMessageV3> messageClass,
           final Class<? extends Builder> builderClass) {
-        getMethod = getMethodOrDie(messageClass,
-                                   "get" + camelCaseName + "List");
-        getMethodBuilder = getMethodOrDie(builderClass,
-                                   "get" + camelCaseName + "List");
-        getRepeatedMethod =
-            getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
-        getRepeatedMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
-        type = getRepeatedMethod.getReturnType();
-        setRepeatedMethod =
-            getMethodOrDie(builderClass, "set" + camelCaseName,
-                           Integer.TYPE, type);
-        addRepeatedMethod =
-            getMethodOrDie(builderClass, "add" + camelCaseName, type);
-        getCountMethod =
-            getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
-        getCountMethodBuilder =
-            getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
+        ReflectionInvoker reflectionInvoker =
+            new ReflectionInvoker(descriptor, camelCaseName, messageClass, builderClass);
+        type = reflectionInvoker.getRepeatedMethod.getReturnType();
+        invoker = tryGetMethodHandleInvoke(reflectionInvoker);
+      }
 
-        clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+      static MethodInvoker tryGetMethodHandleInvoke(ReflectionInvoker accessor) {
+        if (forTestUseReflection) {
+          return accessor;
+        }
+        try {
+          return new MethodHandleInvoker(accessor);
+        } catch (IllegalAccessException e) {
+          throw new RuntimeException(e);
+        }
       }
 
       @Override
       public Object get(final GeneratedMessageV3 message) {
-        return invokeOrDie(getMethod, message);
+        return invoker.get(message);
       }
       @Override
       public Object get(GeneratedMessageV3.Builder builder) {
-        return invokeOrDie(getMethodBuilder, builder);
+        return invoker.get(builder);
       }
       @Override
       public Object getRaw(final GeneratedMessageV3 message) {
@@ -2257,11 +2667,11 @@
       }
       @Override
       public Object getRepeated(final GeneratedMessageV3 message, final int index) {
-        return invokeOrDie(getRepeatedMethod, message, index);
+        return invoker.getRepeated(message, index);
       }
       @Override
       public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
-        return invokeOrDie(getRepeatedMethodBuilder, builder, index);
+        return invoker.getRepeated(builder, index);
       }
       @Override
       public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
@@ -2273,48 +2683,45 @@
       }
       @Override
       public void setRepeated(final Builder builder, final int index, final Object value) {
-        invokeOrDie(setRepeatedMethod, builder, index, value);
+        invoker.setRepeated(builder, index, value);
       }
       @Override
       public void addRepeated(final Builder builder, final Object value) {
-        invokeOrDie(addRepeatedMethod, builder, value);
+        invoker.addRepeated(builder, value);
       }
       @Override
       public boolean has(final GeneratedMessageV3 message) {
-        throw new UnsupportedOperationException(
-          "hasField() called on a repeated field.");
+        throw new UnsupportedOperationException("hasField() called on a repeated field.");
       }
       @Override
       public boolean has(GeneratedMessageV3.Builder builder) {
-        throw new UnsupportedOperationException(
-          "hasField() called on a repeated field.");
+        throw new UnsupportedOperationException("hasField() called on a repeated field.");
       }
       @Override
       public int getRepeatedCount(final GeneratedMessageV3 message) {
-        return (Integer) invokeOrDie(getCountMethod, message);
+        return invoker.getRepeatedCount(message);
       }
       @Override
       public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
-        return (Integer) invokeOrDie(getCountMethodBuilder, builder);
+        return invoker.getRepeatedCount(builder);
       }
       @Override
       public void clear(final Builder builder) {
-        invokeOrDie(clearMethod, builder);
+        invoker.clear(builder);
       }
       @Override
       public Message.Builder newBuilder() {
         throw new UnsupportedOperationException(
-          "newBuilderForField() called on a non-Message type.");
+            "newBuilderForField() called on a non-Message type.");
       }
       @Override
       public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
-        throw new UnsupportedOperationException(
-          "getFieldBuilder() called on a non-Message type.");
+        throw new UnsupportedOperationException("getFieldBuilder() called on a non-Message type.");
       }
       @Override
       public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
         throw new UnsupportedOperationException(
-          "getRepeatedFieldBuilder() called on a non-Message type.");
+            "getRepeatedFieldBuilder() called on a non-Message type.");
       }
     }
 
@@ -2489,10 +2896,8 @@
 
         enumDescriptor = descriptor.getEnumType();
 
-        valueOfMethod = getMethodOrDie(type, "valueOf",
-                                       EnumValueDescriptor.class);
-        getValueDescriptorMethod =
-          getMethodOrDie(type, "getValueDescriptor");
+        valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
+        getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
 
         supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
         if (supportUnknownEnumValue) {
@@ -2554,10 +2959,8 @@
 
         enumDescriptor = descriptor.getEnumType();
 
-        valueOfMethod = getMethodOrDie(type, "valueOf",
-                                       EnumValueDescriptor.class);
-        getValueDescriptorMethod =
-          getMethodOrDie(type, "getValueDescriptor");
+        valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
+        getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
 
         supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
         if (supportUnknownEnumValue) {
@@ -2605,35 +3008,31 @@
       }
 
       @Override
-      public Object getRepeated(final GeneratedMessageV3 message,
-                                final int index) {
+      public Object getRepeated(final GeneratedMessageV3 message, final int index) {
         if (supportUnknownEnumValue) {
           int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index);
           return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
         }
-        return invokeOrDie(getValueDescriptorMethod,
-          super.getRepeated(message, index));
+        return invokeOrDie(getValueDescriptorMethod, super.getRepeated(message, index));
       }
+
       @Override
-      public Object getRepeated(final GeneratedMessageV3.Builder builder,
-                                final int index) {
+      public Object getRepeated(final GeneratedMessageV3.Builder builder, final int index) {
         if (supportUnknownEnumValue) {
           int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index);
           return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
         }
-        return invokeOrDie(getValueDescriptorMethod,
-          super.getRepeated(builder, index));
+        return invokeOrDie(getValueDescriptorMethod, super.getRepeated(builder, index));
       }
+
       @Override
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
+      public void setRepeated(final Builder builder, final int index, final Object value) {
         if (supportUnknownEnumValue) {
           invokeOrDie(setRepeatedValueMethod, builder, index,
               ((EnumValueDescriptor) value).getNumber());
           return;
         }
-        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
-                          value));
+        super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null, value));
       }
       @Override
       public void addRepeated(final Builder builder, final Object value) {
@@ -2729,7 +3128,8 @@
           // DynamicMessage -- we should accept it.  In this case we can make
           // a copy of the message.
           return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
-                  .mergeFrom((Message) value).buildPartial();
+              .mergeFrom((Message) value)
+              .buildPartial();
         }
       }
 
@@ -2772,13 +3172,13 @@
           // DynamicMessage -- we should accept it.  In this case we can make
           // a copy of the message.
           return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
-                  .mergeFrom((Message) value).build();
+              .mergeFrom((Message) value)
+              .build();
         }
       }
 
       @Override
-      public void setRepeated(final Builder builder,
-                              final int index, final Object value) {
+      public void setRepeated(final Builder builder, final int index, final Object value) {
         super.setRepeated(builder, index, coerceType(value));
       }
       @Override
@@ -2809,12 +3209,10 @@
   }
 
   /**
-   * Checks that the {@link Extension} is non-Lite and returns it as a
-   * {@link GeneratedExtension}.
+   * Checks that the {@link Extension} is non-Lite and returns it as a {@link GeneratedExtension}.
    */
   private static <MessageType extends ExtendableMessage<MessageType>, T>
-    Extension<MessageType, T> checkNotLite(
-        ExtensionLite<MessageType, T> extension) {
+      Extension<MessageType, T> checkNotLite(ExtensionLite<MessageType, T> extension) {
     if (extension.isLite()) {
       throw new IllegalArgumentException("Expected non-lite extension.");
     }
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 54a378b..98f1f81 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(new int[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@
   }
 
   @Override
+  public boolean add(Integer element) {
+    addInt(element);
+    return true;
+  }
+
+  @Override
   public void add(int index, Integer element) {
     addInt(index, element);
   }
@@ -167,7 +172,17 @@
   /** Like {@link #add(Integer)} but more efficient in that it doesn't box the element. */
   @Override
   public void addInt(int element) {
-    addInt(size, element);
+    ensureIsMutable();
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      int[] newArray = new int[length];
+
+      System.arraycopy(array, 0, newArray, 0, size);
+      array = newArray;
+    }
+
+    array[size++] = element;
   }
 
   /** Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element. */
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 1a0943c..2dd15b4 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(new long[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@
   }
 
   @Override
+  public boolean add(Long element) {
+    addLong(element);
+    return true;
+  }
+
+  @Override
   public void add(int index, Long element) {
     addLong(index, element);
   }
@@ -167,7 +172,17 @@
   /** Like {@link #add(Long)} but more efficient in that it doesn't box the element. */
   @Override
   public void addLong(long element) {
-    addLong(size, element);
+    ensureIsMutable();
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      long[] newArray = new long[length];
+
+      System.arraycopy(array, 0, newArray, 0, size);
+      array = newArray;
+    }
+
+    array[size++] = element;
   }
 
   /** Like {@link #add(int, Long)} but more efficient in that it doesn't box the element. */
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
index f9a9c85..175b1dd 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -31,14 +31,13 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Internal.ProtobufList;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
 
 /** Implements {@link ProtobufList} for non-primitive and {@link String} types. */
 final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
 
   private static final ProtobufArrayList<Object> EMPTY_LIST =
-      new ProtobufArrayList<Object>(new ArrayList<Object>(0));
+      new ProtobufArrayList<Object>(new Object[0], 0);
 
   static {
     EMPTY_LIST.makeImmutable();
@@ -49,56 +48,127 @@
     return (ProtobufArrayList<E>) EMPTY_LIST;
   }
 
-  private final List<E> list;
+  private E[] array;
+  private int size;
 
+  @SuppressWarnings("unchecked")
   ProtobufArrayList() {
-    this(new ArrayList<E>(DEFAULT_CAPACITY));
+    this((E[]) new Object[DEFAULT_CAPACITY], 0);
   }
 
-  private ProtobufArrayList(List<E> list) {
-    this.list = list;
+  private ProtobufArrayList(E[] array, int size) {
+    this.array = array;
+    this.size = size;
   }
 
   @Override
   public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
-    if (capacity < size()) {
+    if (capacity < size) {
       throw new IllegalArgumentException();
     }
-    List<E> newList = new ArrayList<E>(capacity);
-    newList.addAll(list);
-    return new ProtobufArrayList<E>(newList);
+
+    E[] newArray = Arrays.copyOf(array, capacity);
+
+    return new ProtobufArrayList<E>(newArray, size);
+  }
+
+  @Override
+  public boolean add(E element) {
+    ensureIsMutable();
+
+    if (size == array.length) {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      E[] newArray = Arrays.copyOf(array, length);
+
+      array = newArray;
+    }
+
+    array[size++] = element;
+    modCount++;
+
+    return true;
   }
 
   @Override
   public void add(int index, E element) {
     ensureIsMutable();
-    list.add(index, element);
+
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      E[] newArray = createArray(length);
+
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
     modCount++;
   }
 
   @Override
   public E get(int index) {
-    return list.get(index);
+    ensureIndexInRange(index);
+    return array[index];
   }
 
   @Override
   public E remove(int index) {
     ensureIsMutable();
-    E toReturn = list.remove(index);
+    ensureIndexInRange(index);
+
+    E value = array[index];
+    if (index < size - 1) {
+      System.arraycopy(array, index + 1, array, index, size - index - 1);
+    }
+
+    size--;
     modCount++;
-    return toReturn;
+    return value;
   }
 
   @Override
   public E set(int index, E element) {
     ensureIsMutable();
-    E toReturn = list.set(index, element);
+    ensureIndexInRange(index);
+
+    E toReturn = array[index];
+    array[index] = element;
+
     modCount++;
     return toReturn;
   }
 
   @Override
   public int size() {
-    return list.size();
+    return size;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static <E> E[] createArray(int capacity) {
+    return (E[]) new Object[capacity];
+  }
+
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
   }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
index 2d025fe..12bba6b 100644
--- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
+++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -69,6 +69,7 @@
 import java.util.Iterator;
 import java.util.List;
 import junit.framework.TestCase;
+import junit.framework.TestSuite;
 
 /**
  * Unit test for generated messages and generated code. See also {@link MessageTest}, which tests
@@ -80,6 +81,40 @@
   TestUtil.ReflectionTester reflectionTester =
       new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
 
+  public static TestSuite suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(ReflectionTest.class);
+    suite.addTestSuite(FastInvokeTest.class);
+    return suite;
+  }
+
+  public static class ReflectionTest extends GeneratedMessageTest {
+    public ReflectionTest() {
+      super(true);
+    }
+  }
+
+  public static class FastInvokeTest extends GeneratedMessageTest {
+    public FastInvokeTest() {
+      super(false);
+    }
+  }
+
+  private final boolean useReflection;
+
+  GeneratedMessageTest(boolean useReflection) {
+    this.useReflection = useReflection;
+  }
+
+  @Override public void setUp() {
+    GeneratedMessageV3.setForTestUseReflection(useReflection);
+  }
+
+  @Override public void tearDown() {
+    GeneratedMessageV3.setForTestUseReflection(false);
+    GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(false);
+  }
+
   public void testDefaultInstance() throws Exception {
     assertSame(
         TestAllTypes.getDefaultInstance(),
@@ -937,7 +972,7 @@
   }
 
   public void testInvalidations() throws Exception {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+    GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(true);
     TestAllTypes.NestedMessage nestedMessage1 = TestAllTypes.NestedMessage.newBuilder().build();
     TestAllTypes.NestedMessage nestedMessage2 = TestAllTypes.NestedMessage.newBuilder().build();
 
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 36e5eea..22c0be2 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -2776,7 +2776,7 @@
     }
 
     /** Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes. */
-    private Descriptors.FieldDescriptor f(String name) {
+    Descriptors.FieldDescriptor f(String name) {
       Descriptors.FieldDescriptor result;
       if (extensionRegistry == null) {
         result = baseDescriptor.findFieldByName(name);
diff --git a/src/Makefile.am b/src/Makefile.am
index f869d56..dc50703 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -699,7 +699,7 @@
 COMMON_TEST_SOURCES =                                          \
   google/protobuf/arena_test_util.cc                           \
   google/protobuf/arena_test_util.h                            \
-  google/protobuf/map_test_util.cc                             \
+  google/protobuf/map_test_util.inc                            \
   google/protobuf/map_test_util.h                              \
   google/protobuf/map_test_util_impl.h                         \
   google/protobuf/test_util.cc                                 \
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index a7d9fbe..bd382d1 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -271,37 +270,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Any::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Any)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string type_url = 1;
-  if (this->type_url().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->type_url().data(), static_cast<int>(this->type_url().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Any.type_url");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->type_url(), output);
-  }
-
-  // bytes value = 2;
-  if (this->value().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesMaybeAliased(
-      2, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Any)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Any::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -312,21 +282,19 @@
       this->type_url().data(), static_cast<int>(this->type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Any.type_url");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->type_url(), target);
   }
 
   // bytes value = 2;
   if (this->value().size() > 0) {
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesToArray(
+    target = stream->WriteBytesMaybeAliased(
         2, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Any)
   return target;
@@ -336,11 +304,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -359,6 +322,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 0264bd7..7430dce 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -157,10 +157,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index 26bd56d..123026f 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -485,80 +484,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Api::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Api)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Api.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.Method methods = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->methods_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->methods(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  // string version = 4;
-  if (this->version().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->version().data(), static_cast<int>(this->version().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Api.version");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      4, this->version(), output);
-  }
-
-  // .google.protobuf.SourceContext source_context = 5;
-  if (this->has_source_context()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5, _Internal::source_context(this), output);
-  }
-
-  // repeated .google.protobuf.Mixin mixins = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->mixins_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6,
-      this->mixins(static_cast<int>(i)),
-      output);
-  }
-
-  // .google.protobuf.Syntax syntax = 7;
-  if (this->syntax() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      7, this->syntax(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Api)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Api::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -569,25 +496,24 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Api.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.Method methods = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->methods_size()); i < n; i++) {
+  for (auto it = this->methods().pointer_begin(),
+            end = this->methods().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->methods(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        3, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(3, **it, target, stream);
   }
 
   // string version = 4;
@@ -596,35 +522,36 @@
       this->version().data(), static_cast<int>(this->version().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Api.version");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         4, this->version(), target);
   }
 
   // .google.protobuf.SourceContext source_context = 5;
   if (this->has_source_context()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        5, _Internal::source_context(this), target);
+        5, _Internal::source_context(this), target, stream);
   }
 
   // repeated .google.protobuf.Mixin mixins = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->mixins_size()); i < n; i++) {
+  for (auto it = this->mixins().pointer_begin(),
+            end = this->mixins().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        6, this->mixins(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(6, **it, target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 7;
   if (this->syntax() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       7, this->syntax(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api)
   return target;
@@ -634,11 +561,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -703,6 +625,10 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->syntax());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1081,76 +1007,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Method::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Method)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Method.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // string request_type_url = 2;
-  if (this->request_type_url().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->request_type_url().data(), static_cast<int>(this->request_type_url().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Method.request_type_url");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->request_type_url(), output);
-  }
-
-  // bool request_streaming = 3;
-  if (this->request_streaming() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(3, this->request_streaming(), output);
-  }
-
-  // string response_type_url = 4;
-  if (this->response_type_url().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->response_type_url().data(), static_cast<int>(this->response_type_url().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Method.response_type_url");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      4, this->response_type_url(), output);
-  }
-
-  // bool response_streaming = 5;
-  if (this->response_streaming() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(5, this->response_streaming(), output);
-  }
-
-  // repeated .google.protobuf.Option options = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  // .google.protobuf.Syntax syntax = 7;
-  if (this->syntax() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      7, this->syntax(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Method)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Method::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1161,8 +1019,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -1172,13 +1029,13 @@
       this->request_type_url().data(), static_cast<int>(this->request_type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.request_type_url");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->request_type_url(), target);
   }
 
   // bool request_streaming = 3;
   if (this->request_streaming() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->request_streaming(), target);
   }
 
@@ -1188,33 +1045,34 @@
       this->response_type_url().data(), static_cast<int>(this->response_type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Method.response_type_url");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         4, this->response_type_url(), target);
   }
 
   // bool response_streaming = 5;
   if (this->response_streaming() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->response_streaming(), target);
   }
 
   // repeated .google.protobuf.Option options = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        6, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(6, **it, target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 7;
   if (this->syntax() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       7, this->syntax(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method)
   return target;
@@ -1224,11 +1082,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1281,6 +1134,10 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->syntax());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1537,41 +1394,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Mixin::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Mixin)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Mixin.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // string root = 2;
-  if (this->root().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->root().data(), static_cast<int>(this->root().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Mixin.root");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->root(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Mixin)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Mixin::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1582,8 +1406,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Mixin.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -1593,14 +1416,13 @@
       this->root().data(), static_cast<int>(this->root().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Mixin.root");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->root(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin)
   return target;
@@ -1610,11 +1432,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1633,6 +1450,10 @@
         this->root());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index f0a292d..836641f 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -151,10 +151,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -357,10 +355,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -554,10 +550,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index dedc221..5eeb99e 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -50,9 +50,9 @@
 #include <typeinfo>
 #endif
 
-#include <google/protobuf/arena_impl.h>
 #include <google/protobuf/port.h>
 #include <type_traits>
+#include <google/protobuf/arena_impl.h>
 
 #include <google/protobuf/port_def.inc>
 
diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h
index f4ff07d..99e26b8 100644
--- a/src/google/protobuf/arenastring.h
+++ b/src/google/protobuf/arenastring.h
@@ -32,22 +32,28 @@
 #define GOOGLE_PROTOBUF_ARENASTRING_H__
 
 #include <string>
+#include <utility>
 
-#include <google/protobuf/arena.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/fastmem.h>
-#include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/port.h>
 
 #include <google/protobuf/port_def.inc>
 
+#ifdef SWIG
+#error "You cannot SWIG proto headers"
+#endif
+
+
 // This is the implementation of arena string fields written for the open-source
 // release. The ArenaStringPtr struct below is an internal implementation class
 // and *should not be used* by user code. It is used to collect string
 // operations together into one place and abstract away the underlying
 // string-field pointer representation, so that (for example) an alternate
-// implementation that knew more about ::std::string's internals could integrate more
-// closely with the arena allocator.
+// implementation that knew more about ::std::string's internals could integrate
+// more closely with the arena allocator.
 
 namespace google {
 namespace protobuf {
@@ -115,14 +121,14 @@
     } else {
       released = ptr_;
     }
-    ptr_ = const_cast< ::std::string* >(default_value);
+    ptr_ = const_cast< ::std::string*>(default_value);
     return released;
   }
 
-  // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned (i.e.
-  // have its destructor already registered) if arena != NULL. If the field was
-  // not set, this returns NULL. This method clears this field back to NULL
-  // state. Used to implement unsafe_arena_release_<field>() methods on
+  // UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned
+  // (i.e.  have its destructor already registered) if arena != NULL. If the
+  // field was not set, this returns NULL. This method clears this field back to
+  // NULL state. Used to implement unsafe_arena_release_<field>() methods on
   // generated classes.
   inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
                                            Arena* /* arena */) {
@@ -130,7 +136,7 @@
       return NULL;
     }
     ::std::string* released = ptr_;
-    ptr_ = const_cast< ::std::string* >(default_value);
+    ptr_ = const_cast< ::std::string*>(default_value);
     return released;
   }
 
@@ -148,7 +154,7 @@
         arena->Own(value);
       }
     } else {
-      ptr_ = const_cast< ::std::string* >(default_value);
+      ptr_ = const_cast< ::std::string*>(default_value);
     }
   }
 
@@ -162,7 +168,7 @@
     if (value != NULL) {
       ptr_ = value;
     } else {
-      ptr_ = const_cast< ::std::string* >(default_value);
+      ptr_ = const_cast< ::std::string*>(default_value);
     }
   }
 
@@ -221,12 +227,8 @@
 
   // Clears content, assuming that the current value is not the empty string
   // default.
-  inline void ClearNonDefaultToEmpty() {
-    ptr_->clear();
-  }
-  inline void ClearNonDefaultToEmptyNoArena() {
-    ptr_->clear();
-  }
+  inline void ClearNonDefaultToEmpty() { ptr_->clear(); }
+  inline void ClearNonDefaultToEmptyNoArena() { ptr_->clear(); }
 
   // Clears content, but keeps allocated string if arena != NULL, to avoid the
   // overhead of heap operations. After this returns, the content (as seen by
@@ -251,7 +253,7 @@
   inline void UnsafeSetDefault(const ::std::string* default_value) {
     // Casting away 'const' is safe here: accessors ensure that ptr_ is only
     // returned as a const if it is equal to default_value.
-    ptr_ = const_cast< ::std::string* >(default_value);
+    ptr_ = const_cast< ::std::string*>(default_value);
   }
 
   // The 'NoArena' variants of methods below assume arena == NULL and are
@@ -270,7 +272,6 @@
     }
   }
 
-#if LANG_CXX11
   void SetNoArena(const ::std::string* default_value, ::std::string&& value) {
     if (IsDefault(default_value)) {
       ptr_ = new ::std::string(std::move(value));
@@ -278,9 +279,9 @@
       *ptr_ = std::move(value);
     }
   }
-#endif
 
-  void AssignWithDefault(const ::std::string* default_value, ArenaStringPtr value);
+  void AssignWithDefault(const ::std::string* default_value,
+                         ArenaStringPtr value);
 
   inline const ::std::string& GetNoArena() const { return *ptr_; }
 
@@ -303,11 +304,10 @@
       const ::std::string* default_value) {
     GOOGLE_DCHECK(!IsDefault(default_value));
     ::std::string* released = ptr_;
-    ptr_ = const_cast< ::std::string* >(default_value);
+    ptr_ = const_cast< ::std::string*>(default_value);
     return released;
   }
 
-
   inline void SetAllocatedNoArena(const ::std::string* default_value,
                                   ::std::string* value) {
     if (ptr_ != default_value) {
@@ -316,7 +316,7 @@
     if (value != NULL) {
       ptr_ = value;
     } else {
-      ptr_ = const_cast< ::std::string* >(default_value);
+      ptr_ = const_cast< ::std::string*>(default_value);
     }
   }
 
@@ -347,9 +347,7 @@
   // raw pointer from the shared parse routine (in the non-arenas case). The
   // parse routine does the string allocation in order to save code size in the
   // generated parsing code.
-  inline ::std::string** UnsafeRawStringPointer() {
-    return &ptr_;
-  }
+  inline ::std::string** UnsafeRawStringPointer() { return &ptr_; }
 
   inline bool IsDefault(const ::std::string* default_value) const {
     return ptr_ == default_value;
@@ -371,7 +369,7 @@
   void CreateInstance(Arena* arena, const ::std::string* initial_value) {
     GOOGLE_DCHECK(initial_value != NULL);
     // uses "new ::std::string" when arena is nullptr
-    ptr_ = Arena::Create< ::std::string >(arena, *initial_value);
+    ptr_ = Arena::Create< ::std::string>(arena, *initial_value);
   }
   PROTOBUF_NOINLINE
   void CreateInstanceNoArena(const ::std::string* initial_value) {
@@ -383,13 +381,11 @@
 }  // namespace internal
 }  // namespace protobuf
 
-
-
 namespace protobuf {
 namespace internal {
 
-inline void ArenaStringPtr::AssignWithDefault(const ::std::string* default_value,
-                                       ArenaStringPtr value) {
+inline void ArenaStringPtr::AssignWithDefault(
+    const ::std::string* default_value, ArenaStringPtr value) {
   const ::std::string* me = *UnsafeRawStringPointer();
   const ::std::string* other = *value.UnsafeRawStringPointer();
   // If the pointers are the same then do nothing.
@@ -402,6 +398,7 @@
 }  // namespace protobuf
 }  // namespace google
 
+
 #include <google/protobuf/port_undef.inc>
 
 #endif  // GOOGLE_PROTOBUF_ARENASTRING_H__
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index a74aaef..557bec3 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -34,7 +34,6 @@
 
 #include <google/protobuf/compiler/command_line_interface.h>
 
-
 #include <google/protobuf/stubs/platform_macros.h>
 
 #include <stdio.h>
@@ -80,6 +79,8 @@
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+
+
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/stl_util.h>
 
@@ -366,7 +367,6 @@
 class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
  public:
   GeneratorContextImpl(const std::vector<const FileDescriptor*>& parsed_files);
-  ~GeneratorContextImpl();
 
   // Write all files in the directory to disk at the given output location,
   // which must end in a '/'.
@@ -397,7 +397,7 @@
 
   // map instead of unordered_map so that files are written in order (good when
   // writing zips).
-  std::map<std::string, std::string*> files_;
+  std::map<std::string, std::string> files_;
   const std::vector<const FileDescriptor*>& parsed_files_;
   bool had_error_;
 };
@@ -446,10 +446,6 @@
     const std::vector<const FileDescriptor*>& parsed_files)
     : parsed_files_(parsed_files), had_error_(false) {}
 
-CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() {
-  STLDeleteValues(&files_);
-}
-
 bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
     const std::string& prefix) {
   if (had_error_) {
@@ -460,12 +456,10 @@
     return false;
   }
 
-  for (std::map<std::string, std::string*>::const_iterator iter =
-           files_.begin();
-       iter != files_.end(); ++iter) {
-    const std::string& relative_filename = iter->first;
-    const char* data = iter->second->data();
-    int size = iter->second->size();
+  for (const auto& pair : files_) {
+    const std::string& relative_filename = pair.first;
+    const char* data = pair.second.data();
+    int size = pair.second.size();
 
     if (!TryCreateParentDirectory(prefix, relative_filename)) {
       return false;
@@ -549,10 +543,8 @@
   io::FileOutputStream stream(file_descriptor);
   ZipWriter zip_writer(&stream);
 
-  for (std::map<std::string, std::string*>::const_iterator iter =
-           files_.begin();
-       iter != files_.end(); ++iter) {
-    zip_writer.Write(iter->first, *iter->second);
+  for (const auto& pair : files_) {
+    zip_writer.Write(pair.first, pair.second);
   }
 
   zip_writer.WriteDirectory();
@@ -569,20 +561,19 @@
 }
 
 void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
-  std::string** map_slot = &files_["META-INF/MANIFEST.MF"];
-  if (*map_slot == NULL) {
-    *map_slot = new std::string(
+  auto pair = files_.insert({"META-INF/MANIFEST.MF", ""});
+  if (pair.second) {
+    pair.first->second =
         "Manifest-Version: 1.0\n"
         "Created-By: 1.6.0 (protoc)\n"
-        "\n");
+        "\n";
   }
 }
 
 void CommandLineInterface::GeneratorContextImpl::GetOutputFilenames(
     std::vector<std::string>* output_filenames) {
-  for (std::map<std::string, std::string*>::iterator iter = files_.begin();
-       iter != files_.end(); ++iter) {
-    output_filenames->push_back(iter->first);
+  for (const auto& pair : files_) {
+    output_filenames->push_back(pair.first);
   }
 }
 
@@ -623,17 +614,16 @@
 
 void CommandLineInterface::MemoryOutputStream::UpdateMetadata(
     size_t insertion_offset, size_t insertion_length) {
-  std::map<std::string, std::string*>::iterator meta_file =
-      directory_->files_.find(filename_ + ".meta");
-  if (meta_file == directory_->files_.end() || !meta_file->second) {
+  auto it = directory_->files_.find(filename_ + ".meta");
+  if (it == directory_->files_.end()) {
     // No metadata was recorded for this file.
     return;
   }
-  std::string* encoded_data = meta_file->second;
+  std::string& encoded_data = it->second;
   GeneratedCodeInfo metadata;
   bool is_text_format = false;
-  if (!metadata.ParseFromString(*encoded_data)) {
-    if (!TextFormat::ParseFromString(*encoded_data, &metadata)) {
+  if (!metadata.ParseFromString(encoded_data)) {
+    if (!TextFormat::ParseFromString(encoded_data, &metadata)) {
       // The metadata is invalid.
       std::cerr << filename_
                 << ".meta: Could not parse metadata as wire or text format."
@@ -653,9 +643,9 @@
     }
   }
   if (is_text_format) {
-    TextFormat::PrintToString(metadata, encoded_data);
+    TextFormat::PrintToString(metadata, &encoded_data);
   } else {
-    metadata.SerializeToString(encoded_data);
+    metadata.SerializeToString(&encoded_data);
   }
 }
 
@@ -664,13 +654,15 @@
   inner_.reset();
 
   // Insert into the directory.
-  std::string** map_slot = &directory_->files_[filename_];
+  auto pair = directory_->files_.insert({filename_, ""});
+  auto it = pair.first;
+  bool already_present = !pair.second;
 
   if (insertion_point_.empty()) {
     // This was just a regular Open().
-    if (*map_slot != NULL) {
+    if (already_present) {
       if (append_mode_) {
-        (*map_slot)->append(data_);
+        it->second.append(data_);
       } else {
         std::cerr << filename_ << ": Tried to write the same file twice."
                   << std::endl;
@@ -679,8 +671,7 @@
       return;
     }
 
-    *map_slot = new std::string;
-    (*map_slot)->swap(data_);
+    it->second.swap(data_);
   } else {
     // This was an OpenForInsert().
 
@@ -690,14 +681,14 @@
     }
 
     // Find the file we are going to insert into.
-    if (*map_slot == NULL) {
+    if (!already_present) {
       std::cerr << filename_
                 << ": Tried to insert into file that doesn't exist."
                 << std::endl;
       directory_->had_error_ = true;
       return;
     }
-    std::string* target = *map_slot;
+    std::string* target = &it->second;
 
     // Find the insertion point.
     std::string magic_string =
@@ -896,28 +887,27 @@
           !HasSuffixString(output_location, ".jar")) {
         AddTrailingSlash(&output_location);
       }
-      GeneratorContextImpl** map_slot = &output_directories[output_location];
 
-      if (*map_slot == NULL) {
+      auto& generator = output_directories[output_location];
+
+      if (!generator) {
         // First time we've seen this output location.
-        *map_slot = new GeneratorContextImpl(parsed_files);
+        generator.reset(new GeneratorContextImpl(parsed_files));
       }
 
-      if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) {
-        STLDeleteValues(&output_directories);
+      if (!GenerateOutput(parsed_files, output_directives_[i],
+                          generator.get())) {
         return 1;
       }
     }
   }
 
   // Write all output to disk.
-  for (GeneratorContextMap::iterator iter = output_directories.begin();
-       iter != output_directories.end(); ++iter) {
-    const std::string& location = iter->first;
-    GeneratorContextImpl* directory = iter->second;
+  for (const auto& pair : output_directories) {
+    const std::string& location = pair.first;
+    GeneratorContextImpl* directory = pair.second.get();
     if (HasSuffixString(location, "/")) {
       if (!directory->WriteAllToDisk(location)) {
-        STLDeleteValues(&output_directories);
         return 1;
       }
     } else {
@@ -926,7 +916,6 @@
       }
 
       if (!directory->WriteAllToZip(location)) {
-        STLDeleteValues(&output_directories);
         return 1;
       }
     }
@@ -940,8 +929,6 @@
     }
   }
 
-  STLDeleteValues(&output_directories);
-
   if (!descriptor_set_out_name_.empty()) {
     if (!WriteDescriptorSet(parsed_files)) {
       return 1;
@@ -1955,10 +1942,9 @@
   }
 
   std::vector<std::string> output_filenames;
-  for (GeneratorContextMap::const_iterator iter = output_directories.begin();
-       iter != output_directories.end(); ++iter) {
-    const std::string& location = iter->first;
-    GeneratorContextImpl* directory = iter->second;
+  for (const auto& pair : output_directories) {
+    const std::string& location = pair.first;
+    GeneratorContextImpl* directory = pair.second.get();
     std::vector<std::string> relative_output_filenames;
     directory->GetOutputFilenames(&relative_output_filenames);
     for (int i = 0; i < relative_output_filenames.size(); i++) {
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index 6c9893f..49d7259 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -39,6 +39,7 @@
 #define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
 
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -46,7 +47,6 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
-
 #include <google/protobuf/port_def.inc>
 
 namespace google {
@@ -208,7 +208,7 @@
   class ErrorPrinter;
   class GeneratorContextImpl;
   class MemoryOutputStream;
-  typedef std::unordered_map<std::string, GeneratorContextImpl*>
+  typedef std::unordered_map<std::string, std::unique_ptr<GeneratorContextImpl>>
       GeneratorContextMap;
 
   // Clear state from previous Run().
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index debd9a0..ef5be03 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -84,16 +84,13 @@
 
 class MockGeneratorContext : public GeneratorContext {
  public:
-  MockGeneratorContext() {}
-  ~MockGeneratorContext() { STLDeleteValues(&files_); }
-
   void ExpectFileMatches(const std::string& virtual_filename,
                          const std::string& physical_filename) {
-    std::string* expected_contents =
-        FindPtrOrNull(files_, virtual_filename);
-    ASSERT_TRUE(expected_contents != NULL)
+    auto it = files_.find(virtual_filename);
+    ASSERT_TRUE(it != files_.end())
         << "Generator failed to generate file: " << virtual_filename;
 
+    std::string expected_contents = *it->second;
     std::string actual_contents;
     GOOGLE_CHECK_OK(
         File::GetContents(TestUtil::TestSourceDir() + "/" + physical_filename,
@@ -102,13 +99,13 @@
     CleanStringLineEndings(&actual_contents, false);
 
 #ifdef WRITE_FILES  // Define to debug mismatched files.
-    GOOGLE_CHECK_OK(File::SetContents("/tmp/expected.cc", *expected_contents,
+    GOOGLE_CHECK_OK(File::SetContents("/tmp/expected.cc", expected_contents,
                                true));
     GOOGLE_CHECK_OK(
         File::SetContents("/tmp/actual.cc", actual_contents, true));
 #endif
 
-    ASSERT_EQ(*expected_contents, actual_contents)
+    ASSERT_EQ(expected_contents, actual_contents)
         << physical_filename
         << " needs to be regenerated.  Please run "
            "generate_descriptor_proto.sh. "
@@ -118,15 +115,13 @@
   // implements GeneratorContext --------------------------------------
 
   virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
-    std::string** map_slot = &files_[filename];
-    delete *map_slot;
-    *map_slot = new std::string;
-
-    return new io::StringOutputStream(*map_slot);
+    auto& map_slot = files_[filename];
+    map_slot.reset(new std::string);
+    return new io::StringOutputStream(map_slot.get());
   }
 
  private:
-  std::map<std::string, std::string*> files_;
+  std::map<std::string, std::unique_ptr<std::string>> files_;
 };
 
 const char kDescriptorParameter[] = "dllexport_decl=PROTOBUF_EXPORT";
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 10eed3d..9fdde41 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -86,10 +86,12 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return static_cast< $type$ >($name$_);\n"
       "}\n"
-      "inline void $classname$::set_$name$($type$ value) {\n");
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "$annotate_accessor$");
   if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
     format("  assert($type$_IsValid(value));\n");
   }
@@ -157,18 +159,11 @@
   }
 }
 
-void EnumFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  format(
-      "::$proto_ns$::internal::WireFormatLite::WriteEnum(\n"
-      "  $number$, this->$name$(), output);\n");
-}
-
 void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   format(
+      "stream->EnsureSpace(&target);\n"
       "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
       "  $number$, this->$name$(), target);\n");
 }
@@ -195,13 +190,15 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  if (has_$name$()) {\n"
       "    return static_cast< $type$ >($field_member$);\n"
       "  }\n"
       "  return static_cast< $type$ >($default$);\n"
       "}\n"
-      "inline void $classname$::set_$name$($type$ value) {\n");
+      "inline void $classname$::set_$name$($type$ value) {\n"
+      "$annotate_accessor$");
   if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
     format("  assert($type$_IsValid(value));\n");
   }
@@ -269,10 +266,12 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$(int index) const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return static_cast< $type$ >($name$_.Get(index));\n"
       "}\n"
-      "inline void $classname$::set_$name$(int index, $type$ value) {\n");
+      "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+      "$annotate_accessor$");
   if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
     format("  assert($type$_IsValid(value));\n");
   }
@@ -280,7 +279,8 @@
       "  $name$_.Set(index, value);\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
-      "inline void $classname$::add_$name$($type$ value) {\n");
+      "inline void $classname$::add_$name$($type$ value) {\n"
+      "$annotate_accessor$");
   if (!HasPreservingUnknownEnumSemantics(descriptor_)) {
     format("  assert($type$_IsValid(value));\n");
   }
@@ -290,11 +290,13 @@
       "}\n"
       "inline const ::$proto_ns$::RepeatedField<int>&\n"
       "$classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_list:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
       "inline ::$proto_ns$::RepeatedField<int>*\n"
       "$classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
       "  return &$name$_;\n"
       "}\n");
@@ -423,58 +425,27 @@
   }
 }
 
-void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  if (descriptor_->is_packed()) {
-    // Write the tag and the size.
-    format(
-        "if (this->$name$_size() > 0) {\n"
-        "  ::$proto_ns$::internal::WireFormatLite::WriteTag(\n"
-        "    $number$,\n"
-        "    "
-        "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
-        "    output);\n"
-        "  output->WriteVarint32(_$name$_cached_byte_size_.load(\n"
-        "      std::memory_order_relaxed));\n"
-        "}\n");
-  }
-  format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
-  if (descriptor_->is_packed()) {
-    format(
-        "  ::$proto_ns$::internal::WireFormatLite::WriteEnumNoTag(\n"
-        "    this->$name$(i), output);\n");
-  } else {
-    format(
-        "  ::$proto_ns$::internal::WireFormatLite::WriteEnum(\n"
-        "    $number$, this->$name$(i), output);\n");
-  }
-  format("}\n");
-}
-
 void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   if (descriptor_->is_packed()) {
     // Write the tag and the size.
     format(
-        "if (this->$name$_size() > 0) {\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::WriteTagToArray(\n"
-        "    $number$,\n"
-        "    "
-        "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
-        "    target);\n"
-        "  target = ::$proto_ns$::io::CodedOutputStream::WriteVarint32ToArray("
-        "      _$name$_cached_byte_size_.load(std::memory_order_relaxed),\n"
-        "      target);\n"
-        "  target = "
-        "::$proto_ns$::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
-        "    this->$name$_, target);\n"
+        "{\n"
+        "  int byte_size = "
+        "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n"
+        "  if (byte_size > 0) {\n"
+        "    target = stream->WriteEnumPacked(\n"
+        "        $number$, $name$_, byte_size, target);\n"
+        "  }\n"
         "}\n");
   } else {
     format(
-        "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
-        "  $number$, this->$name$_, target);\n");
+        "for (const auto& x : this->$name$()) {\n"
+        "  stream->EnsureSpace(&target);\n"
+        "  target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n"
+        "      $number$, x, target);\n"
+        "}\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index b43d402..7226a7a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -59,7 +59,6 @@
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
@@ -100,7 +99,6 @@
   void GenerateCopyConstructorCode(io::Printer* printer) const {}
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
   void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 137e133..72d6fa2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -81,6 +81,7 @@
   } else {
     (*variables)["set_hasbit_io"] = "";
   }
+  (*variables)["annotate_accessor"] = "";
 
   // These variables are placeholders to pick out the beginning and ends of
   // identifiers for annotations (when doing so with existing variables would
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index c66bddc..470899e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -74,7 +74,8 @@
                           const Options& options)
       : descriptor_(descriptor), options_(options) {}
   virtual ~FieldGenerator();
-
+  virtual void GenerateSerializeWithCachedSizes(
+      io::Printer* printer) const final{};
   // Generate lines of code declaring members fields of the message class
   // needed to represent this field.  These are placed inside the message
   // class.
@@ -180,10 +181,6 @@
   virtual void GenerateMergeFromCodedStreamWithPacking(
       io::Printer* printer) const;
 
-  // Generate lines to serialize this field, which are placed within the
-  // message's SerializeWithCachedSizes() method.
-  virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0;
-
   // Generate lines to serialize this field directly to the array "target",
   // which are placed within the message's SerializeWithCachedSizesToArray()
   // method. This must also advance "target" past the written bytes.
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 63276de..3db64b4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -33,9 +33,11 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
+
 #include <map>
 #include <memory>
 #include <set>
+#include <unordered_set>
 #include <vector>
 
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
@@ -395,10 +397,6 @@
       "\n",
       CreateHeaderInclude(target_basename, file_));
 
-  if (options_.opensource_runtime) {
-    DoIncludeFile("net/proto2/public/stubs/common.h", false, printer);
-  }
-
   IncludeFile("net/proto2/io/public/coded_stream.h", printer);
   // TODO(gerbens) This is to include parse_context.h, we need a better way
   IncludeFile("net/proto2/public/extension_set.h", printer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 52ecd6c..fd518e0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -375,14 +375,6 @@
          file->options().cc_generic_services();
 }
 
-// Should we generate a separate, super-optimized code path for serializing to
-// flat arrays?  We don't do this in Lite mode because we'd rather reduce code
-// size.
-inline bool HasFastArraySerialization(const FileDescriptor* file,
-                                      const Options& options) {
-  return GetOptimizeFor(file, options) == FileOptions::SPEED;
-}
-
 inline bool IsProto2MessageSet(const Descriptor* descriptor,
                                const Options& options) {
   return !options.opensource_runtime &&
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 38f0584..0c4634b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -50,11 +50,6 @@
                          const Options& options) {
   SetCommonFieldVariables(descriptor, variables, options);
   (*variables)["type"] = ClassName(descriptor->message_type(), false);
-  (*variables)["stream_writer"] =
-      (*variables)["declared_type"] +
-      (HasFastArraySerialization(descriptor->message_type()->file(), options)
-           ? "MaybeToArray"
-           : "");
   (*variables)["full_name"] = descriptor->full_name();
 
   const FieldDescriptor* key =
@@ -130,11 +125,13 @@
   format(
       "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
       "$classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_map:$full_name$)\n"
       "  return $name$_.GetMap();\n"
       "}\n"
       "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
       "$classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
       "  return $name$_.MutableMap();\n"
       "}\n");
@@ -231,7 +228,7 @@
 }
 
 static void GenerateSerializationLoop(const Formatter& format, bool string_key,
-                                      bool string_value, bool to_array,
+                                      bool string_value,
                                       bool is_deterministic) {
   std::string ptr;
   if (is_deterministic) {
@@ -247,17 +244,10 @@
   }
   format.Indent();
 
-  if (to_array) {
-    format(
-        "target = $map_classname$::Funcs::SerializeToArray($number$, "
-        "$1$->first, $1$->second, target);\n",
-        ptr);
-  } else {
-    format(
-        "$map_classname$::Funcs::SerializeToCodedStream($number$, "
-        "$1$->first, $1$->second, output);\n",
-        ptr);
-  }
+  format(
+      "target = $map_classname$::Funcs::InternalSerialize($number$, "
+      "$1$->first, $1$->second, target, stream);\n",
+      ptr);
 
   if (string_key || string_value) {
     // ptr is either an actual pointer or an iterator, either way we can
@@ -269,18 +259,8 @@
   format("}\n");
 }
 
-void MapFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  GenerateSerializeWithCachedSizes(printer, false);
-}
-
 void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
-  GenerateSerializeWithCachedSizes(printer, true);
-}
-
-void MapFieldGenerator::GenerateSerializeWithCachedSizes(io::Printer* printer,
-                                                         bool to_array) const {
   Formatter format(printer, variables_);
   format("if (!this->$name$().empty()) {\n");
   format.Indent();
@@ -332,7 +312,7 @@
 
   format(
       "\n"
-      "if ($1$ &&\n"
+      "if (stream->IsSerializationDeterministic() &&\n"
       "    this->$name$().size() > 1) {\n"
       "  ::std::unique_ptr<SortItem[]> items(\n"
       "      new SortItem[this->$name$().size()]);\n"
@@ -344,14 +324,13 @@
       "      it != this->$name$().end(); ++it, ++n) {\n"
       "    items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
       "  }\n"
-      "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n",
-      to_array ? "false" : "output->IsSerializationDeterministic()");
+      "  ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
   format.Indent();
-  GenerateSerializationLoop(format, string_key, string_value, to_array, true);
+  GenerateSerializationLoop(format, string_key, string_value, true);
   format.Outdent();
   format("} else {\n");
   format.Indent();
-  GenerateSerializationLoop(format, string_key, string_value, to_array, false);
+  GenerateSerializationLoop(format, string_key, string_value, false);
   format.Outdent();
   format("}\n");
   format.Outdent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
index 95eecc0..45a70c4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -56,15 +56,10 @@
   void GenerateConstructorCode(io::Printer* printer) const {}
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
  private:
-  // A helper for GenerateSerializeWithCachedSizes{,ToArray}.
-  void GenerateSerializeWithCachedSizes(io::Printer* printer,
-                                        bool to_array) const;
-
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 3ef4665..8dba163 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -785,6 +785,7 @@
   if (field->options().weak()) {
     format(
         "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_accessor$"
         "  return _weak_field_map_.Has($number$);\n"
         "}\n");
     return;
@@ -800,6 +801,7 @@
                strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8));
     format(
         "inline bool $classname$::has_$name$() const {\n"
+        "$annotate_accessor$"
         "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
         "}\n");
   } else {
@@ -808,11 +810,13 @@
       if (IsLazy(field, options_)) {
         format(
             "inline bool $classname$::has_$name$() const {\n"
+            "$annotate_accessor$"
             "  return !$name$_.IsCleared();\n"
             "}\n");
       } else {
         format(
             "inline bool $classname$::has_$name$() const {\n"
+            "$annotate_accessor$"
             "  return this != internal_default_instance() "
             "&& $name$_ != nullptr;\n"
             "}\n");
@@ -847,9 +851,11 @@
   // _oneof_case_[index] against a constant everywhere).
   format(
       "inline bool $classname$::has_$name$() const {\n"
+      "$annotate_accessor$"
       "  return $oneof_name$_case() == k$field_name$;\n"
       "}\n"
       "inline void $classname$::set_has_$name$() {\n"
+      "$annotate_accessor$"
       "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
       "}\n");
 }
@@ -860,7 +866,9 @@
   if (is_inline) {
     format("inline ");
   }
-  format("void $classname$::clear_$name$() {\n");
+  format(
+      "void $classname$::clear_$name$() {\n"
+      "$annotate_accessor$");
 
   format.Indent();
 
@@ -909,6 +917,7 @@
     if (field->is_repeated()) {
       format(
           "inline int $classname$::$name$_size() const {\n"
+          "$annotate_accessor$"
           "  return $name$_.size();\n"
           "}\n");
     } else if (field->containing_oneof()) {
@@ -1285,24 +1294,16 @@
         "#else\n"
         "bool MergePartialFromCodedStream(\n"
         "    ::$proto_ns$::io::CodedInputStream* input) final;\n"
-        "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n");
+        "#endif  // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"
+        "$uint8$* InternalSerializeWithCachedSizesToArray(\n"
+        "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+        "const final;\n");
 
-    if (!options_.table_driven_serialization ||
-        descriptor_->options().message_set_wire_format()) {
-      format(
-          "void SerializeWithCachedSizes(\n"
-          "    ::$proto_ns$::io::CodedOutputStream* output) const final;\n");
-    }
     // DiscardUnknownFields() is implemented in message.cc using reflections. We
     // need to implement this function in generated code for messages.
     if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
       format("void DiscardUnknownFields()$ full_final$;\n");
     }
-    if (HasFastArraySerialization(descriptor_->file(), options_)) {
-      format(
-          "$uint8$* InternalSerializeWithCachedSizesToArray(\n"
-          "    $uint8$* target) const final;\n");
-    }
   }
 
   format(
@@ -2075,14 +2076,9 @@
     GenerateMergeFromCodedStream(printer);
     format("\n");
 
-    GenerateSerializeWithCachedSizes(printer);
+    GenerateSerializeWithCachedSizesToArray(printer);
     format("\n");
 
-    if (HasFastArraySerialization(descriptor_->file(), options_)) {
-      GenerateSerializeWithCachedSizesToArray(printer);
-      format("\n");
-    }
-
     GenerateByteSize(printer);
     format("\n");
 
@@ -3674,12 +3670,11 @@
 }
 
 void MessageGenerator::GenerateSerializeOneofFields(
-    io::Printer* printer, const std::vector<const FieldDescriptor*>& fields,
-    bool to_array) {
+    io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) {
   Formatter format(printer, variables_);
   GOOGLE_CHECK(!fields.empty());
   if (fields.size() == 1) {
-    GenerateSerializeOneField(printer, fields[0], to_array, -1);
+    GenerateSerializeOneField(printer, fields[0], -1);
     return;
   }
   // We have multiple mutually exclusive choices.  Emit a switch statement.
@@ -3689,12 +3684,8 @@
   for (auto field : fields) {
     format("case k$1$:\n", UnderscoresToCamelCase(field->name(), true));
     format.Indent();
-    if (to_array) {
-      field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(
-          printer);
-    } else {
-      field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
-    }
+    field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(
+        printer);
     format("break;\n");
     format.Outdent();
   }
@@ -3707,7 +3698,6 @@
 
 void MessageGenerator::GenerateSerializeOneField(io::Printer* printer,
                                                  const FieldDescriptor* field,
-                                                 bool to_array,
                                                  int cached_has_bits_index) {
   Formatter format(printer, variables_);
   if (!field->options().weak()) {
@@ -3735,12 +3725,7 @@
     have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field);
   }
 
-  if (to_array) {
-    field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(
-        printer);
-  } else {
-    field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
-  }
+  field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer);
 
   if (have_enclosing_if) {
     format.Outdent();
@@ -3750,57 +3735,15 @@
 }
 
 void MessageGenerator::GenerateSerializeOneExtensionRange(
-    io::Printer* printer, const Descriptor::ExtensionRange* range,
-    bool to_array) {
-  std::map<std::string, std::string> vars;
+    io::Printer* printer, const Descriptor::ExtensionRange* range) {
+  std::map<std::string, std::string> vars = variables_;
   vars["start"] = StrCat(range->start);
   vars["end"] = StrCat(range->end);
   Formatter format(printer, vars);
   format("// Extension range [$start$, $end$)\n");
-  if (to_array) {
-    format(
-        "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n"
-        "    $start$, $end$, target);\n\n");
-  } else {
-    format(
-        "_extensions_.SerializeWithCachedSizes($start$, $end$, output);\n"
-        "\n");
-  }
-}
-
-void MessageGenerator::GenerateSerializeWithCachedSizes(io::Printer* printer) {
-  Formatter format(printer, variables_);
-  if (descriptor_->options().message_set_wire_format()) {
-    // Special-case MessageSet.
-    format(
-        "void $classname$::SerializeWithCachedSizes(\n"
-        "    ::$proto_ns$::io::CodedOutputStream* output) const {\n"
-        "  _extensions_.SerializeMessageSetWithCachedSizes(output);\n");
-    std::map<std::string, std::string> vars;
-    SetUnknkownFieldsVariable(descriptor_, options_, &vars);
-    format.AddMap(vars);
-    format(
-        "  "
-        "::$proto_ns$::internal::SerializeUnknownMessageSetItems(\n"
-        "      $unknown_fields$, output);\n");
-    format("}\n");
-    return;
-  }
-  if (options_.table_driven_serialization) return;
-
   format(
-      "void $classname$::SerializeWithCachedSizes(\n"
-      "    ::$proto_ns$::io::CodedOutputStream* output) const {\n");
-  format.Indent();
-
-  format("// @@protoc_insertion_point(serialize_start:$full_name$)\n");
-
-  GenerateSerializeWithCachedSizesBody(printer, false);
-
-  format("// @@protoc_insertion_point(serialize_end:$full_name$)\n");
-
-  format.Outdent();
-  format("}\n");
+      "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n"
+      "    $start$, $end$, target, stream);\n\n");
 }
 
 void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
@@ -3810,17 +3753,17 @@
     // Special-case MessageSet.
     format(
         "$uint8$* $classname$::InternalSerializeWithCachedSizesToArray(\n"
-        "    $uint8$* target) const {\n"
+        "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+        "const {\n"
         "  target = _extensions_."
-        "InternalSerializeMessageSetWithCachedSizesToArray(target);\n");
-    GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
+        "InternalSerializeMessageSetWithCachedSizesToArray(target, stream);\n");
     std::map<std::string, std::string> vars;
     SetUnknkownFieldsVariable(descriptor_, options_, &vars);
     format.AddMap(vars);
     format(
-        "  target = ::$proto_ns$::internal::WireFormat::\n"
-        "             SerializeUnknownMessageSetItemsToArray(\n"
-        "               $unknown_fields$, target);\n");
+        "  target = ::$proto_ns$::internal::"
+        "InternalSerializeUnknownMessageSetItemsToArray(\n"
+        "               $unknown_fields$, target, stream);\n");
     format(
         "  return target;\n"
         "}\n");
@@ -3829,12 +3772,13 @@
 
   format(
       "$uint8$* $classname$::InternalSerializeWithCachedSizesToArray(\n"
-      "    $uint8$* target) const {\n");
+      "    $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+      "const {\n");
   format.Indent();
 
   format("// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n");
 
-  GenerateSerializeWithCachedSizesBody(printer, true);
+  GenerateSerializeWithCachedSizesBody(printer);
 
   format("// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n");
 
@@ -3845,7 +3789,7 @@
 }
 
 void MessageGenerator::GenerateSerializeWithCachedSizesBody(
-    io::Printer* printer, bool to_array) {
+    io::Printer* printer) {
   Formatter format(printer, variables_);
   // If there are multiple fields in a row from the same oneof then we
   // coalesce them and emit a switch statement.  This is more efficient
@@ -3854,11 +3798,9 @@
   // compiler's emitted code might check has_y() even when has_x() is true.
   class LazySerializerEmitter {
    public:
-    LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer,
-                          bool to_array)
+    LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer)
         : mg_(mg),
           format_(printer),
-          to_array_(to_array),
           eager_(!HasFieldPresence(mg->descriptor_->file())),
           cached_has_bit_index_(-1) {}
 
@@ -3888,7 +3830,7 @@
           }
         }
 
-        mg_->GenerateSerializeOneField(format_.printer(), field, to_array_,
+        mg_->GenerateSerializeOneField(format_.printer(), field,
                                        cached_has_bit_index_);
       } else {
         v_.push_back(field);
@@ -3897,7 +3839,7 @@
 
     void Flush() {
       if (!v_.empty()) {
-        mg_->GenerateSerializeOneofFields(format_.printer(), v_, to_array_);
+        mg_->GenerateSerializeOneofFields(format_.printer(), v_);
         v_.clear();
       }
     }
@@ -3912,7 +3854,6 @@
 
     MessageGenerator* mg_;
     Formatter format_;
-    const bool to_array_;
     const bool eager_;
     std::vector<const FieldDescriptor*> v_;
 
@@ -3944,7 +3885,7 @@
 
   // Merge the fields and the extension ranges, both sorted by field number.
   {
-    LazySerializerEmitter e(this, printer, to_array);
+    LazySerializerEmitter e(this, printer);
     const FieldDescriptor* last_weak_field = nullptr;
     int i, j;
     for (i = 0, j = 0;
@@ -3969,8 +3910,7 @@
           last_weak_field = nullptr;
         }
         e.Flush();
-        GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++],
-                                           to_array);
+        GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
       }
     }
     if (last_weak_field != nullptr) {
@@ -3981,27 +3921,21 @@
   std::map<std::string, std::string> vars;
   SetUnknkownFieldsVariable(descriptor_, options_, &vars);
   format.AddMap(vars);
+  format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
+  format.Indent();
   if (UseUnknownFieldSet(descriptor_->file(), options_)) {
-    format("if ($have_unknown_fields$) {\n");
-    format.Indent();
-    if (to_array) {
-      format(
-          "target = "
-          "::$proto_ns$::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
-          "    $unknown_fields$, target);\n");
-    } else {
-      format(
-          "::$proto_ns$::internal::WireFormat::SerializeUnknownFields(\n"
-          "    $unknown_fields$, output);\n");
-    }
-    format.Outdent();
-
-    format("}\n");
+    format(
+        "target = "
+        "::$proto_ns$::internal::WireFormat::"
+        "InternalSerializeUnknownFieldsToArray(\n"
+        "    $unknown_fields$, target, stream);\n");
   } else {
     format(
-        "output->WriteRaw($unknown_fields$.data(),\n"
-        "                 static_cast<int>($unknown_fields$.size()));\n");
+        "target = stream->WriteRaw($unknown_fields$.data(),\n"
+        "    static_cast<int>($unknown_fields$.size()), target);\n");
   }
+  format.Outdent();
+  format("}\n");
 }
 
 std::vector<uint32> MessageGenerator::RequiredFieldsBitMask() const {
@@ -4112,18 +4046,6 @@
   std::map<std::string, std::string> vars;
   SetUnknkownFieldsVariable(descriptor_, options_, &vars);
   format.AddMap(vars);
-  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
-    format(
-        "if ($have_unknown_fields$) {\n"
-        "  total_size +=\n"
-        "    ::$proto_ns$::internal::WireFormat::ComputeUnknownFieldsSize(\n"
-        "      $unknown_fields$);\n"
-        "}\n");
-  } else {
-    format(
-        "total_size += $unknown_fields$.size();\n"
-        "\n");
-  }
 
   // Handle required fields (if any).  We expect all of them to be
   // present, so emit one conditional that checks for that.  If they are all
@@ -4302,6 +4224,19 @@
     format("total_size += _weak_field_map_.ByteSizeLong();\n");
   }
 
+  format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
+  if (UseUnknownFieldSet(descriptor_->file(), options_)) {
+    // We go out of our way to put the computation of the uncommon path of
+    // unknown fields in tail position. This allows for better code generation
+    // of this function for simple protos.
+    format(
+        "  return ::$proto_ns$::internal::ComputeUnknownFieldsSize(\n"
+        "      _internal_metadata_, total_size, &_cached_size_);\n");
+  } else {
+    format("  total_size += $unknown_fields$.size();\n");
+  }
+  format("}\n");
+
   // We update _cached_size_ even though this is a const method.  Because
   // const methods might be called concurrently this needs to be atomic
   // operations or the program is undefined.  In practice, since any concurrent
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index f7206b9..bc4febf 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -141,8 +141,7 @@
   void GenerateMergeFromCodedStream(io::Printer* printer);
   void GenerateSerializeWithCachedSizes(io::Printer* printer);
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
-  void GenerateSerializeWithCachedSizesBody(io::Printer* printer,
-                                            bool to_array);
+  void GenerateSerializeWithCachedSizesBody(io::Printer* printer);
   void GenerateByteSize(io::Printer* printer);
   void GenerateMergeFrom(io::Printer* printer);
   void GenerateCopyFrom(io::Printer* printer);
@@ -155,16 +154,14 @@
   //   cached_has_bits = _has_bits_[cached_has_bit_index]
   // for cached_has_bit_index >= 0
   void GenerateSerializeOneField(io::Printer* printer,
-                                 const FieldDescriptor* field, bool unbounded,
+                                 const FieldDescriptor* field,
                                  int cached_has_bits_index);
   // Generate a switch statement to serialize 2+ fields from the same oneof.
   // Or, if fields.size() == 1, just call GenerateSerializeOneField().
   void GenerateSerializeOneofFields(
-      io::Printer* printer, const std::vector<const FieldDescriptor*>& fields,
-      bool to_array);
+      io::Printer* printer, const std::vector<const FieldDescriptor*>& fields);
   void GenerateSerializeOneExtensionRange(
-      io::Printer* printer, const Descriptor::ExtensionRange* range,
-      bool unbounded);
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
 
   // Generates has_foo() functions and variables for singular field has-bits.
   void GenerateSingularFieldHasBits(const FieldDescriptor* field,
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 3007cc2..7d621e0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -67,11 +67,6 @@
           ? ("  " + ReferenceFunctionName(descriptor->message_type(), options) +
              "();\n")
           : "";
-  (*variables)["stream_writer"] =
-      (*variables)["declared_type"] +
-      (HasFastArraySerialization(descriptor->message_type()->file(), options)
-           ? "MaybeToArray"
-           : "");
   // NOTE: Escaped here to unblock proto1->proto2 migration.
   // TODO(liujisi): Extend this to apply for other conflicting methods.
   (*variables)["release_name"] =
@@ -130,6 +125,7 @@
     format(
         "void $classname$::unsafe_arena_set_allocated_$name$(\n"
         "    $type$* $name$) {\n"
+        "$annotate_accessor$"
         // If we're not on an arena, free whatever we were holding before.
         // (If we are on arena, we can just forget the earlier pointer.)
         "  if (GetArenaNoVirtual() == nullptr) {\n"
@@ -152,6 +148,7 @@
   Formatter format(printer, variables_);
   format(
       "inline const $type$& $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  const $type$* p = $casted_member$;\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return p != nullptr ? *p : *reinterpret_cast<const $type$*>(\n"
@@ -160,6 +157,7 @@
 
   format(
       "inline $type$* $classname$::$release_name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_release:$full_name$)\n"
       "$type_reference_function$"
       "  $clear_hasbit$\n"
@@ -178,6 +176,7 @@
   if (SupportsArenas(descriptor_)) {
     format(
         "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+        "$annotate_accessor$"
         "  // "
         "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
         "$type_reference_function$"
@@ -190,6 +189,7 @@
 
   format(
       "inline $type$* $classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  $set_hasbit$\n"
       "  if ($name$_ == nullptr) {\n"
       "    auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n");
@@ -208,6 +208,7 @@
   // the slow fallback function.
   format(
       "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$annotate_accessor$"
       "  ::$proto_ns$::Arena* message_arena = GetArenaNoVirtual();\n");
   format("  if (message_arena == nullptr) {\n");
   if (IsCrossFileMessage(descriptor_)) {
@@ -442,21 +443,14 @@
   }
 }
 
-void MessageFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  format(
-      "::$proto_ns$::internal::WireFormatLite::Write$stream_writer$(\n"
-      "  $number$, _Internal::$name$(this), output);\n");
-}
-
 void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   format(
+      "stream->EnsureSpace(&target);\n"
       "target = ::$proto_ns$::internal::WireFormatLite::\n"
       "  InternalWrite$declared_type$ToArray(\n"
-      "    $number$, _Internal::$name$(this), target);\n");
+      "    $number$, _Internal::$name$(this), target, stream);\n");
 }
 
 void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const {
@@ -483,6 +477,7 @@
   Formatter format(printer, variables_);
   format(
       "void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$annotate_accessor$"
       "  ::$proto_ns$::Arena* message_arena = GetArenaNoVirtual();\n"
       "  clear_$oneof_name$();\n"
       "  if ($name$) {\n");
@@ -518,6 +513,7 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$* $classname$::$release_name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_release:$full_name$)\n"
       "  if (has_$name$()) {\n"
       "    clear_has_$oneof_name$();\n"
@@ -538,6 +534,7 @@
 
   format(
       "inline const $type$& $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return has_$name$()\n"
       "      ? *$field_member$\n"
@@ -547,6 +544,7 @@
   if (SupportsArenas(descriptor_)) {
     format(
         "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_unsafe_arena_release"
         ":$full_name$)\n"
         "  if (has_$name$()) {\n"
@@ -560,6 +558,7 @@
         "}\n"
         "inline void $classname$::unsafe_arena_set_allocated_$name$"
         "($type$* $name$) {\n"
+        "$annotate_accessor$"
         // We rely on the oneof clear method to free the earlier contents of
         // this oneof. We can directly use the pointer we're given to set the
         // new value.
@@ -575,6 +574,7 @@
 
   format(
       "inline $type$* $classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
@@ -659,6 +659,7 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$* $classname$::mutable_$name$(int index) {\n"
+      "$annotate_accessor$"
       // TODO(dlj): move insertion points
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "$type_reference_function$"
@@ -666,6 +667,7 @@
       "}\n"
       "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n"
       "$classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
       "$type_reference_function$"
       "  return &$name$_;\n"
@@ -674,6 +676,7 @@
   if (options_.safe_boundary_check) {
     format(
         "inline const $type$& $classname$::$name$(int index) const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  return $name$_.InternalCheckedGet(index,\n"
         "      *reinterpret_cast<const $type$*>(&$type_default_instance$));\n"
@@ -681,6 +684,7 @@
   } else {
     format(
         "inline const $type$& $classname$::$name$(int index) const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "$type_reference_function$"
         "  return $name$_.Get(index);\n"
@@ -689,6 +693,7 @@
 
   format(
       "inline $type$* $classname$::add_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
       "  return $name$_.Add();\n"
       "}\n");
@@ -696,6 +701,7 @@
   format(
       "inline const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
       "$classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_list:$full_name$)\n"
       "$type_reference_function$"
       "  return $name$_;\n"
@@ -761,37 +767,32 @@
   }
 }
 
-void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  format(
-      "for (unsigned int i = 0,\n"
-      "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
-      "  ::$proto_ns$::internal::WireFormatLite::Write$stream_writer$(\n"
-      "    $number$,\n");
-  if (implicit_weak_field_) {
-    format(
-        "    CastToBase($name$_).Get<"
-        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>("
-        "static_cast<int>(i)),\n");
-  } else {
-    format("    this->$name$(static_cast<int>(i)),\n");
-  }
-  format(
-      "    output);\n"
-      "}\n");
-}
-
 void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format(
-      "for (unsigned int i = 0,\n"
-      "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
-      "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-      "    InternalWrite$declared_type$ToArray(\n"
-      "      $number$, this->$name$(static_cast<int>(i)), target);\n"
-      "}\n");
+  if (implicit_weak_field_) {
+    format(
+        "for (unsigned int i = 0,\n"
+        "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) "
+        "{\n"
+        "  stream->EnsureSpace(&target);\n"
+        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "    InternalWrite$declared_type$ToArray(\n"
+        "      $number$,\n"
+        "    CastToBase($name$_).Get<"
+        "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>("
+        "static_cast<int>(i)), target, stream);\n"
+        "}\n");
+  } else {
+    format(
+        "for (auto it = this->$name$().pointer_begin(),\n"
+        "          end = this->$name$().pointer_end(); it < end; ++it) {\n"
+        "  stream->EnsureSpace(&target);\n"
+        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
+        "    InternalWrite$declared_type$ToArray($number$, **it, target, "
+        "stream);\n"
+        "}\n");
+  }
 }
 
 void RepeatedMessageFieldGenerator::GenerateByteSize(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index eed8e4f..88b01e0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -67,7 +67,6 @@
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
@@ -118,7 +117,6 @@
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateCopyConstructorCode(io::Printer* printer) const {}
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 6616e4b..d8fe3a7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -61,6 +61,7 @@
   bool lite_implicit_weak_fields = false;
   bool bootstrap = false;
   bool opensource_runtime = false;
+  bool annotate_accessor = false;
   std::string runtime_include_base;
   int num_cc_files = 0;
   std::string annotation_pragma_name;
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 164bb1c..62dcdcc 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -146,10 +146,12 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
       "inline void $classname$::set_$name$($type$ value) {\n"
+      "$annotate_accessor$"
       "  $set_hasbit$\n"
       "  $name$_ = value;\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
@@ -194,18 +196,11 @@
       "       input, &$name$_)));\n");
 }
 
-void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  format(
-      "::$proto_ns$::internal::WireFormatLite::Write$declared_type$("
-      "$number$, this->$name$(), output);\n");
-}
-
 void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   format(
+      "stream->EnsureSpace(&target);\n"
       "target = "
       "::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray("
       "$number$, this->$name$(), target);\n");
@@ -239,6 +234,7 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  if (has_$name$()) {\n"
       "    return $field_member$;\n"
@@ -246,6 +242,7 @@
       "  return $default$;\n"
       "}\n"
       "inline void $classname$::set_$name$($type$ value) {\n"
+      "$annotate_accessor$"
       "  if (!has_$name$()) {\n"
       "    clear_$oneof_name$();\n"
       "    set_has_$name$();\n"
@@ -331,24 +328,29 @@
   Formatter format(printer, variables_);
   format(
       "inline $type$ $classname$::$name$(int index) const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  return $name$_.Get(index);\n"
       "}\n"
       "inline void $classname$::set_$name$(int index, $type$ value) {\n"
+      "$annotate_accessor$"
       "  $name$_.Set(index, value);\n"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "}\n"
       "inline void $classname$::add_$name$($type$ value) {\n"
+      "$annotate_accessor$"
       "  $name$_.Add(value);\n"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
       "}\n"
       "inline const ::$proto_ns$::RepeatedField< $type$ >&\n"
       "$classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_list:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
       "inline ::$proto_ns$::RepeatedField< $type$ >*\n"
       "$classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
       "  return &$name$_;\n"
       "}\n");
@@ -403,72 +405,33 @@
       "       input, this->mutable_$name$())));\n");
 }
 
-void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  bool array_written = false;
-  if (descriptor_->is_packed()) {
-    // Write the tag and the size.
-    format(
-        "if (this->$name$_size() > 0) {\n"
-        "  ::$proto_ns$::internal::WireFormatLite::WriteTag("
-        "$number$, "
-        "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
-        "output);\n"
-        "  output->WriteVarint32(_$name$_cached_byte_size_.load(\n"
-        "      std::memory_order_relaxed));\n");
-
-    if (FixedSize(descriptor_->type()) > 0) {
-      // TODO(ckennelly): Use RepeatedField<T>::unsafe_data() via
-      // WireFormatLite to access the contents of this->$name$_ to save a branch
-      // here.
-      format(
-          "  "
-          "::$proto_ns$::internal::WireFormatLite::Write$declared_type$Array(\n"
-          "    this->$name$().data(), this->$name$_size(), output);\n");
-      array_written = true;  // Wrote array all at once
-    }
-    format("}\n");
-  }
-  if (!array_written) {
-    format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
-    if (descriptor_->is_packed()) {
-      format(
-          "  "
-          "::$proto_ns$::internal::WireFormatLite::Write$declared_type$NoTag(\n"
-          "    this->$name$(i), output);\n");
-    } else {
-      format(
-          "  ::$proto_ns$::internal::WireFormatLite::Write$declared_type$(\n"
-          "    $number$, this->$name$(i), output);\n");
-    }
-    format("}\n");
-  }
-}
-
 void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
   if (descriptor_->is_packed()) {
-    // Write the tag and the size.
-    format(
-        "if (this->$name$_size() > 0) {\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::WriteTagToArray(\n"
-        "    $number$,\n"
-        "    "
-        "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
-        "    target);\n"
-        "  target = "
-        "::$proto_ns$::io::CodedOutputStream::WriteVarint32ToArray(\n"
-        "      _$name$_cached_byte_size_.load(std::memory_order_relaxed),\n"
-        "       target);\n"
-        "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "    Write$declared_type$NoTagToArray(this->$name$_, target);\n"
-        "}\n");
+    if (FixedSize(descriptor_->type()) > 0) {
+      format(
+          "if (this->$name$_size() > 0) {\n"
+          "  target = stream->WriteFixedPacked($number$, $name$_, target);\n"
+          "}\n");
+    } else {
+      format(
+          "{\n"
+          "  int byte_size = "
+          "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n"
+          "  if (byte_size > 0) {\n"
+          "    target = stream->Write$declared_type$Packed(\n"
+          "        $number$, $name$_, byte_size, target);\n"
+          "  }\n"
+          "}\n");
+    }
   } else {
     format(
-        "target = ::$proto_ns$::internal::WireFormatLite::\n"
-        "  Write$declared_type$ToArray($number$, this->$name$_, target);\n");
+        "for (const auto& x : this->$name$()) {\n"
+        "  stream->EnsureSpace(&target);\n"
+        "  target = ::$proto_ns$::internal::WireFormatLite::"
+        "Write$declared_type$ToArray($number$, x, target);\n"
+        "}\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 77389aa..18b67ad 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -60,7 +60,6 @@
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
@@ -102,7 +101,6 @@
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
   void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 1f14b16..455ac6e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -211,21 +211,25 @@
   if (SupportsArenas(descriptor_)) {
     format(
         "inline const std::string& $classname$::$name$() const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  return $name$_.Get();\n"
         "}\n"
         "inline void $classname$::set_$name$(const std::string& value) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.Set$lite$($default_variable$, value, GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.Set$lite$(\n"
         "    $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(const char* value) {\n"
+        "$annotate_accessor$"
         "  $null_check$"
         "  $set_hasbit$\n"
         "  $name$_.Set$lite$($default_variable$, $string_piece$(value),\n"
@@ -235,6 +239,7 @@
     if (!options_.opensource_runtime) {
       format(
           "inline void $classname$::set_$name$(::StringPiece value) {\n"
+          "$annotate_accessor$"
           "  $set_hasbit$\n"
           "  $name$_.Set$lite$($default_variable$, value, "
           "GetArenaNoVirtual());\n"
@@ -245,6 +250,7 @@
         "inline "
         "void $classname$::set_$name$(const $pointer_type$* value,\n"
         "    size_t size) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.Set$lite$($default_variable$, $string_piece$(\n"
         "      reinterpret_cast<const char*>(value), size), "
@@ -252,11 +258,13 @@
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::mutable_$name$() {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n");
 
     if (HasFieldPresence(descriptor_->file())) {
@@ -277,6 +285,7 @@
     format(
         "}\n"
         "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+        "$annotate_accessor$"
         "  if ($name$ != nullptr) {\n"
         "    $set_hasbit$\n"
         "  } else {\n"
@@ -289,6 +298,7 @@
     if (options_.opensource_runtime) {
       format(
           "inline std::string* $classname$::unsafe_arena_release_$name$() {\n"
+          "$annotate_accessor$"
           "  // "
           "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
           "  $DCHK$(GetArenaNoVirtual() != nullptr);\n"
@@ -297,6 +307,7 @@
           "      GetArenaNoVirtual());\n"
           "}\n"
           "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+          "$annotate_accessor$"
           "    std::string* $name$) {\n"
           "  $DCHK$(GetArenaNoVirtual() != nullptr);\n"
           "  if ($name$ != nullptr) {\n"
@@ -314,21 +325,25 @@
     // No-arena case.
     format(
         "inline const std::string& $classname$::$name$() const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  return $name$_.GetNoArena();\n"
         "}\n"
         "inline void $classname$::set_$name$(const std::string& value) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.SetNoArena($default_variable$, value);\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.SetNoArena(\n"
         "    $default_variable$, ::std::move(value));\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(const char* value) {\n"
+        "$annotate_accessor$"
         "  $null_check$"
         "  $set_hasbit$\n"
         "  $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
@@ -337,6 +352,7 @@
     if (!options_.opensource_runtime) {
       format(
           "inline void $classname$::set_$name$(::StringPiece value) {\n"
+          "$annotate_accessor$"
           "  $set_hasbit$\n"
           "  $name$_.SetNoArena($default_variable$, value);\n"
           "  // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
@@ -346,17 +362,20 @@
         "inline "
         "void $classname$::set_$name$(const $pointer_type$* value, "
         "size_t size) {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  $name$_.SetNoArena($default_variable$,\n"
         "      $string_piece$(reinterpret_cast<const char*>(value), size));\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::mutable_$name$() {\n"
+        "$annotate_accessor$"
         "  $set_hasbit$\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  return $name$_.MutableNoArena($default_variable$);\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n");
 
     if (HasFieldPresence(descriptor_->file())) {
@@ -375,6 +394,7 @@
     format(
         "}\n"
         "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+        "$annotate_accessor$"
         "  if ($name$ != nullptr) {\n"
         "    $set_hasbit$\n"
         "  } else {\n"
@@ -612,21 +632,6 @@
   return !lite_ && !inlined_ && !options_.opensource_runtime;
 }
 
-void StringFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(
-        descriptor_, options_, false,
-        "this->$name$().data(), static_cast<int>(this->$name$().length()),\n",
-        format);
-  }
-  format(
-      "::$proto_ns$::internal::WireFormatLite::Write$declared_type$"
-      "MaybeAliased(\n"
-      "  $number$, this->$name$(), output);\n");
-}
-
 void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
@@ -637,8 +642,7 @@
         format);
   }
   format(
-      "target =\n"
-      "  ::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray(\n"
+      "target = stream->Write$declared_type$MaybeAliased(\n"
       "    $number$, this->$name$(), target);\n");
 }
 
@@ -672,6 +676,7 @@
   if (SupportsArenas(descriptor_)) {
     format(
         "inline const std::string& $classname$::$name$() const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "    return $field_member$.Get();\n"
@@ -679,6 +684,7 @@
         "  return *$default_variable$;\n"
         "}\n"
         "inline void $classname$::set_$name$(const std::string& value) {\n"
+        "$annotate_accessor$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
@@ -689,6 +695,7 @@
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
@@ -700,6 +707,7 @@
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(const char* value) {\n"
+        "$annotate_accessor$"
         "  $null_check$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
@@ -713,6 +721,7 @@
     if (!options_.opensource_runtime) {
       format(
           "inline void $classname$::set_$name$(::StringPiece value) {\n"
+          "$annotate_accessor$"
           "  if (!has_$name$()) {\n"
           "    clear_$oneof_name$();\n"
           "    set_has_$name$();\n"
@@ -727,6 +736,7 @@
         "inline "
         "void $classname$::set_$name$(const $pointer_type$* value,\n"
         "                             size_t size) {\n"
+        "$annotate_accessor$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
@@ -739,6 +749,7 @@
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::mutable_$name$() {\n"
+        "$annotate_accessor$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
@@ -749,6 +760,7 @@
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "    clear_has_$oneof_name$();\n"
@@ -759,6 +771,7 @@
         "  }\n"
         "}\n"
         "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+        "$annotate_accessor$"
         "  if (has_$oneof_name$()) {\n"
         "    clear_$oneof_name$();\n"
         "  }\n"
@@ -771,6 +784,7 @@
     if (options_.opensource_runtime) {
       format(
           "inline std::string* $classname$::unsafe_arena_release_$name$() {\n"
+          "$annotate_accessor$"
           "  // "
           "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
           "  $DCHK$(GetArenaNoVirtual() != nullptr);\n"
@@ -784,6 +798,7 @@
           "}\n"
           "inline void $classname$::unsafe_arena_set_allocated_$name$("
           "std::string* $name$) {\n"
+          "$annotate_accessor$"
           "  $DCHK$(GetArenaNoVirtual() != nullptr);\n"
           "  if (!has_$name$()) {\n"
           "    $field_member$.UnsafeSetDefault($default_variable$);\n"
@@ -802,6 +817,7 @@
     // No-arena case.
     format(
         "inline const std::string& $classname$::$name$() const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "    return $field_member$.GetNoArena();\n"
@@ -809,6 +825,7 @@
         "  return *$default_variable$;\n"
         "}\n"
         "inline void $classname$::set_$name$(const std::string& value) {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
@@ -819,6 +836,7 @@
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(std::string&& value) {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
@@ -829,6 +847,7 @@
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "inline void $classname$::set_$name$(const char* value) {\n"
+        "$annotate_accessor$"
         "  $null_check$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
@@ -842,6 +861,7 @@
     if (!options_.opensource_runtime) {
       format(
           "inline void $classname$::set_$name$(::StringPiece value) {\n"
+          "$annotate_accessor$"
           "  if (!has_$name$()) {\n"
           "    clear_$oneof_name$();\n"
           "    set_has_$name$();\n"
@@ -855,6 +875,7 @@
         "inline "
         "void $classname$::set_$name$(const $pointer_type$* value, size_t "
         "size) {\n"
+        "$annotate_accessor$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
@@ -865,6 +886,7 @@
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
         "inline std::string* $classname$::mutable_$name$() {\n"
+        "$annotate_accessor$"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
@@ -874,6 +896,7 @@
         "  return $field_member$.MutableNoArena($default_variable$);\n"
         "}\n"
         "inline std::string* $classname$::$release_name$() {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "    clear_has_$oneof_name$();\n"
@@ -883,6 +906,7 @@
         "  }\n"
         "}\n"
         "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
+        "$annotate_accessor$"
         "  if (has_$oneof_name$()) {\n"
         "    clear_$oneof_name$();\n"
         "  }\n"
@@ -1056,6 +1080,7 @@
   if (options_.safe_boundary_check) {
     format(
         "inline const std::string& $classname$::$name$(int index) const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  return $name$_.InternalCheckedGet(\n"
         "      index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n"
@@ -1063,26 +1088,31 @@
   } else {
     format(
         "inline const std::string& $classname$::$name$(int index) const {\n"
+        "$annotate_accessor$"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  return $name$_.Get(index);\n"
         "}\n");
   }
   format(
       "inline std::string* $classname$::mutable_$name$(int index) {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_.Mutable(index);\n"
       "}\n"
       "inline void $classname$::set_$name$(int index, const std::string& "
       "value) "
       "{\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  $name$_.Mutable(index)->assign(value);\n"
       "}\n"
       "inline void $classname$::set_$name$(int index, std::string&& value) {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_set:$full_name$)\n"
       "  $name$_.Mutable(index)->assign(std::move(value));\n"
       "}\n"
       "inline void $classname$::set_$name$(int index, const char* value) {\n"
+      "$annotate_accessor$"
       "  $null_check$"
       "  $name$_.Mutable(index)->assign(value);\n"
       "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
@@ -1091,6 +1121,7 @@
     format(
         "inline void "
         "$classname$::set_$name$(int index, StringPiece value) {\n"
+        "$annotate_accessor$"
         "  $name$_.Mutable(index)->assign(value.data(), value.size());\n"
         "  // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
         "}\n");
@@ -1099,23 +1130,28 @@
       "inline void "
       "$classname$::set_$name$"
       "(int index, const $pointer_type$* value, size_t size) {\n"
+      "$annotate_accessor$"
       "  $name$_.Mutable(index)->assign(\n"
       "    reinterpret_cast<const char*>(value), size);\n"
       "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
       "}\n"
       "inline std::string* $classname$::add_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
       "  return $name$_.Add();\n"
       "}\n"
       "inline void $classname$::add_$name$(const std::string& value) {\n"
+      "$annotate_accessor$"
       "  $name$_.Add()->assign(value);\n"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
       "}\n"
       "inline void $classname$::add_$name$(std::string&& value) {\n"
+      "$annotate_accessor$"
       "  $name$_.Add(std::move(value));\n"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
       "}\n"
       "inline void $classname$::add_$name$(const char* value) {\n"
+      "$annotate_accessor$"
       "  $null_check$"
       "  $name$_.Add()->assign(value);\n"
       "  // @@protoc_insertion_point(field_add_char:$full_name$)\n"
@@ -1123,6 +1159,7 @@
   if (!options_.opensource_runtime) {
     format(
         "inline void $classname$::add_$name$(StringPiece value) {\n"
+        "$annotate_accessor$"
         "  $name$_.Add()->assign(value.data(), value.size());\n"
         "  // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n"
         "}\n");
@@ -1130,16 +1167,19 @@
   format(
       "inline void "
       "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
+      "$annotate_accessor$"
       "  $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
       "  // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
       "}\n"
       "inline const ::$proto_ns$::RepeatedPtrField<std::string>&\n"
       "$classname$::$name$() const {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_list:$full_name$)\n"
       "  return $name$_;\n"
       "}\n"
       "inline ::$proto_ns$::RepeatedPtrField<std::string>*\n"
       "$classname$::mutable_$name$() {\n"
+      "$annotate_accessor$"
       "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
       "  return &$name$_;\n"
       "}\n");
@@ -1189,39 +1229,23 @@
   }
 }
 
-void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizes(
-    io::Printer* printer) const {
-  Formatter format(printer, variables_);
-  format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
-  format.Indent();
-  if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(
-        descriptor_, options_, false,
-        "this->$name$(i).data(), static_cast<int>(this->$name$(i).length()),\n",
-        format);
-  }
-  format.Outdent();
-  format(
-      "  ::$proto_ns$::internal::WireFormatLite::Write$declared_type$(\n"
-      "    $number$, this->$name$(i), output);\n"
-      "}\n");
-}
-
 void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
     io::Printer* printer) const {
   Formatter format(printer, variables_);
-  format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n");
+  format(
+      "for (auto it = this->$name$().pointer_begin(),\n"
+      "          end = this->$name$().pointer_end(); it < end; ++it) {\n"
+      "  const auto& s = **it;\n");
+  // format("for (const std::string& s : this->$name$()) {\n");
   format.Indent();
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
-    GenerateUtf8CheckCodeForString(
-        descriptor_, options_, false,
-        "this->$name$(i).data(), static_cast<int>(this->$name$(i).length()),\n",
-        format);
+    GenerateUtf8CheckCodeForString(descriptor_, options_, false,
+                                   "s.data(), static_cast<int>(s.length()),\n",
+                                   format);
   }
   format.Outdent();
   format(
-      "  target = ::$proto_ns$::internal::WireFormatLite::\n"
-      "    Write$declared_type$ToArray($number$, this->$name$(i), target);\n"
+      "  target = stream->Write$declared_type$($number$, s, target);\n"
       "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 3a1de55..b01c9a0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -66,7 +66,6 @@
   bool GenerateArenaDestructorCode(io::Printer* printer) const;
   void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
   uint32 CalculateFieldTag() const;
@@ -120,7 +119,6 @@
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateCopyConstructorCode(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
-  void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index e895391..5bc847c 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -521,7 +521,7 @@
         // we want the mutable code to be independent from the immutable code
         // at compile time. It is required to implement dual-compile for
         // mutable and immutable API in blaze.
-        "  java.lang.Class immutableClass = java.lang.Class.forName(\n"
+        "  java.lang.Class<?> immutableClass = java.lang.Class.forName(\n"
         "      \"$immutable_classname$\");\n"
         "} catch (java.lang.ClassNotFoundException e) {\n",
         "immutable_classname", name_resolver_->GetImmutableClassName(file_));
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 23ac4f2..dcfaca3 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -436,47 +435,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Version::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.Version)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional int32 major = 1;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(1, this->major(), output);
-  }
-
-  // optional int32 minor = 2;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->minor(), output);
-  }
-
-  // optional int32 patch = 3;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(3, this->patch(), output);
-  }
-
-  // optional string suffix = 4;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->suffix().data(), static_cast<int>(this->suffix().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.Version.suffix");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      4, this->suffix(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.Version)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Version::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.Version)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -484,16 +444,19 @@
   cached_has_bits = _has_bits_[0];
   // optional int32 major = 1;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->major(), target);
   }
 
   // optional int32 minor = 2;
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->minor(), target);
   }
 
   // optional int32 patch = 3;
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->patch(), target);
   }
 
@@ -503,14 +466,13 @@
       this->suffix().data(), static_cast<int>(this->suffix().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.Version.suffix");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         4, this->suffix(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.Version)
   return target;
@@ -520,11 +482,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.Version)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -560,6 +517,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -888,69 +849,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void CodeGeneratorRequest::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorRequest)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated string file_to_generate = 1;
-  for (int i = 0, n = this->file_to_generate_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->file_to_generate(i).data(), static_cast<int>(this->file_to_generate(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      1, this->file_to_generate(i), output);
-  }
-
-  cached_has_bits = _has_bits_[0];
-  // optional string parameter = 2;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->parameter().data(), static_cast<int>(this->parameter().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorRequest.parameter");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->parameter(), output);
-  }
-
-  // optional .google.protobuf.compiler.Version compiler_version = 3;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, _Internal::compiler_version(this), output);
-  }
-
-  // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->proto_file_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      15,
-      this->proto_file(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorRequest)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* CodeGeneratorRequest::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated string file_to_generate = 1;
-  for (int i = 0, n = this->file_to_generate_size(); i < n; i++) {
+  for (auto it = this->file_to_generate().pointer_begin(),
+            end = this->file_to_generate().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->file_to_generate(i).data(), static_cast<int>(this->file_to_generate(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(1, this->file_to_generate(i), target);
+    target = stream->WriteString(1, s, target);
   }
 
   cached_has_bits = _has_bits_[0];
@@ -960,29 +873,29 @@
       this->parameter().data(), static_cast<int>(this->parameter().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorRequest.parameter");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->parameter(), target);
   }
 
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        3, _Internal::compiler_version(this), target);
+        3, _Internal::compiler_version(this), target, stream);
   }
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->proto_file_size()); i < n; i++) {
+  for (auto it = this->proto_file().pointer_begin(),
+            end = this->proto_file().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        15, this->proto_file(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(15, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorRequest)
   return target;
@@ -992,11 +905,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1037,6 +945,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1332,52 +1244,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void CodeGeneratorResponse_File::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorResponse.File)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorResponse.File.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional string insertion_point = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->insertion_point().data(), static_cast<int>(this->insertion_point().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->insertion_point(), output);
-  }
-
-  // optional string content = 15;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->content().data(), static_cast<int>(this->content().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorResponse.File.content");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      15, this->content(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse.File)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* CodeGeneratorResponse_File::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1389,8 +1257,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -1400,8 +1267,7 @@
       this->insertion_point().data(), static_cast<int>(this->insertion_point().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->insertion_point(), target);
   }
 
@@ -1411,14 +1277,13 @@
       this->content().data(), static_cast<int>(this->content().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.File.content");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         15, this->content(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse.File)
   return target;
@@ -1428,11 +1293,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1461,6 +1321,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1714,41 +1578,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void CodeGeneratorResponse::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.compiler.CodeGeneratorResponse)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string error = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->error().data(), static_cast<int>(this->error().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.compiler.CodeGeneratorResponse.error");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->error(), output);
-  }
-
-  // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      15,
-      this->file(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* CodeGeneratorResponse::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -1760,22 +1591,21 @@
       this->error().data(), static_cast<int>(this->error().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.compiler.CodeGeneratorResponse.error");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->error(), target);
   }
 
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
+  for (auto it = this->file().pointer_begin(),
+            end = this->file().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        15, this->file(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(15, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.compiler.CodeGeneratorResponse)
   return target;
@@ -1785,11 +1615,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1813,6 +1638,10 @@
         this->error());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ef26798..5055df2 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -170,10 +170,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -340,10 +338,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -528,10 +524,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -702,10 +696,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 1bae6a4..5bc64f1 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -649,13 +649,13 @@
   FileDescriptorTables* AllocateFileTables();
 
  private:
-  std::vector<std::string*> strings_;  // All strings in the pool.
-  std::vector<Message*> messages_;     // All messages in the pool.
-  std::vector<internal::once_flag*>
-      once_dynamics_;  // All internal::call_onces in the pool.
-  std::vector<FileDescriptorTables*>
-      file_tables_;                 // All file tables in the pool.
-  std::vector<void*> allocations_;  // All other memory allocated in the pool.
+  // All other memory allocated in the pool.  Must be first as other objects can
+  // point into these.
+  std::vector<std::unique_ptr<char[]>> allocations_;
+  std::vector<std::unique_ptr<std::string>> strings_;
+  std::vector<std::unique_ptr<Message>> messages_;
+  std::vector<std::unique_ptr<internal::once_flag>> once_dynamics_;
+  std::vector<std::unique_ptr<FileDescriptorTables>> file_tables_;
 
   SymbolsByNameMap symbols_by_name_;
   FilesByNameMap files_by_name_;
@@ -806,15 +806,6 @@
 
 DescriptorPool::Tables::~Tables() {
   GOOGLE_DCHECK(checkpoints_.empty());
-  // Note that the deletion order is important, since the destructors of some
-  // messages may refer to objects in allocations_.
-  STLDeleteElements(&messages_);
-  for (int i = 0; i < allocations_.size(); i++) {
-    operator delete(allocations_[i]);
-  }
-  STLDeleteElements(&strings_);
-  STLDeleteElements(&file_tables_);
-  STLDeleteElements(&once_dynamics_);
 }
 
 FileDescriptorTables::FileDescriptorTables()
@@ -876,22 +867,6 @@
   extensions_after_checkpoint_.resize(
       checkpoint.pending_extensions_before_checkpoint);
 
-  STLDeleteContainerPointers(
-      strings_.begin() + checkpoint.strings_before_checkpoint, strings_.end());
-  STLDeleteContainerPointers(
-      messages_.begin() + checkpoint.messages_before_checkpoint,
-      messages_.end());
-  STLDeleteContainerPointers(
-      once_dynamics_.begin() + checkpoint.once_dynamics_before_checkpoint,
-      once_dynamics_.end());
-  STLDeleteContainerPointers(
-      file_tables_.begin() + checkpoint.file_tables_before_checkpoint,
-      file_tables_.end());
-  for (int i = checkpoint.allocations_before_checkpoint;
-       i < allocations_.size(); i++) {
-    operator delete(allocations_[i]);
-  }
-
   strings_.resize(checkpoint.strings_before_checkpoint);
   messages_.resize(checkpoint.messages_before_checkpoint);
   once_dynamics_.resize(checkpoint.once_dynamics_before_checkpoint);
@@ -1194,32 +1169,32 @@
 
 std::string* DescriptorPool::Tables::AllocateString(const std::string& value) {
   std::string* result = new std::string(value);
-  strings_.push_back(result);
+  strings_.emplace_back(result);
   return result;
 }
 
 std::string* DescriptorPool::Tables::AllocateEmptyString() {
   std::string* result = new std::string();
-  strings_.push_back(result);
+  strings_.emplace_back(result);
   return result;
 }
 
 internal::once_flag* DescriptorPool::Tables::AllocateOnceDynamic() {
   internal::once_flag* result = new internal::once_flag();
-  once_dynamics_.push_back(result);
+  once_dynamics_.emplace_back(result);
   return result;
 }
 
 template <typename Type>
 Type* DescriptorPool::Tables::AllocateMessage(Type* /* dummy */) {
   Type* result = new Type;
-  messages_.push_back(result);
+  messages_.emplace_back(result);
   return result;
 }
 
 FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() {
   FileDescriptorTables* result = new FileDescriptorTables;
-  file_tables_.push_back(result);
+  file_tables_.emplace_back(result);
   return result;
 }
 
@@ -1230,9 +1205,8 @@
   // allocators...
   if (size == 0) return nullptr;
 
-  void* result = operator new(size);
-  allocations_.push_back(result);
-  return result;
+  allocations_.emplace_back(new char[size]);
+  return allocations_.back().get();
 }
 
 void FileDescriptorTables::BuildLocationsByPath(
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 420320d..8feecb8 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -1530,45 +1529,23 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FileDescriptorSet::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FileDescriptorSet)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.FileDescriptorProto file = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      1,
-      this->file(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorSet)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FileDescriptorSet::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.FileDescriptorProto file = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
+  for (auto it = this->file().pointer_begin(),
+            end = this->file().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        1, this->file(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(1, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorSet)
   return target;
@@ -1578,11 +1555,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1598,6 +1570,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2204,122 +2180,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FileDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FileDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional string package = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->package().data(), static_cast<int>(this->package().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileDescriptorProto.package");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->package(), output);
-  }
-
-  // repeated string dependency = 3;
-  for (int i = 0, n = this->dependency_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->dependency(i).data(), static_cast<int>(this->dependency(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileDescriptorProto.dependency");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      3, this->dependency(i), output);
-  }
-
-  // repeated .google.protobuf.DescriptorProto message_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->message_type_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4,
-      this->message_type(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enum_type_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5,
-      this->enum_type(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->service_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6,
-      this->service(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      7,
-      this->extension(static_cast<int>(i)),
-      output);
-  }
-
-  // optional .google.protobuf.FileOptions options = 8;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      8, _Internal::options(this), output);
-  }
-
-  // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      9, _Internal::source_code_info(this), output);
-  }
-
-  // repeated int32 public_dependency = 10;
-  for (int i = 0, n = this->public_dependency_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(
-      10, this->public_dependency(i), output);
-  }
-
-  // repeated int32 weak_dependency = 11;
-  for (int i = 0, n = this->weak_dependency_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(
-      11, this->weak_dependency(i), output);
-  }
-
-  // optional string syntax = 12;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->syntax().data(), static_cast<int>(this->syntax().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileDescriptorProto.syntax");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      12, this->syntax(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FileDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2331,8 +2193,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -2342,74 +2203,80 @@
       this->package().data(), static_cast<int>(this->package().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileDescriptorProto.package");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->package(), target);
   }
 
   // repeated string dependency = 3;
-  for (int i = 0, n = this->dependency_size(); i < n; i++) {
+  for (auto it = this->dependency().pointer_begin(),
+            end = this->dependency().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->dependency(i).data(), static_cast<int>(this->dependency(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileDescriptorProto.dependency");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(3, this->dependency(i), target);
+    target = stream->WriteString(3, s, target);
   }
 
   // repeated .google.protobuf.DescriptorProto message_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->message_type_size()); i < n; i++) {
+  for (auto it = this->message_type().pointer_begin(),
+            end = this->message_type().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        4, this->message_type(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(4, **it, target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enum_type_size()); i < n; i++) {
+  for (auto it = this->enum_type().pointer_begin(),
+            end = this->enum_type().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        5, this->enum_type(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(5, **it, target, stream);
   }
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->service_size()); i < n; i++) {
+  for (auto it = this->service().pointer_begin(),
+            end = this->service().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        6, this->service(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(6, **it, target, stream);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_size()); i < n; i++) {
+  for (auto it = this->extension().pointer_begin(),
+            end = this->extension().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        7, this->extension(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(7, **it, target, stream);
   }
 
   // optional .google.protobuf.FileOptions options = 8;
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        8, _Internal::options(this), target);
+        8, _Internal::options(this), target, stream);
   }
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
   if (cached_has_bits & 0x00000010u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        9, _Internal::source_code_info(this), target);
+        9, _Internal::source_code_info(this), target, stream);
   }
 
   // repeated int32 public_dependency = 10;
-  target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-    WriteInt32ToArray(10, this->public_dependency_, target);
+  for (const auto& x : this->public_dependency()) {
+    stream->EnsureSpace(&target);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(10, x, target);
+  }
 
   // repeated int32 weak_dependency = 11;
-  target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-    WriteInt32ToArray(11, this->weak_dependency_, target);
+  for (const auto& x : this->weak_dependency()) {
+    stream->EnsureSpace(&target);
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(11, x, target);
+  }
 
   // optional string syntax = 12;
   if (cached_has_bits & 0x00000004u) {
@@ -2417,14 +2284,13 @@
       this->syntax().data(), static_cast<int>(this->syntax().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileDescriptorProto.syntax");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         12, this->syntax(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileDescriptorProto)
   return target;
@@ -2434,11 +2300,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2551,6 +2412,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2896,38 +2761,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void DescriptorProto_ExtensionRange::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ExtensionRange)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional int32 start = 1;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(1, this->start(), output);
-  }
-
-  // optional int32 end = 2;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->end(), output);
-  }
-
-  // optional .google.protobuf.ExtensionRangeOptions options = 3;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, _Internal::options(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ExtensionRange)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* DescriptorProto_ExtensionRange::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2935,24 +2770,27 @@
   cached_has_bits = _has_bits_[0];
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
   }
 
   // optional .google.protobuf.ExtensionRangeOptions options = 3;
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        3, _Internal::options(this), target);
+        3, _Internal::options(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ExtensionRange)
   return target;
@@ -2962,11 +2800,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2995,6 +2828,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -3260,32 +3097,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void DescriptorProto_ReservedRange::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ReservedRange)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional int32 start = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(1, this->start(), output);
-  }
-
-  // optional int32 end = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->end(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* DescriptorProto_ReservedRange::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -3293,17 +3106,19 @@
   cached_has_bits = _has_bits_[0];
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
   return target;
@@ -3313,11 +3128,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -3339,6 +3149,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -3841,111 +3655,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void DescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.DescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->field_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->field(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->nested_type_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3,
-      this->nested_type(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enum_type_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4,
-      this->enum_type(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_range_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5,
-      this->extension_range(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6,
-      this->extension(static_cast<int>(i)),
-      output);
-  }
-
-  // optional .google.protobuf.MessageOptions options = 7;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      7, _Internal::options(this), output);
-  }
-
-  // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->oneof_decl_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      8,
-      this->oneof_decl(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->reserved_range_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      9,
-      this->reserved_range(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated string reserved_name = 10;
-  for (int i = 0, n = this->reserved_name_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->reserved_name(i).data(), static_cast<int>(this->reserved_name(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.DescriptorProto.reserved_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      10, this->reserved_name(i), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* DescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -3957,87 +3668,88 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.DescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->field_size()); i < n; i++) {
+  for (auto it = this->field().pointer_begin(),
+            end = this->field().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->field(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->nested_type_size()); i < n; i++) {
+  for (auto it = this->nested_type().pointer_begin(),
+            end = this->nested_type().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        3, this->nested_type(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(3, **it, target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enum_type_size()); i < n; i++) {
+  for (auto it = this->enum_type().pointer_begin(),
+            end = this->enum_type().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        4, this->enum_type(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(4, **it, target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_range_size()); i < n; i++) {
+  for (auto it = this->extension_range().pointer_begin(),
+            end = this->extension_range().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        5, this->extension_range(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(5, **it, target, stream);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->extension_size()); i < n; i++) {
+  for (auto it = this->extension().pointer_begin(),
+            end = this->extension().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        6, this->extension(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(6, **it, target, stream);
   }
 
   // optional .google.protobuf.MessageOptions options = 7;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        7, _Internal::options(this), target);
+        7, _Internal::options(this), target, stream);
   }
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->oneof_decl_size()); i < n; i++) {
+  for (auto it = this->oneof_decl().pointer_begin(),
+            end = this->oneof_decl().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        8, this->oneof_decl(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(8, **it, target, stream);
   }
 
   // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->reserved_range_size()); i < n; i++) {
+  for (auto it = this->reserved_range().pointer_begin(),
+            end = this->reserved_range().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        9, this->reserved_range(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(9, **it, target, stream);
   }
 
   // repeated string reserved_name = 10;
-  for (int i = 0, n = this->reserved_name_size(); i < n; i++) {
+  for (auto it = this->reserved_name().pointer_begin(),
+            end = this->reserved_name().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->reserved_name(i).data(), static_cast<int>(this->reserved_name(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.DescriptorProto.reserved_name");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(10, this->reserved_name(i), target);
+    target = stream->WriteString(10, s, target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto)
   return target;
@@ -4047,11 +3759,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -4158,6 +3865,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -4421,52 +4132,27 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void ExtensionRangeOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.ExtensionRangeOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.ExtensionRangeOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* ExtensionRangeOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ExtensionRangeOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ExtensionRangeOptions)
   return target;
@@ -4478,11 +4164,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -4498,6 +4179,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -5056,100 +4741,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FieldDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FieldDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FieldDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional string extendee = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->extendee().data(), static_cast<int>(this->extendee().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FieldDescriptorProto.extendee");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->extendee(), output);
-  }
-
-  // optional int32 number = 3;
-  if (cached_has_bits & 0x00000040u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(3, this->number(), output);
-  }
-
-  // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
-  if (cached_has_bits & 0x00000100u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      4, this->label(), output);
-  }
-
-  // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
-  if (cached_has_bits & 0x00000200u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      5, this->type(), output);
-  }
-
-  // optional string type_name = 6;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->type_name().data(), static_cast<int>(this->type_name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FieldDescriptorProto.type_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      6, this->type_name(), output);
-  }
-
-  // optional string default_value = 7;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->default_value().data(), static_cast<int>(this->default_value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FieldDescriptorProto.default_value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      7, this->default_value(), output);
-  }
-
-  // optional .google.protobuf.FieldOptions options = 8;
-  if (cached_has_bits & 0x00000020u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      8, _Internal::options(this), output);
-  }
-
-  // optional int32 oneof_index = 9;
-  if (cached_has_bits & 0x00000080u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(9, this->oneof_index(), output);
-  }
-
-  // optional string json_name = 10;
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->json_name().data(), static_cast<int>(this->json_name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FieldDescriptorProto.json_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      10, this->json_name(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FieldDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FieldDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -5161,8 +4754,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FieldDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -5172,24 +4764,26 @@
       this->extendee().data(), static_cast<int>(this->extendee().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FieldDescriptorProto.extendee");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->extendee(), target);
   }
 
   // optional int32 number = 3;
   if (cached_has_bits & 0x00000040u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target);
   }
 
   // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
   if (cached_has_bits & 0x00000100u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       4, this->label(), target);
   }
 
   // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
   if (cached_has_bits & 0x00000200u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       5, this->type(), target);
   }
@@ -5200,8 +4794,7 @@
       this->type_name().data(), static_cast<int>(this->type_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FieldDescriptorProto.type_name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         6, this->type_name(), target);
   }
 
@@ -5211,20 +4804,21 @@
       this->default_value().data(), static_cast<int>(this->default_value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FieldDescriptorProto.default_value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         7, this->default_value(), target);
   }
 
   // optional .google.protobuf.FieldOptions options = 8;
   if (cached_has_bits & 0x00000020u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        8, _Internal::options(this), target);
+        8, _Internal::options(this), target, stream);
   }
 
   // optional int32 oneof_index = 9;
   if (cached_has_bits & 0x00000080u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(9, this->oneof_index(), target);
   }
 
@@ -5234,14 +4828,13 @@
       this->json_name().data(), static_cast<int>(this->json_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FieldDescriptorProto.json_name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         10, this->json_name(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldDescriptorProto)
   return target;
@@ -5251,11 +4844,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -5333,6 +4921,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -5665,38 +5257,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void OneofDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.OneofDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.OneofDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional .google.protobuf.OneofOptions options = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2, _Internal::options(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.OneofDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* OneofDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -5708,21 +5270,21 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.OneofDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // optional .google.protobuf.OneofOptions options = 2;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        2, _Internal::options(this), target);
+        2, _Internal::options(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofDescriptorProto)
   return target;
@@ -5732,11 +5294,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -5758,6 +5315,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -6019,32 +5580,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumDescriptorProto_EnumReservedRange::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional int32 start = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(1, this->start(), output);
-  }
-
-  // optional int32 end = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->end(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumDescriptorProto.EnumReservedRange)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumDescriptorProto_EnumReservedRange::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -6052,17 +5589,19 @@
   cached_has_bits = _has_bits_[0];
   // optional int32 start = 1;
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
   }
 
   // optional int32 end = 2;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto.EnumReservedRange)
   return target;
@@ -6072,11 +5611,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto.EnumReservedRange)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -6098,6 +5632,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -6470,66 +6008,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.EnumDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->value_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->value(static_cast<int>(i)),
-      output);
-  }
-
-  // optional .google.protobuf.EnumOptions options = 3;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, _Internal::options(this), output);
-  }
-
-  // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->reserved_range_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4,
-      this->reserved_range(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated string reserved_name = 5;
-  for (int i = 0, n = this->reserved_name_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->reserved_name(i).data(), static_cast<int>(this->reserved_name(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.EnumDescriptorProto.reserved_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      5, this->reserved_name(i), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -6541,47 +6021,48 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.EnumDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->value_size()); i < n; i++) {
+  for (auto it = this->value().pointer_begin(),
+            end = this->value().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->value(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // optional .google.protobuf.EnumOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        3, _Internal::options(this), target);
+        3, _Internal::options(this), target, stream);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->reserved_range_size()); i < n; i++) {
+  for (auto it = this->reserved_range().pointer_begin(),
+            end = this->reserved_range().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        4, this->reserved_range(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(4, **it, target, stream);
   }
 
   // repeated string reserved_name = 5;
-  for (int i = 0, n = this->reserved_name_size(); i < n; i++) {
+  for (auto it = this->reserved_name().pointer_begin(),
+            end = this->reserved_name().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->reserved_name(i).data(), static_cast<int>(this->reserved_name(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.EnumDescriptorProto.reserved_name");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(5, this->reserved_name(i), target);
+    target = stream->WriteString(5, s, target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumDescriptorProto)
   return target;
@@ -6591,11 +6072,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -6647,6 +6123,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -6974,43 +6454,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumValueDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValueDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.EnumValueDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional int32 number = 2;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->number(), output);
-  }
-
-  // optional .google.protobuf.EnumValueOptions options = 3;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, _Internal::options(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumValueDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -7022,26 +6467,27 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.EnumValueDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // optional int32 number = 2;
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target);
   }
 
   // optional .google.protobuf.EnumValueOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        3, _Internal::options(this), target);
+        3, _Internal::options(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueDescriptorProto)
   return target;
@@ -7051,11 +6497,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -7084,6 +6525,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -7407,47 +6852,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void ServiceDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.ServiceDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.ServiceDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->method_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->method(static_cast<int>(i)),
-      output);
-  }
-
-  // optional .google.protobuf.ServiceOptions options = 3;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, _Internal::options(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* ServiceDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -7459,29 +6865,29 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.ServiceDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->method_size()); i < n; i++) {
+  for (auto it = this->method().pointer_begin(),
+            end = this->method().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->method(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // optional .google.protobuf.ServiceOptions options = 3;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        3, _Internal::options(this), target);
+        3, _Internal::options(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceDescriptorProto)
   return target;
@@ -7491,11 +6897,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -7528,6 +6929,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -7949,68 +7354,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void MethodDescriptorProto::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.MethodDescriptorProto)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string name = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.MethodDescriptorProto.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // optional string input_type = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->input_type().data(), static_cast<int>(this->input_type().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.MethodDescriptorProto.input_type");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->input_type(), output);
-  }
-
-  // optional string output_type = 3;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->output_type().data(), static_cast<int>(this->output_type().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.MethodDescriptorProto.output_type");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      3, this->output_type(), output);
-  }
-
-  // optional .google.protobuf.MethodOptions options = 4;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4, _Internal::options(this), output);
-  }
-
-  // optional bool client_streaming = 5 [default = false];
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(5, this->client_streaming(), output);
-  }
-
-  // optional bool server_streaming = 6 [default = false];
-  if (cached_has_bits & 0x00000020u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(6, this->server_streaming(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.MethodDescriptorProto)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* MethodDescriptorProto::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -8022,8 +7367,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.MethodDescriptorProto.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
@@ -8033,8 +7377,7 @@
       this->input_type().data(), static_cast<int>(this->input_type().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.MethodDescriptorProto.input_type");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->input_type(), target);
   }
 
@@ -8044,31 +7387,33 @@
       this->output_type().data(), static_cast<int>(this->output_type().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.MethodDescriptorProto.output_type");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         3, this->output_type(), target);
   }
 
   // optional .google.protobuf.MethodOptions options = 4;
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        4, _Internal::options(this), target);
+        4, _Internal::options(this), target, stream);
   }
 
   // optional bool client_streaming = 5 [default = false];
   if (cached_has_bits & 0x00000010u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->client_streaming(), target);
   }
 
   // optional bool server_streaming = 6 [default = false];
   if (cached_has_bits & 0x00000020u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(6, this->server_streaming(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodDescriptorProto)
   return target;
@@ -8078,11 +7423,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -8128,6 +7468,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -9013,185 +8357,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FileOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FileOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional string java_package = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->java_package().data(), static_cast<int>(this->java_package().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.java_package");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->java_package(), output);
-  }
-
-  // optional string java_outer_classname = 8;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->java_outer_classname().data(), static_cast<int>(this->java_outer_classname().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.java_outer_classname");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      8, this->java_outer_classname(), output);
-  }
-
-  // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
-  if (cached_has_bits & 0x00080000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      9, this->optimize_for(), output);
-  }
-
-  // optional bool java_multiple_files = 10 [default = false];
-  if (cached_has_bits & 0x00000400u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output);
-  }
-
-  // optional string go_package = 11;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->go_package().data(), static_cast<int>(this->go_package().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.go_package");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      11, this->go_package(), output);
-  }
-
-  // optional bool cc_generic_services = 16 [default = false];
-  if (cached_has_bits & 0x00002000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output);
-  }
-
-  // optional bool java_generic_services = 17 [default = false];
-  if (cached_has_bits & 0x00004000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output);
-  }
-
-  // optional bool py_generic_services = 18 [default = false];
-  if (cached_has_bits & 0x00008000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output);
-  }
-
-  // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
-  if (cached_has_bits & 0x00000800u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(20, this->java_generate_equals_and_hash(), output);
-  }
-
-  // optional bool deprecated = 23 [default = false];
-  if (cached_has_bits & 0x00020000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(23, this->deprecated(), output);
-  }
-
-  // optional bool java_string_check_utf8 = 27 [default = false];
-  if (cached_has_bits & 0x00001000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(27, this->java_string_check_utf8(), output);
-  }
-
-  // optional bool cc_enable_arenas = 31 [default = false];
-  if (cached_has_bits & 0x00040000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(31, this->cc_enable_arenas(), output);
-  }
-
-  // optional string objc_class_prefix = 36;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->objc_class_prefix().data(), static_cast<int>(this->objc_class_prefix().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.objc_class_prefix");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      36, this->objc_class_prefix(), output);
-  }
-
-  // optional string csharp_namespace = 37;
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->csharp_namespace().data(), static_cast<int>(this->csharp_namespace().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.csharp_namespace");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      37, this->csharp_namespace(), output);
-  }
-
-  // optional string swift_prefix = 39;
-  if (cached_has_bits & 0x00000020u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->swift_prefix().data(), static_cast<int>(this->swift_prefix().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.swift_prefix");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      39, this->swift_prefix(), output);
-  }
-
-  // optional string php_class_prefix = 40;
-  if (cached_has_bits & 0x00000040u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->php_class_prefix().data(), static_cast<int>(this->php_class_prefix().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.php_class_prefix");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      40, this->php_class_prefix(), output);
-  }
-
-  // optional string php_namespace = 41;
-  if (cached_has_bits & 0x00000080u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->php_namespace().data(), static_cast<int>(this->php_namespace().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.php_namespace");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      41, this->php_namespace(), output);
-  }
-
-  // optional bool php_generic_services = 42 [default = false];
-  if (cached_has_bits & 0x00010000u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(42, this->php_generic_services(), output);
-  }
-
-  // optional string php_metadata_namespace = 44;
-  if (cached_has_bits & 0x00000100u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->php_metadata_namespace().data(), static_cast<int>(this->php_metadata_namespace().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.php_metadata_namespace");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      44, this->php_metadata_namespace(), output);
-  }
-
-  // optional string ruby_package = 45;
-  if (cached_has_bits & 0x00000200u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->ruby_package().data(), static_cast<int>(this->ruby_package().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.FileOptions.ruby_package");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      45, this->ruby_package(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FileOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FileOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -9203,8 +8370,7 @@
       this->java_package().data(), static_cast<int>(this->java_package().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.java_package");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->java_package(), target);
   }
 
@@ -9214,19 +8380,20 @@
       this->java_outer_classname().data(), static_cast<int>(this->java_outer_classname().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.java_outer_classname");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         8, this->java_outer_classname(), target);
   }
 
   // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
   if (cached_has_bits & 0x00080000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       9, this->optimize_for(), target);
   }
 
   // optional bool java_multiple_files = 10 [default = false];
   if (cached_has_bits & 0x00000400u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target);
   }
 
@@ -9236,43 +8403,49 @@
       this->go_package().data(), static_cast<int>(this->go_package().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.go_package");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         11, this->go_package(), target);
   }
 
   // optional bool cc_generic_services = 16 [default = false];
   if (cached_has_bits & 0x00002000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target);
   }
 
   // optional bool java_generic_services = 17 [default = false];
   if (cached_has_bits & 0x00004000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target);
   }
 
   // optional bool py_generic_services = 18 [default = false];
   if (cached_has_bits & 0x00008000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target);
   }
 
   // optional bool java_generate_equals_and_hash = 20 [deprecated = true];
   if (cached_has_bits & 0x00000800u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(20, this->java_generate_equals_and_hash(), target);
   }
 
   // optional bool deprecated = 23 [default = false];
   if (cached_has_bits & 0x00020000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(23, this->deprecated(), target);
   }
 
   // optional bool java_string_check_utf8 = 27 [default = false];
   if (cached_has_bits & 0x00001000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(27, this->java_string_check_utf8(), target);
   }
 
   // optional bool cc_enable_arenas = 31 [default = false];
   if (cached_has_bits & 0x00040000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(31, this->cc_enable_arenas(), target);
   }
 
@@ -9282,8 +8455,7 @@
       this->objc_class_prefix().data(), static_cast<int>(this->objc_class_prefix().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.objc_class_prefix");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         36, this->objc_class_prefix(), target);
   }
 
@@ -9293,8 +8465,7 @@
       this->csharp_namespace().data(), static_cast<int>(this->csharp_namespace().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.csharp_namespace");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         37, this->csharp_namespace(), target);
   }
 
@@ -9304,8 +8475,7 @@
       this->swift_prefix().data(), static_cast<int>(this->swift_prefix().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.swift_prefix");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         39, this->swift_prefix(), target);
   }
 
@@ -9315,8 +8485,7 @@
       this->php_class_prefix().data(), static_cast<int>(this->php_class_prefix().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.php_class_prefix");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         40, this->php_class_prefix(), target);
   }
 
@@ -9326,13 +8495,13 @@
       this->php_namespace().data(), static_cast<int>(this->php_namespace().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.php_namespace");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         41, this->php_namespace(), target);
   }
 
   // optional bool php_generic_services = 42 [default = false];
   if (cached_has_bits & 0x00010000u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(42, this->php_generic_services(), target);
   }
 
@@ -9342,8 +8511,7 @@
       this->php_metadata_namespace().data(), static_cast<int>(this->php_metadata_namespace().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.php_metadata_namespace");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         44, this->php_metadata_namespace(), target);
   }
 
@@ -9353,26 +8521,25 @@
       this->ruby_package().data(), static_cast<int>(this->ruby_package().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.FileOptions.ruby_package");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         45, this->ruby_package(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FileOptions)
   return target;
@@ -9384,11 +8551,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -9532,6 +8694,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -9973,54 +9139,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void MessageOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.MessageOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional bool message_set_wire_format = 1 [default = false];
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output);
-  }
-
-  // optional bool no_standard_descriptor_accessor = 2 [default = false];
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(2, this->no_standard_descriptor_accessor(), output);
-  }
-
-  // optional bool deprecated = 3 [default = false];
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
-  }
-
-  // optional bool map_entry = 7;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(7, this->map_entry(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.MessageOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* MessageOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -10028,39 +9148,43 @@
   cached_has_bits = _has_bits_[0];
   // optional bool message_set_wire_format = 1 [default = false];
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->message_set_wire_format(), target);
   }
 
   // optional bool no_standard_descriptor_accessor = 2 [default = false];
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->no_standard_descriptor_accessor(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
   }
 
   // optional bool map_entry = 7;
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(7, this->map_entry(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MessageOptions)
   return target;
@@ -10072,11 +9196,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -10115,6 +9234,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -10548,66 +9671,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FieldOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FieldOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      1, this->ctype(), output);
-  }
-
-  // optional bool packed = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(2, this->packed(), output);
-  }
-
-  // optional bool deprecated = 3 [default = false];
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
-  }
-
-  // optional bool lazy = 5 [default = false];
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(5, this->lazy(), output);
-  }
-
-  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
-  if (cached_has_bits & 0x00000020u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      6, this->jstype(), output);
-  }
-
-  // optional bool weak = 10 [default = false];
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(10, this->weak(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FieldOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FieldOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -10615,51 +9680,57 @@
   cached_has_bits = _has_bits_[0];
   // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       1, this->ctype(), target);
   }
 
   // optional bool packed = 2;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->packed(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
   }
 
   // optional bool lazy = 5 [default = false];
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target);
   }
 
   // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
   if (cached_has_bits & 0x00000020u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       6, this->jstype(), target);
   }
 
   // optional bool weak = 10 [default = false];
   if (cached_has_bits & 0x00000010u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldOptions)
   return target;
@@ -10671,11 +9742,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -10726,6 +9792,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -10989,52 +10059,27 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void OneofOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.OneofOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.OneofOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* OneofOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
   return target;
@@ -11046,11 +10091,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -11066,6 +10106,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -11360,44 +10404,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional bool allow_alias = 2;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(2, this->allow_alias(), output);
-  }
-
-  // optional bool deprecated = 3 [default = false];
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(3, this->deprecated(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -11405,29 +10413,31 @@
   cached_has_bits = _has_bits_[0];
   // optional bool allow_alias = 2;
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->allow_alias(), target);
   }
 
   // optional bool deprecated = 3 [default = false];
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(3, this->deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumOptions)
   return target;
@@ -11439,11 +10449,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -11472,6 +10477,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -11748,39 +10757,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumValueOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValueOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional bool deprecated = 1 [default = false];
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(1, this->deprecated(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumValueOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -11788,24 +10766,25 @@
   cached_has_bits = _has_bits_[0];
   // optional bool deprecated = 1 [default = false];
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValueOptions)
   return target;
@@ -11817,11 +10796,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -11843,6 +10817,10 @@
     total_size += 1 + 1;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -12111,39 +11089,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void ServiceOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.ServiceOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional bool deprecated = 33 [default = false];
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(33, this->deprecated(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* ServiceOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -12151,24 +11098,25 @@
   cached_has_bits = _has_bits_[0];
   // optional bool deprecated = 33 [default = false];
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(33, this->deprecated(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ServiceOptions)
   return target;
@@ -12180,11 +11128,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -12206,6 +11149,10 @@
     total_size += 2 + 1;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -12517,45 +11464,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void MethodOptions::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.MethodOptions)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // optional bool deprecated = 33 [default = false];
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(33, this->deprecated(), output);
-  }
-
-  // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      34, this->idempotency_level(), output);
-  }
-
-  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      999,
-      this->uninterpreted_option(static_cast<int>(i)),
-      output);
-  }
-
-  // Extension range [1000, 536870912)
-  _extensions_.SerializeWithCachedSizes(1000, 536870912, output);
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.MethodOptions)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* MethodOptions::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -12563,30 +11473,32 @@
   cached_has_bits = _has_bits_[0];
   // optional bool deprecated = 33 [default = false];
   if (cached_has_bits & 0x00000001u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(33, this->deprecated(), target);
   }
 
   // optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       34, this->idempotency_level(), target);
   }
 
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->uninterpreted_option_size()); i < n; i++) {
+  for (auto it = this->uninterpreted_option().pointer_begin(),
+            end = this->uninterpreted_option().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        999, this->uninterpreted_option(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(999, **it, target, stream);
   }
 
   // Extension range [1000, 536870912)
   target = _extensions_.InternalSerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+      1000, 536870912, target, stream);
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.MethodOptions)
   return target;
@@ -12598,11 +11510,6 @@
 
   total_size += _extensions_.ByteSize();
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -12632,6 +11539,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -12903,37 +11814,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void UninterpretedOption_NamePart::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.UninterpretedOption.NamePart)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  cached_has_bits = _has_bits_[0];
-  // required string name_part = 1;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->name_part().data(), static_cast<int>(this->name_part().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.UninterpretedOption.NamePart.name_part");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name_part(), output);
-  }
-
-  // required bool is_extension = 2;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(2, this->is_extension(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption.NamePart)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* UninterpretedOption_NamePart::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -12945,19 +11827,19 @@
       this->name_part().data(), static_cast<int>(this->name_part().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.UninterpretedOption.NamePart.name_part");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name_part(), target);
   }
 
   // required bool is_extension = 2;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(2, this->is_extension(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption.NamePart)
   return target;
@@ -12985,11 +11867,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) {  // All required fields are present.
     // required string name_part = 1;
     total_size += 1 +
@@ -13006,6 +11883,10 @@
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -13420,82 +12301,18 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void UninterpretedOption::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.UninterpretedOption)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->name_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->name(static_cast<int>(i)),
-      output);
-  }
-
-  cached_has_bits = _has_bits_[0];
-  // optional string identifier_value = 3;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->identifier_value().data(), static_cast<int>(this->identifier_value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.UninterpretedOption.identifier_value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      3, this->identifier_value(), output);
-  }
-
-  // optional uint64 positive_int_value = 4;
-  if (cached_has_bits & 0x00000008u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64(4, this->positive_int_value(), output);
-  }
-
-  // optional int64 negative_int_value = 5;
-  if (cached_has_bits & 0x00000010u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64(5, this->negative_int_value(), output);
-  }
-
-  // optional double double_value = 6;
-  if (cached_has_bits & 0x00000020u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDouble(6, this->double_value(), output);
-  }
-
-  // optional bytes string_value = 7;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesMaybeAliased(
-      7, this->string_value(), output);
-  }
-
-  // optional string aggregate_value = 8;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->aggregate_value().data(), static_cast<int>(this->aggregate_value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.UninterpretedOption.aggregate_value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      8, this->aggregate_value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* UninterpretedOption::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->name_size()); i < n; i++) {
+  for (auto it = this->name().pointer_begin(),
+            end = this->name().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->name(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   cached_has_bits = _has_bits_[0];
@@ -13505,30 +12322,31 @@
       this->identifier_value().data(), static_cast<int>(this->identifier_value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.UninterpretedOption.identifier_value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         3, this->identifier_value(), target);
   }
 
   // optional uint64 positive_int_value = 4;
   if (cached_has_bits & 0x00000008u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(4, this->positive_int_value(), target);
   }
 
   // optional int64 negative_int_value = 5;
   if (cached_has_bits & 0x00000010u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(5, this->negative_int_value(), target);
   }
 
   // optional double double_value = 6;
   if (cached_has_bits & 0x00000020u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(6, this->double_value(), target);
   }
 
   // optional bytes string_value = 7;
   if (cached_has_bits & 0x00000002u) {
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesToArray(
+    target = stream->WriteBytesMaybeAliased(
         7, this->string_value(), target);
   }
 
@@ -13538,14 +12356,13 @@
       this->aggregate_value().data(), static_cast<int>(this->aggregate_value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.UninterpretedOption.aggregate_value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         8, this->aggregate_value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UninterpretedOption)
   return target;
@@ -13555,11 +12372,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -13618,6 +12430,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -14001,102 +12817,28 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void SourceCodeInfo_Location::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.SourceCodeInfo.Location)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated int32 path = 1 [packed = true];
-  if (this->path_size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTag(1, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_path_cached_byte_size_.load(
-        std::memory_order_relaxed));
-  }
-  for (int i = 0, n = this->path_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32NoTag(
-      this->path(i), output);
-  }
-
-  // repeated int32 span = 2 [packed = true];
-  if (this->span_size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTag(2, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_span_cached_byte_size_.load(
-        std::memory_order_relaxed));
-  }
-  for (int i = 0, n = this->span_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32NoTag(
-      this->span(i), output);
-  }
-
-  cached_has_bits = _has_bits_[0];
-  // optional string leading_comments = 3;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->leading_comments().data(), static_cast<int>(this->leading_comments().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.SourceCodeInfo.Location.leading_comments");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      3, this->leading_comments(), output);
-  }
-
-  // optional string trailing_comments = 4;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->trailing_comments().data(), static_cast<int>(this->trailing_comments().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.SourceCodeInfo.Location.trailing_comments");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      4, this->trailing_comments(), output);
-  }
-
-  // repeated string leading_detached_comments = 6;
-  for (int i = 0, n = this->leading_detached_comments_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->leading_detached_comments(i).data(), static_cast<int>(this->leading_detached_comments(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      6, this->leading_detached_comments(i), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo.Location)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* SourceCodeInfo_Location::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated int32 path = 1 [packed = true];
-  if (this->path_size() > 0) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTagToArray(
-      1,
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream::WriteVarint32ToArray(
-        _path_cached_byte_size_.load(std::memory_order_relaxed),
-         target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteInt32NoTagToArray(this->path_, target);
+  {
+    int byte_size = _path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, path_, byte_size, target);
+    }
   }
 
   // repeated int32 span = 2 [packed = true];
-  if (this->span_size() > 0) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTagToArray(
-      2,
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream::WriteVarint32ToArray(
-        _span_cached_byte_size_.load(std::memory_order_relaxed),
-         target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteInt32NoTagToArray(this->span_, target);
+  {
+    int byte_size = _span_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          2, span_, byte_size, target);
+    }
   }
 
   cached_has_bits = _has_bits_[0];
@@ -14106,8 +12848,7 @@
       this->leading_comments().data(), static_cast<int>(this->leading_comments().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.SourceCodeInfo.Location.leading_comments");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         3, this->leading_comments(), target);
   }
 
@@ -14117,24 +12858,24 @@
       this->trailing_comments().data(), static_cast<int>(this->trailing_comments().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.SourceCodeInfo.Location.trailing_comments");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         4, this->trailing_comments(), target);
   }
 
   // repeated string leading_detached_comments = 6;
-  for (int i = 0, n = this->leading_detached_comments_size(); i < n; i++) {
+  for (auto it = this->leading_detached_comments().pointer_begin(),
+            end = this->leading_detached_comments().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->leading_detached_comments(i).data(), static_cast<int>(this->leading_detached_comments(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.SourceCodeInfo.Location.leading_detached_comments");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(6, this->leading_detached_comments(i), target);
+    target = stream->WriteString(6, s, target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo.Location)
   return target;
@@ -14144,11 +12885,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -14208,6 +12944,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -14438,45 +13178,23 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void SourceCodeInfo::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.SourceCodeInfo)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->location_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      1,
-      this->location(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* SourceCodeInfo::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->location_size()); i < n; i++) {
+  for (auto it = this->location().pointer_begin(),
+            end = this->location().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        1, this->location(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(1, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceCodeInfo)
   return target;
@@ -14486,11 +13204,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -14506,6 +13219,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -14819,68 +13536,19 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo.Annotation)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated int32 path = 1 [packed = true];
-  if (this->path_size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTag(1, ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(_path_cached_byte_size_.load(
-        std::memory_order_relaxed));
-  }
-  for (int i = 0, n = this->path_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32NoTag(
-      this->path(i), output);
-  }
-
-  cached_has_bits = _has_bits_[0];
-  // optional string source_file = 2;
-  if (cached_has_bits & 0x00000001u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::VerifyUTF8StringNamedField(
-      this->source_file().data(), static_cast<int>(this->source_file().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
-      "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      2, this->source_file(), output);
-  }
-
-  // optional int32 begin = 3;
-  if (cached_has_bits & 0x00000002u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(3, this->begin(), output);
-  }
-
-  // optional int32 end = 4;
-  if (cached_has_bits & 0x00000004u) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(4, this->end(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* GeneratedCodeInfo_Annotation::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated int32 path = 1 [packed = true];
-  if (this->path_size() > 0) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteTagToArray(
-      1,
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
-      target);
-    target = ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream::WriteVarint32ToArray(
-        _path_cached_byte_size_.load(std::memory_order_relaxed),
-         target);
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteInt32NoTagToArray(this->path_, target);
+  {
+    int byte_size = _path_cached_byte_size_.load(std::memory_order_relaxed);
+    if (byte_size > 0) {
+      target = stream->WriteInt32Packed(
+          1, path_, byte_size, target);
+    }
   }
 
   cached_has_bits = _has_bits_[0];
@@ -14890,24 +13558,25 @@
       this->source_file().data(), static_cast<int>(this->source_file().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SERIALIZE,
       "google.protobuf.GeneratedCodeInfo.Annotation.source_file");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         2, this->source_file(), target);
   }
 
   // optional int32 begin = 3;
   if (cached_has_bits & 0x00000002u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->begin(), target);
   }
 
   // optional int32 end = 4;
   if (cached_has_bits & 0x00000004u) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(4, this->end(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo.Annotation)
   return target;
@@ -14917,11 +13586,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -14965,6 +13629,10 @@
     }
 
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -15195,45 +13863,23 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void GeneratedCodeInfo::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.GeneratedCodeInfo)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->annotation_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      1,
-      this->annotation(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* GeneratedCodeInfo::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->annotation_size()); i < n; i++) {
+  for (auto it = this->annotation().pointer_begin(),
+            end = this->annotation().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        1, this->annotation(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(1, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.GeneratedCodeInfo)
   return target;
@@ -15243,11 +13889,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -15263,6 +13904,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 47b1d87..d2601e3 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -427,10 +427,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -595,10 +593,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -942,10 +938,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1126,10 +1120,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1297,10 +1289,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1601,10 +1591,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1772,10 +1760,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -2181,10 +2167,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -2372,10 +2356,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -2543,10 +2525,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -2781,10 +2761,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -2980,10 +2958,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -3184,10 +3160,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -3437,10 +3411,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -3950,10 +3922,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -4153,10 +4123,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -4436,10 +4404,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -4607,10 +4573,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -4794,10 +4758,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -4973,10 +4935,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -5152,10 +5112,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -5371,10 +5329,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -5560,10 +5516,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -5823,10 +5777,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -6071,10 +6023,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -6241,10 +6191,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -6449,10 +6397,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc
index 9759300..fe6b02c 100644
--- a/src/google/protobuf/descriptor_database.cc
+++ b/src/google/protobuf/descriptor_database.cc
@@ -111,6 +111,9 @@
 
 // ===================================================================
 
+SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
+SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {}
+
 template <typename Value>
 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
     const FileDescriptorProto& file, Value value) {
@@ -328,11 +331,6 @@
 
 // -------------------------------------------------------------------
 
-SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
-SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
-  STLDeleteElements(&files_to_delete_);
-}
-
 bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
   FileDescriptorProto* new_file = new FileDescriptorProto;
   new_file->CopyFrom(file);
@@ -340,7 +338,7 @@
 }
 
 bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
-  files_to_delete_.push_back(file);
+  files_to_delete_.emplace_back(file);
   return index_.AddFile(*file, file);
 }
 
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index 351e6ee..e6d9266 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -47,7 +47,7 @@
 #include <google/protobuf/port_def.inc>
 
 #ifdef SWIG
-#define PROTOBUF_EXPORT
+#error "You cannot SWIG proto headers"
 #endif
 
 namespace google {
@@ -284,7 +284,7 @@
   };
 
   DescriptorIndex<const FileDescriptorProto*> index_;
-  std::vector<const FileDescriptorProto*> files_to_delete_;
+  std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_;
 
   // If file is non-NULL, copy it into *output and return true, otherwise
   // return false.
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 6aea363..6f0cec7 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -254,48 +253,27 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Duration::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Duration)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // int64 seconds = 1;
-  if (this->seconds() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64(1, this->seconds(), output);
-  }
-
-  // int32 nanos = 2;
-  if (this->nanos() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->nanos(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Duration)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Duration::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // int64 seconds = 1;
   if (this->seconds() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->seconds(), target);
   }
 
   // int32 nanos = 2;
   if (this->nanos() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->nanos(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Duration)
   return target;
@@ -305,11 +283,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -328,6 +301,10 @@
         this->nanos());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index c7023fe..dd0c6a8 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -156,10 +156,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index 412d6f7..caa48d0 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -196,28 +195,15 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Empty::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Empty)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Empty)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Empty::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
   return target;
@@ -227,15 +213,14 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index d9b04b4..50e8271 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -156,10 +156,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 67b0fca..8342482 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -1465,23 +1465,35 @@
   return ParseMessageSetLite(input, &finder, &skipper);
 }
 
-void ExtensionSet::SerializeWithCachedSizes(
-    int start_field_number, int end_field_number,
-    io::CodedOutputStream* output) const {
+uint8* ExtensionSet::InternalSerializeWithCachedSizesToArray(
+    int start_field_number, int end_field_number, uint8* target,
+    io::EpsCopyOutputStream* stream) const {
   if (PROTOBUF_PREDICT_FALSE(is_large())) {
     const auto& end = map_.large->end();
     for (auto it = map_.large->lower_bound(start_field_number);
          it != end && it->first < end_field_number; ++it) {
-      it->second.SerializeFieldWithCachedSizes(it->first, output);
+      target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+          it->first, target, stream);
     }
-    return;
+    return target;
   }
   const KeyValue* end = flat_end();
   for (const KeyValue* it = std::lower_bound(
            flat_begin(), end, start_field_number, KeyValue::FirstComparator());
        it != end && it->first < end_field_number; ++it) {
-    it->second.SerializeFieldWithCachedSizes(it->first, output);
+    target = it->second.InternalSerializeFieldWithCachedSizesToArray(
+        it->first, target, stream);
   }
+  return target;
+}
+
+uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+    uint8* target, io::EpsCopyOutputStream* stream) const {
+  ForEach([&target, stream](int number, const Extension& ext) {
+    target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
+        number, target, stream);
+  });
+  return target;
 }
 
 size_t ExtensionSet::ByteSize() const {
@@ -1552,115 +1564,6 @@
   }
 }
 
-void ExtensionSet::Extension::SerializeFieldWithCachedSizes(
-    int number, io::CodedOutputStream* output) const {
-  if (is_repeated) {
-    if (is_packed) {
-      if (cached_size == 0) return;
-
-      WireFormatLite::WriteTag(
-          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-      output->WriteVarint32(cached_size);
-
-      switch (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
-  case WireFormatLite::TYPE_##UPPERCASE:                             \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
-      WireFormatLite::Write##CAMELCASE##NoTag(                       \
-          repeated_##LOWERCASE##_value->Get(i), output);             \
-    }                                                                \
-    break
-
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
-        HANDLE_TYPE(FLOAT, Float, float);
-        HANDLE_TYPE(DOUBLE, Double, double);
-        HANDLE_TYPE(BOOL, Bool, bool);
-        HANDLE_TYPE(ENUM, Enum, enum);
-#undef HANDLE_TYPE
-
-        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 (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
-  case WireFormatLite::TYPE_##UPPERCASE:                             \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
-      WireFormatLite::Write##CAMELCASE(                              \
-          number, repeated_##LOWERCASE##_value->Get(i), output);     \
-    }                                                                \
-    break
-
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
-        HANDLE_TYPE(FLOAT, Float, float);
-        HANDLE_TYPE(DOUBLE, Double, double);
-        HANDLE_TYPE(BOOL, Bool, bool);
-        HANDLE_TYPE(STRING, String, string);
-        HANDLE_TYPE(BYTES, Bytes, string);
-        HANDLE_TYPE(ENUM, Enum, enum);
-        HANDLE_TYPE(GROUP, Group, message);
-        HANDLE_TYPE(MESSAGE, Message, message);
-#undef HANDLE_TYPE
-      }
-    }
-  } else if (!is_cleared) {
-    switch (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)             \
-  case WireFormatLite::TYPE_##UPPERCASE:                     \
-    WireFormatLite::Write##CAMELCASE(number, VALUE, output); \
-    break
-
-      HANDLE_TYPE(INT32, Int32, int32_value);
-      HANDLE_TYPE(INT64, Int64, int64_value);
-      HANDLE_TYPE(UINT32, UInt32, uint32_value);
-      HANDLE_TYPE(UINT64, UInt64, uint64_value);
-      HANDLE_TYPE(SINT32, SInt32, int32_value);
-      HANDLE_TYPE(SINT64, SInt64, int64_value);
-      HANDLE_TYPE(FIXED32, Fixed32, uint32_value);
-      HANDLE_TYPE(FIXED64, Fixed64, uint64_value);
-      HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
-      HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
-      HANDLE_TYPE(FLOAT, Float, float_value);
-      HANDLE_TYPE(DOUBLE, Double, double_value);
-      HANDLE_TYPE(BOOL, Bool, bool_value);
-      HANDLE_TYPE(STRING, String, *string_value);
-      HANDLE_TYPE(BYTES, Bytes, *string_value);
-      HANDLE_TYPE(ENUM, Enum, enum_value);
-      HANDLE_TYPE(GROUP, Group, *message_value);
-#undef HANDLE_TYPE
-      case WireFormatLite::TYPE_MESSAGE:
-        if (is_lazy) {
-          lazymessage_value->WriteMessage(number, output);
-        } else {
-          WireFormatLite::WriteMessage(number, *message_value, output);
-        }
-        break;
-    }
-  }
-}
-
 size_t ExtensionSet::Extension::ByteSize(int number) const {
   size_t result = 0;
 
@@ -2025,33 +1928,184 @@
   return instance;
 }
 
-void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
-    int number, io::CodedOutputStream* output) const {
+uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+    int number, uint8* target, io::EpsCopyOutputStream* stream) const {
+  if (is_repeated) {
+    if (is_packed) {
+      if (cached_size == 0) return target;
+
+      stream->EnsureSpace(&target);
+      target = WireFormatLite::WriteTagToArray(
+          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+      target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
+
+      switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      stream->EnsureSpace(&target);                                  \
+      target = WireFormatLite::Write##CAMELCASE##NoTagToArray(       \
+          repeated_##LOWERCASE##_value->Get(i), target);             \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32);
+        HANDLE_TYPE(INT64, Int64, int64);
+        HANDLE_TYPE(UINT32, UInt32, uint32);
+        HANDLE_TYPE(UINT64, UInt64, uint64);
+        HANDLE_TYPE(SINT32, SInt32, int32);
+        HANDLE_TYPE(SINT64, SInt64, int64);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+
+        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 (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      stream->EnsureSpace(&target);                                  \
+      target = WireFormatLite::Write##CAMELCASE##ToArray(            \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+
+        HANDLE_TYPE(INT32, Int32, int32);
+        HANDLE_TYPE(INT64, Int64, int64);
+        HANDLE_TYPE(UINT32, UInt32, uint32);
+        HANDLE_TYPE(UINT64, UInt64, uint64);
+        HANDLE_TYPE(SINT32, SInt32, int32);
+        HANDLE_TYPE(SINT64, SInt64, int64);
+        HANDLE_TYPE(FIXED32, Fixed32, uint32);
+        HANDLE_TYPE(FIXED64, Fixed64, uint64);
+        HANDLE_TYPE(SFIXED32, SFixed32, int32);
+        HANDLE_TYPE(SFIXED64, SFixed64, int64);
+        HANDLE_TYPE(FLOAT, Float, float);
+        HANDLE_TYPE(DOUBLE, Double, double);
+        HANDLE_TYPE(BOOL, Bool, bool);
+        HANDLE_TYPE(ENUM, Enum, enum);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
+  case WireFormatLite::TYPE_##UPPERCASE:                             \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
+      stream->EnsureSpace(&target);                                  \
+      target = stream->WriteString(                                  \
+          number, repeated_##LOWERCASE##_value->Get(i), target);     \
+    }                                                                \
+    break
+        HANDLE_TYPE(STRING, String, string);
+        HANDLE_TYPE(BYTES, Bytes, string);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                     \
+  case WireFormatLite::TYPE_##UPPERCASE:                                 \
+    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {     \
+      stream->EnsureSpace(&target);                                      \
+      target = WireFormatLite::InternalWrite##CAMELCASE##ToArray(        \
+          number, repeated_##LOWERCASE##_value->Get(i), target, stream); \
+    }                                                                    \
+    break
+
+        HANDLE_TYPE(GROUP, Group, message);
+        HANDLE_TYPE(MESSAGE, Message, message);
+#undef HANDLE_TYPE
+      }
+    }
+  } else if (!is_cleared) {
+    switch (real_type(type)) {
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)                               \
+  case WireFormatLite::TYPE_##UPPERCASE:                                       \
+    stream->EnsureSpace(&target);                                              \
+    target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
+    break
+
+      HANDLE_TYPE(INT32, Int32, int32_value);
+      HANDLE_TYPE(INT64, Int64, int64_value);
+      HANDLE_TYPE(UINT32, UInt32, uint32_value);
+      HANDLE_TYPE(UINT64, UInt64, uint64_value);
+      HANDLE_TYPE(SINT32, SInt32, int32_value);
+      HANDLE_TYPE(SINT64, SInt64, int64_value);
+      HANDLE_TYPE(FIXED32, Fixed32, uint32_value);
+      HANDLE_TYPE(FIXED64, Fixed64, uint64_value);
+      HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
+      HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
+      HANDLE_TYPE(FLOAT, Float, float_value);
+      HANDLE_TYPE(DOUBLE, Double, double_value);
+      HANDLE_TYPE(BOOL, Bool, bool_value);
+      HANDLE_TYPE(ENUM, Enum, enum_value);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)         \
+  case WireFormatLite::TYPE_##UPPERCASE:                 \
+    stream->EnsureSpace(&target);                        \
+    target = stream->WriteString(number, VALUE, target); \
+    break
+      HANDLE_TYPE(STRING, String, *string_value);
+      HANDLE_TYPE(BYTES, Bytes, *string_value);
+#undef HANDLE_TYPE
+      case WireFormatLite::TYPE_GROUP:
+        stream->EnsureSpace(&target);
+        target = WireFormatLite::InternalWriteGroupToArray(
+            number, *message_value, target, stream);
+        break;
+      case WireFormatLite::TYPE_MESSAGE:
+        if (is_lazy) {
+          target =
+              lazymessage_value->WriteMessageToArray(number, target, stream);
+        } else {
+          stream->EnsureSpace(&target);
+          target = WireFormatLite::InternalWriteMessageToArray(
+              number, *message_value, target, stream);
+        }
+        break;
+    }
+  }
+  return target;
+}
+
+uint8*
+ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
+    int number, uint8* target, io::EpsCopyOutputStream* stream) const {
   if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
     // Not a valid MessageSet extension, but serialize it the normal way.
-    SerializeFieldWithCachedSizes(number, output);
-    return;
+    GOOGLE_LOG(WARNING) << "Invalid message set extension.";
+    return InternalSerializeFieldWithCachedSizesToArray(number, target, stream);
   }
 
-  if (is_cleared) return;
+  if (is_cleared) return target;
 
+  stream->EnsureSpace(&target);
   // Start group.
-  output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
-
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
   // Write type ID.
-  WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, number,
-                              output);
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, number, target);
   // Write message.
   if (is_lazy) {
-    lazymessage_value->WriteMessage(WireFormatLite::kMessageSetMessageNumber,
-                                    output);
+    target = lazymessage_value->WriteMessageToArray(
+        WireFormatLite::kMessageSetMessageNumber, target, stream);
   } else {
-    WireFormatLite::WriteMessageMaybeToArray(
-        WireFormatLite::kMessageSetMessageNumber, *message_value, output);
+    target = WireFormatLite::InternalWriteMessageToArray(
+        WireFormatLite::kMessageSetMessageNumber, *message_value, target,
+        stream);
   }
-
   // End group.
-  output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
+  stream->EnsureSpace(&target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
 }
 
 size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
@@ -2082,13 +2136,6 @@
   return our_size;
 }
 
-void ExtensionSet::SerializeMessageSetWithCachedSizes(
-    io::CodedOutputStream* output) const {
-  ForEach([output](int number, const Extension& ext) {
-    ext.SerializeMessageSetItemWithCachedSizes(number, output);
-  });
-}
-
 size_t ExtensionSet::MessageSetByteSize() const {
   size_t total_size = 0;
   ForEach([&total_size](int number, const Extension& ext) {
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index a369662..a7de200 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -69,13 +69,9 @@
 class Message;          // message.h
 class MessageFactory;   // message.h
 class UnknownFieldSet;  // unknown_field_set.h
-namespace io {
-class CodedInputStream;   // coded_stream.h
-class CodedOutputStream;  // coded_stream.h
-}  // namespace io
 namespace internal {
 class FieldSkipper;  // wire_format_lite.h
-}
+}  // namespace internal
 }  // namespace protobuf
 }  // namespace google
 
@@ -463,20 +459,28 @@
   // to the output stream, using the cached sizes computed when ByteSize() was
   // last called.  Note that the range bounds are inclusive-exclusive.
   void SerializeWithCachedSizes(int start_field_number, int end_field_number,
-                                io::CodedOutputStream* output) const;
+                                io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeWithCachedSizesToArray(
+        start_field_number, end_field_number, output->Cur(),
+        output->EpsCopy()));
+  }
 
   // Same as SerializeWithCachedSizes, but without any bounds checking.
   // The caller must ensure that target has sufficient capacity for the
   // serialized extensions.
   //
   // Returns a pointer past the last written byte.
-  uint8* InternalSerializeWithCachedSizesToArray(int start_field_number,
-                                                 int end_field_number,
-                                                 uint8* target) const;
+  uint8* InternalSerializeWithCachedSizesToArray(
+      int start_field_number, int end_field_number, uint8* target,
+      io::EpsCopyOutputStream* stream) const;
 
   // Like above but serializes in MessageSet format.
-  void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
-  uint8* InternalSerializeMessageSetWithCachedSizesToArray(uint8* target) const;
+  void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeMessageSetWithCachedSizesToArray(
+        output->Cur(), output->EpsCopy()));
+  }
+  uint8* InternalSerializeMessageSetWithCachedSizesToArray(
+      uint8* target, io::EpsCopyOutputStream* stream) const;
 
   // For backward-compatibility, versions of two of the above methods that
   // serialize deterministically iff SetDefaultSerializationDeterministic()
@@ -540,9 +544,8 @@
 #if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
     virtual const char* _InternalParse(const char* ptr, ParseContext* ctx) = 0;
 #endif
-    virtual void WriteMessage(int number,
-                              io::CodedOutputStream* output) const = 0;
-    virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
+    virtual uint8* WriteMessageToArray(
+        int number, uint8* target, io::EpsCopyOutputStream* stream) const = 0;
 
    private:
     virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
@@ -609,14 +612,10 @@
     const FieldDescriptor* descriptor;
 
     // Some helper methods for operations on a single Extension.
-    void SerializeFieldWithCachedSizes(int number,
-                                       io::CodedOutputStream* output) const;
-    uint8* InternalSerializeFieldWithCachedSizesToArray(int number,
-                                                        uint8* target) const;
-    void SerializeMessageSetItemWithCachedSizes(
-        int number, io::CodedOutputStream* output) const;
+    uint8* InternalSerializeFieldWithCachedSizesToArray(
+        int number, uint8* target, io::EpsCopyOutputStream* stream) const;
     uint8* InternalSerializeMessageSetItemWithCachedSizesToArray(
-        int number, uint8* target) const;
+        int number, uint8* target, io::EpsCopyOutputStream* stream) const;
     size_t ByteSize(int number) const;
     size_t MessageSetItemByteSize(int number) const;
     void Clear();
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 32ca435..36cedd0 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -472,199 +472,12 @@
   return total_size;
 }
 
-// The Serialize*ToArray methods are only needed in the heavy library, as
-// the lite library only generates SerializeWithCachedSizes.
-uint8* ExtensionSet::SerializeWithCachedSizesToArray(int start_field_number,
-                                                     int end_field_number,
-                                                     uint8* target) const {
-  return InternalSerializeWithCachedSizesToArray(start_field_number,
-                                                 end_field_number, target);
-}
-
 uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
     uint8* target) const {
-  return InternalSerializeMessageSetWithCachedSizesToArray(target);
-}
-
-uint8* ExtensionSet::InternalSerializeWithCachedSizesToArray(
-    int start_field_number, int end_field_number, uint8* target) const {
-  if (PROTOBUF_PREDICT_FALSE(is_large())) {
-    const auto& end = map_.large->end();
-    for (auto it = map_.large->lower_bound(start_field_number);
-         it != end && it->first < end_field_number; ++it) {
-      target = it->second.InternalSerializeFieldWithCachedSizesToArray(
-          it->first, target);
-    }
-    return target;
-  }
-  const KeyValue* end = flat_end();
-  for (const KeyValue* it = std::lower_bound(
-           flat_begin(), end, start_field_number, KeyValue::FirstComparator());
-       it != end && it->first < end_field_number; ++it) {
-    target = it->second.InternalSerializeFieldWithCachedSizesToArray(it->first,
-                                                                     target);
-  }
-  return target;
-}
-
-uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
-    uint8* target) const {
-  ForEach([&target](int number, const Extension& ext) {
-    target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(number,
-                                                                       target);
-  });
-  return target;
-}
-
-uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
-    int number, uint8* target) const {
-  if (is_repeated) {
-    if (is_packed) {
-      if (cached_size == 0) return target;
-
-      target = WireFormatLite::WriteTagToArray(
-          number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
-      target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
-
-      switch (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
-  case FieldDescriptor::TYPE_##UPPERCASE:                            \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
-      target = WireFormatLite::Write##CAMELCASE##NoTagToArray(       \
-          repeated_##LOWERCASE##_value->Get(i), target);             \
-    }                                                                \
-    break
-
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
-        HANDLE_TYPE(FLOAT, Float, float);
-        HANDLE_TYPE(DOUBLE, Double, double);
-        HANDLE_TYPE(BOOL, Bool, bool);
-        HANDLE_TYPE(ENUM, Enum, enum);
-#undef HANDLE_TYPE
-
-        case FieldDescriptor::TYPE_STRING:
-        case FieldDescriptor::TYPE_BYTES:
-        case FieldDescriptor::TYPE_GROUP:
-        case FieldDescriptor::TYPE_MESSAGE:
-          GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
-          break;
-      }
-    } else {
-      switch (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
-  case FieldDescriptor::TYPE_##UPPERCASE:                            \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
-      target = WireFormatLite::Write##CAMELCASE##ToArray(            \
-          number, repeated_##LOWERCASE##_value->Get(i), target);     \
-    }                                                                \
-    break
-
-        HANDLE_TYPE(INT32, Int32, int32);
-        HANDLE_TYPE(INT64, Int64, int64);
-        HANDLE_TYPE(UINT32, UInt32, uint32);
-        HANDLE_TYPE(UINT64, UInt64, uint64);
-        HANDLE_TYPE(SINT32, SInt32, int32);
-        HANDLE_TYPE(SINT64, SInt64, int64);
-        HANDLE_TYPE(FIXED32, Fixed32, uint32);
-        HANDLE_TYPE(FIXED64, Fixed64, uint64);
-        HANDLE_TYPE(SFIXED32, SFixed32, int32);
-        HANDLE_TYPE(SFIXED64, SFixed64, int64);
-        HANDLE_TYPE(FLOAT, Float, float);
-        HANDLE_TYPE(DOUBLE, Double, double);
-        HANDLE_TYPE(BOOL, Bool, bool);
-        HANDLE_TYPE(STRING, String, string);
-        HANDLE_TYPE(BYTES, Bytes, string);
-        HANDLE_TYPE(ENUM, Enum, enum);
-#undef HANDLE_TYPE
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                 \
-  case FieldDescriptor::TYPE_##UPPERCASE:                            \
-    for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
-      target = WireFormatLite::InternalWrite##CAMELCASE##ToArray(    \
-          number, repeated_##LOWERCASE##_value->Get(i), target);     \
-    }                                                                \
-    break
-
-        HANDLE_TYPE(GROUP, Group, message);
-        HANDLE_TYPE(MESSAGE, Message, message);
-#undef HANDLE_TYPE
-      }
-    }
-  } else if (!is_cleared) {
-    switch (real_type(type)) {
-#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE)                               \
-  case FieldDescriptor::TYPE_##UPPERCASE:                                      \
-    target = WireFormatLite::Write##CAMELCASE##ToArray(number, VALUE, target); \
-    break
-
-      HANDLE_TYPE(INT32, Int32, int32_value);
-      HANDLE_TYPE(INT64, Int64, int64_value);
-      HANDLE_TYPE(UINT32, UInt32, uint32_value);
-      HANDLE_TYPE(UINT64, UInt64, uint64_value);
-      HANDLE_TYPE(SINT32, SInt32, int32_value);
-      HANDLE_TYPE(SINT64, SInt64, int64_value);
-      HANDLE_TYPE(FIXED32, Fixed32, uint32_value);
-      HANDLE_TYPE(FIXED64, Fixed64, uint64_value);
-      HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
-      HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
-      HANDLE_TYPE(FLOAT, Float, float_value);
-      HANDLE_TYPE(DOUBLE, Double, double_value);
-      HANDLE_TYPE(BOOL, Bool, bool_value);
-      HANDLE_TYPE(STRING, String, *string_value);
-      HANDLE_TYPE(BYTES, Bytes, *string_value);
-      HANDLE_TYPE(ENUM, Enum, enum_value);
-      HANDLE_TYPE(GROUP, Group, *message_value);
-#undef HANDLE_TYPE
-      case FieldDescriptor::TYPE_MESSAGE:
-        if (is_lazy) {
-          target = lazymessage_value->WriteMessageToArray(number, target);
-        } else {
-          target = WireFormatLite::InternalWriteMessageToArray(
-              number, *message_value, target);
-        }
-        break;
-    }
-  }
-  return target;
-}
-
-uint8*
-ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
-    int number, uint8* target) const {
-  if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
-    // Not a valid MessageSet extension, but serialize it the normal way.
-    GOOGLE_LOG(WARNING) << "Invalid message set extension.";
-    return InternalSerializeFieldWithCachedSizesToArray(number, target);
-  }
-
-  if (is_cleared) return target;
-
-  // Start group.
-  target = io::CodedOutputStream::WriteTagToArray(
-      WireFormatLite::kMessageSetItemStartTag, target);
-  // Write type ID.
-  target = WireFormatLite::WriteUInt32ToArray(
-      WireFormatLite::kMessageSetTypeIdNumber, number, target);
-  // Write message.
-  if (is_lazy) {
-    target = lazymessage_value->WriteMessageToArray(
-        WireFormatLite::kMessageSetMessageNumber, target);
-  } else {
-    target = WireFormatLite::InternalWriteMessageToArray(
-        WireFormatLite::kMessageSetMessageNumber, *message_value, target);
-  }
-  // End group.
-  target = io::CodedOutputStream::WriteTagToArray(
-      WireFormatLite::kMessageSetItemEndTag, target);
-  return target;
+  io::EpsCopyOutputStream stream(
+      target, MessageSetByteSize(),
+      io::CodedOutputStream::IsDefaultSerializationDeterministic());
+  return InternalSerializeMessageSetWithCachedSizesToArray(target, &stream);
 }
 
 bool ExtensionSet::ParseFieldMaybeLazily(
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index ca88d38..5761909 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -236,48 +235,26 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FieldMask::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FieldMask)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated string paths = 1;
-  for (int i = 0, n = this->paths_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->paths(i).data(), static_cast<int>(this->paths(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.FieldMask.paths");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      1, this->paths(i), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FieldMask)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FieldMask::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated string paths = 1;
-  for (int i = 0, n = this->paths_size(); i < n; i++) {
+  for (auto it = this->paths().pointer_begin(),
+            end = this->paths().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->paths(i).data(), static_cast<int>(this->paths(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.FieldMask.paths");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(1, this->paths(i), target);
+    target = stream->WriteString(1, s, target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FieldMask)
   return target;
@@ -287,11 +264,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -304,6 +276,10 @@
       this->paths(i));
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index 0e3c58e..44160db 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -156,10 +156,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index e5718a3..f7e6ed3 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1701,7 +1701,9 @@
                                           int ctype,
                                           const Descriptor* desc) const {
   USAGE_CHECK_REPEATED("MutableRawRepeatedField");
-  if (field->cpp_type() != cpptype)
+  if (field->cpp_type() != cpptype &&
+      (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM ||
+       cpptype != FieldDescriptor::CPPTYPE_INT32))
     ReportReflectionUsageTypeError(descriptor_, field,
                                    "MutableRawRepeatedField", cpptype);
   if (desc != nullptr)
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 36d7307..6cf87aa 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -299,15 +299,11 @@
 }
 
 void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
-  if (output->is_deterministic) {
-    io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
-    io::CodedOutputStream o(&array_stream);
-    o.SetSerializationDeterministic(true);
-    msg->SerializeWithCachedSizes(&o);
-    output->ptr += o.ByteCount();
-  } else {
-    output->ptr = msg->InternalSerializeWithCachedSizesToArray(output->ptr);
-  }
+  io::ArrayOutputStream array_stream(output->ptr, INT_MAX);
+  io::CodedOutputStream o(&array_stream);
+  o.SetSerializationDeterministic(output->is_deterministic);
+  msg->SerializeWithCachedSizes(&o);
+  output->ptr += o.ByteCount();
 }
 
 // Helper to branch to fast path if possible
@@ -316,16 +312,6 @@
                               int32 cached_size,
                               io::CodedOutputStream* output) {
   const uint8* base = reinterpret_cast<const uint8*>(&msg);
-  if (!output->IsSerializationDeterministic()) {
-    // Try the fast path
-    uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size);
-    if (ptr) {
-      // We use virtual dispatch to enable dedicated generated code for the
-      // fast path.
-      msg.InternalSerializeWithCachedSizesToArray(ptr);
-      return;
-    }
-  }
   SerializeInternal(base, field_table, num_fields, output);
 }
 
diff --git a/src/google/protobuf/implicit_weak_message.h b/src/google/protobuf/implicit_weak_message.h
index cab5df9..a0cb1c1 100644
--- a/src/google/protobuf/implicit_weak_message.h
+++ b/src/google/protobuf/implicit_weak_message.h
@@ -84,8 +84,10 @@
 
   size_t ByteSizeLong() const override { return data_.size(); }
 
-  void SerializeWithCachedSizes(io::CodedOutputStream* output) const override {
-    output->WriteString(data_);
+  uint8* InternalSerializeWithCachedSizesToArray(
+      uint8* target, io::EpsCopyOutputStream* stream) const final {
+    return stream->WriteRaw(data_.data(), static_cast<int>(data_.size()),
+                            target);
   }
 
   int GetCachedSize() const override { return static_cast<int>(data_.size()); }
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 6aaaa0b..f04dc1d 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -38,9 +38,14 @@
 // will not cross the end of the buffer, since we can avoid a lot
 // of branching in this case.
 
+#include <google/protobuf/io/coded_stream.h>
+
 #include <limits.h>
+
 #include <algorithm>
+#include <cstring>
 #include <utility>
+
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream_inl.h>
@@ -84,10 +89,6 @@
 int CodedInputStream::default_recursion_limit_ = 100;
 
 
-void CodedOutputStream::EnableAliasing(bool enabled) {
-  aliasing_enabled_ = enabled && output_->AllowsAliasing();
-}
-
 void CodedInputStream::BackUpInputToCurrentPosition() {
   int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
   if (backup_bytes > 0) {
@@ -637,152 +638,283 @@
 
 // CodedOutputStream =================================================
 
+void EpsCopyOutputStream::EnableAliasing(bool enabled) {
+  aliasing_enabled_ = enabled && stream_->AllowsAliasing();
+}
+
+int64 EpsCopyOutputStream::ByteCount(uint8* ptr) const {
+  // Calculate the current offset relative to the end of the stream buffer.
+  int delta = (end_ - ptr) + (buffer_end_ ? 0 : kSlopBytes);
+  return stream_->ByteCount() - delta;
+}
+
+// Flushes what's written out to the underlying ZeroCopyOutputStream buffers.
+// Returns the size remaining in the buffer and sets buffer_end_ to the start
+// of the remaining buffer, ie. [buffer_end_, buffer_end_ + return value)
+int EpsCopyOutputStream::Flush(uint8* ptr) {
+  while (buffer_end_ && ptr > end_) {
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(!had_error_);
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+    if (had_error_) return 0;
+  }
+  int s;
+  if (buffer_end_) {
+    std::memcpy(buffer_end_, buffer_, ptr - buffer_);
+    buffer_end_ += ptr - buffer_;
+    s = end_ - ptr;
+  } else {
+    // The stream is writing directly in the ZeroCopyOutputStream buffer.
+    s = end_ + kSlopBytes - ptr;
+    buffer_end_ = ptr;
+  }
+  GOOGLE_DCHECK(s >= 0);  // NOLINT
+  return s;
+}
+
+uint8* EpsCopyOutputStream::Trim(uint8* ptr) {
+  if (had_error_) return ptr;
+  int s = Flush(ptr);
+  if (s) stream_->BackUp(s);
+  // Reset to initial state (expecting new buffer)
+  buffer_end_ = end_ = buffer_;
+  return buffer_;
+}
+
+
+uint8* EpsCopyOutputStream::FlushAndResetBuffer(uint8* ptr) {
+  if (had_error_) return buffer_;
+  int s = Flush(ptr);
+  if (had_error_) return buffer_;
+  return SetInitialBuffer(buffer_end_, s);
+}
+
+bool EpsCopyOutputStream::Skip(int count, uint8** pp) {
+  if (count < 0) return false;
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  int size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  void* data = buffer_end_;
+  while (count > size) {
+    count -= size;
+    if (!stream_->Next(&data, &size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(static_cast<uint8*>(data) + count, size - count);
+  return true;
+}
+
+bool EpsCopyOutputStream::GetDirectBufferPointer(void** data, int* size,
+                                                 uint8** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *size = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return false;
+  }
+  *data = buffer_end_;
+  while (*size == 0) {
+    if (!stream_->Next(data, size)) {
+      *pp = Error();
+      return false;
+    }
+  }
+  *pp = SetInitialBuffer(*data, *size);
+  return true;
+}
+
+uint8* EpsCopyOutputStream::GetDirectBufferForNBytesAndAdvance(int size,
+                                                               uint8** pp) {
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  int s = Flush(*pp);
+  if (had_error_) {
+    *pp = buffer_;
+    return nullptr;
+  }
+  if (s >= size) {
+    auto res = buffer_end_;
+    *pp = SetInitialBuffer(buffer_end_ + size, s - size);
+    return res;
+  } else {
+    *pp = SetInitialBuffer(buffer_end_, s);
+    return nullptr;
+  }
+}
+
+uint8* EpsCopyOutputStream::Next() {
+  GOOGLE_DCHECK(!had_error_);  // NOLINT
+  if (PROTOBUF_PREDICT_FALSE(stream_ == nullptr)) return Error();
+  if (buffer_end_) {
+    // We're in the patch buffer and need to fill up the previous buffer.
+    std::memcpy(buffer_end_, buffer_, end_ - buffer_);
+    uint8* ptr;
+    int size;
+    do {
+      void* data;
+      if (PROTOBUF_PREDICT_FALSE(!stream_->Next(&data, &size))) {
+        // Stream has an error, we use the patch buffer to continue to be
+        // able to write.
+        return Error();
+      }
+      ptr = static_cast<uint8*>(data);
+    } while (size == 0);
+    if (PROTOBUF_PREDICT_TRUE(size > kSlopBytes)) {
+      std::memcpy(ptr, end_, kSlopBytes);
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      GOOGLE_DCHECK(size > 0);  // NOLINT
+      // Buffer to small
+      std::memmove(buffer_, end_, kSlopBytes);
+      buffer_end_ = ptr;
+      end_ = buffer_ + size;
+      return buffer_;
+    }
+  } else {
+    std::memcpy(buffer_, end_, kSlopBytes);
+    buffer_end_ = end_;
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+}
+
+uint8* EpsCopyOutputStream::EnsureSpaceFallback(uint8* ptr) {
+  do {
+    if (PROTOBUF_PREDICT_FALSE(had_error_)) return buffer_;
+    int overrun = ptr - end_;
+    GOOGLE_DCHECK(overrun >= 0);           // NOLINT
+    GOOGLE_DCHECK(overrun <= kSlopBytes);  // NOLINT
+    ptr = Next() + overrun;
+  } while (ptr >= end_);
+  GOOGLE_DCHECK(ptr < end_);  // NOLINT
+  return ptr;
+}
+
+uint8* EpsCopyOutputStream::WriteRawFallback(const void* data, int size,
+                                             uint8* ptr) {
+  int s = GetSize(ptr);
+  while (s < size) {
+    std::memcpy(ptr, data, s);
+    size -= s;
+    data = static_cast<const uint8*>(data) + s;
+    ptr = EnsureSpaceFallback(ptr + s);
+    s = GetSize(ptr);
+  }
+  std::memcpy(ptr, data, size);
+  return ptr + size;
+}
+
+uint8* EpsCopyOutputStream::WriteAliasedRaw(const void* data, int size,
+                                            uint8* ptr) {
+  if (size < GetSize(ptr)
+  ) {
+    return WriteRaw(data, size, ptr);
+  } else {
+    ptr = Trim(ptr);
+    if (stream_->WriteAliasedRaw(data, size)) return ptr;
+    return Error();
+  }
+}
+
+#ifndef PROTOBUF_LITTLE_ENDIAN
+uint8* EpsCopyOutputStream::WriteRawLittleEndian32(const void* data, int size,
+                                                   uint8* ptr) {
+  auto p = static_cast<const uint8*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    EnsureSpace(&ptr);
+    uint32 buffer[4];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian32ToArray(x, ptr);
+  }
+  while (p < end) {
+    EnsureSpace(&ptr);
+    uint32 buffer;
+    std::memcpy(&buffer, p, 4);
+    p += 4;
+    ptr = CodedOutputStream::WriteLittleEndian32ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+
+uint8* EpsCopyOutputStream::WriteRawLittleEndian64(const void* data, int size,
+                                                   uint8* ptr) {
+  auto p = static_cast<const uint8*>(data);
+  auto end = p + size;
+  while (end - p >= kSlopBytes) {
+    EnsureSpace(&ptr);
+    uint64 buffer[2];
+    static_assert(sizeof(buffer) == kSlopBytes, "Buffer must be kSlopBytes");
+    std::memcpy(buffer, p, kSlopBytes);
+    p += kSlopBytes;
+    for (auto x : buffer)
+      ptr = CodedOutputStream::WriteLittleEndian64ToArray(x, ptr);
+  }
+  while (p < end) {
+    EnsureSpace(&ptr);
+    uint64 buffer;
+    std::memcpy(&buffer, p, 8);
+    p += 8;
+    ptr = CodedOutputStream::WriteLittleEndian64ToArray(buffer, ptr);
+  }
+  return ptr;
+}
+#endif
+
+
+uint8* EpsCopyOutputStream::WriteStringMaybeAliasedOutline(uint32 num,
+                                                           const std::string& s,
+                                                           uint8* ptr) {
+  EnsureSpace(&ptr);
+  uint32 size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRawMaybeAliased(s.data(), size, ptr);
+}
+
+uint8* EpsCopyOutputStream::WriteStringOutline(uint32 num, const std::string& s,
+                                               uint8* ptr) {
+  EnsureSpace(&ptr);
+  uint32 size = s.size();
+  ptr = WriteLengthDelim(num, size, ptr);
+  return WriteRaw(s.data(), size, ptr);
+}
+
 std::atomic<bool> CodedOutputStream::default_serialization_deterministic_{
     false};
 
-CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
-    : CodedOutputStream(output, true) {}
-
-CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output,
+CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* stream,
                                      bool do_eager_refresh)
-    : output_(output),
-      buffer_(NULL),
-      buffer_size_(0),
-      total_bytes_(0),
-      had_error_(false),
-      aliasing_enabled_(false),
-      is_serialization_deterministic_(IsDefaultSerializationDeterministic()) {
+    : impl_(stream, IsDefaultSerializationDeterministic(), &cur_),
+      start_count_(stream->ByteCount()) {
   if (do_eager_refresh) {
-    // Eagerly Refresh() so buffer space is immediately available.
-    Refresh();
-    // The Refresh() may have failed. If the client doesn't write any data,
-    // though, don't consider this an error. If the client does write data, then
-    // another Refresh() will be attempted and it will set the error once again.
-    had_error_ = false;
+    void* data;
+    int size;
+    if (!stream->Next(&data, &size) || size == 0) return;
+    cur_ = impl_.SetInitialBuffer(data, size);
   }
 }
 
 CodedOutputStream::~CodedOutputStream() { Trim(); }
 
-void CodedOutputStream::Trim() {
-  if (buffer_size_ > 0) {
-    output_->BackUp(buffer_size_);
-    total_bytes_ -= buffer_size_;
-    buffer_size_ = 0;
-    buffer_ = NULL;
-  }
-}
-
-bool CodedOutputStream::Skip(int count) {
-  if (count < 0) return false;
-
-  while (count > buffer_size_) {
-    count -= buffer_size_;
-    if (!Refresh()) return false;
-  }
-
-  Advance(count);
-  return true;
-}
-
-bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
-  if (buffer_size_ == 0 && !Refresh()) return false;
-
-  *data = buffer_;
-  *size = buffer_size_;
-  return true;
-}
-
-void CodedOutputStream::WriteRaw(const void* data, int size) {
-  while (buffer_size_ < size) {
-    memcpy(buffer_, data, buffer_size_);
-    size -= buffer_size_;
-    data = reinterpret_cast<const uint8*>(data) + buffer_size_;
-    if (!Refresh()) return;
-  }
-
-  memcpy(buffer_, data, size);
-  Advance(size);
-}
-
-uint8* CodedOutputStream::WriteRawToArray(const void* data, int size,
-                                          uint8* target) {
-  memcpy(target, data, size);
-  return target + size;
-}
-
-
-void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
-  if (size < buffer_size_
-  ) {
-    WriteRaw(data, size);
-  } else {
-    Trim();
-
-    total_bytes_ += size;
-    had_error_ |= !output_->WriteAliasedRaw(data, size);
-  }
-}
-
-void CodedOutputStream::WriteLittleEndian32(uint32 value) {
-  uint8 bytes[sizeof(value)];
-
-  bool use_fast = buffer_size_ >= sizeof(value);
-  uint8* ptr = use_fast ? buffer_ : bytes;
-
-  WriteLittleEndian32ToArray(value, ptr);
-
-  if (use_fast) {
-    Advance(sizeof(value));
-  } else {
-    WriteRaw(bytes, sizeof(value));
-  }
-}
-
-void CodedOutputStream::WriteLittleEndian64(uint64 value) {
-  uint8 bytes[sizeof(value)];
-
-  bool use_fast = buffer_size_ >= sizeof(value);
-  uint8* ptr = use_fast ? buffer_ : bytes;
-
-  WriteLittleEndian64ToArray(value, ptr);
-
-  if (use_fast) {
-    Advance(sizeof(value));
-  } else {
-    WriteRaw(bytes, sizeof(value));
-  }
-}
-
-void CodedOutputStream::WriteVarint32SlowPath(uint32 value) {
-  uint8 bytes[kMaxVarint32Bytes];
-  uint8* target = &bytes[0];
-  uint8* end = WriteVarint32ToArray(value, target);
-  int size = end - target;
-  WriteRaw(bytes, size);
-}
-
-void CodedOutputStream::WriteVarint64SlowPath(uint64 value) {
-  uint8 bytes[kMaxVarintBytes];
-  uint8* target = &bytes[0];
-  uint8* end = WriteVarint64ToArray(value, target);
-  int size = end - target;
-  WriteRaw(bytes, size);
-}
-
-bool CodedOutputStream::Refresh() {
-  void* void_buffer;
-  if (output_->Next(&void_buffer, &buffer_size_)) {
-    buffer_ = reinterpret_cast<uint8*>(void_buffer);
-    total_bytes_ += buffer_size_;
-    return true;
-  } else {
-    buffer_ = NULL;
-    buffer_size_ = 0;
-    had_error_ = true;
-    return false;
-  }
-}
 
 uint8* CodedOutputStream::WriteStringWithSizeToArray(const std::string& str,
                                                      uint8* target) {
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index 89ae74d..c620d89 100755
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -110,10 +110,15 @@
 #define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__
 
 #include <assert.h>
+
 #include <atomic>
 #include <climits>
+#include <cstddef>
+#include <cstring>
 #include <string>
+#include <type_traits>
 #include <utility>
+
 #ifdef _MSC_VER
 // Assuming windows is always little-endian.
 #if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST)
@@ -133,7 +138,9 @@
 #endif
 #endif
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/port.h>
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/port.h>
 
 
@@ -644,6 +651,384 @@
   friend class google::protobuf::internal::EpsCopyByteStream;
 };
 
+// EpsCopyOutputStream wraps a ZeroCopyOutputStream and exposes a new stream,
+// which has the property you can write kSlopBytes (16 bytes) from the current
+// position without bounds checks. The cursor into the stream is managed by
+// the user of the class and is an explicit parameter in the methods. Careful
+// use of this class, ie. keep ptr a local variable, eliminates the need to
+// for the compiler to sync the ptr value between register and memory.
+class PROTOBUF_EXPORT EpsCopyOutputStream {
+ public:
+  enum { kSlopBytes = 16 };
+
+  // Initialize from a stream.
+  EpsCopyOutputStream(ZeroCopyOutputStream* stream, bool deterministic,
+                      uint8** pp)
+      : end_(buffer_),
+        stream_(stream),
+        is_serialization_deterministic_(deterministic) {
+    *pp = buffer_;
+  }
+
+  // Only for array serialization. No overflow protection, end_ will be the
+  // pointed to the end of the array. When using this the total size is already
+  // known, so no need to maintain the slop region.
+  EpsCopyOutputStream(void* data, int size, bool deterministic)
+      : end_(static_cast<uint8*>(data) + size),
+        buffer_end_(nullptr),
+        stream_(nullptr),
+        is_serialization_deterministic_(deterministic) {}
+
+  // Initialize from stream but with the first buffer already given (eager).
+  EpsCopyOutputStream(void* data, int size, ZeroCopyOutputStream* stream,
+                      bool deterministic, uint8** pp)
+      : stream_(stream), is_serialization_deterministic_(deterministic) {
+    *pp = SetInitialBuffer(data, size);
+  }
+
+  // Flush everything that's written into the underlying ZeroCopyOutputStream
+  // and trims the underlying stream to the location of ptr.
+  uint8* Trim(uint8* ptr);
+
+  // After this it's guaranteed you can safely write kSlopBytes to ptr. This
+  // will never fail! The underlying stream can produce an error. Use HadError
+  // to check for errors.
+  void EnsureSpace(uint8** ptr) {
+    if (PROTOBUF_PREDICT_FALSE(*ptr >= end_)) {
+      *ptr = EnsureSpaceFallback(*ptr);
+    }
+  }
+
+  uint8* WriteRaw(const void* data, int size, uint8* ptr) {
+    if (PROTOBUF_PREDICT_FALSE(end_ - ptr < size)) {
+      return WriteRawFallback(data, size, ptr);
+    }
+    std::memcpy(ptr, data, size);
+    return ptr + size;
+  }
+  // Writes the buffer specified by data, size to the stream. Possibly by
+  // aliasing the buffer (ie. not copying the data). The caller is responsible
+  // to make sure the buffer is alive for the duration of the
+  // ZeroCopyOutputStream.
+  uint8* WriteRawMaybeAliased(const void* data, int size, uint8* ptr) {
+    if (aliasing_enabled_) {
+      return WriteAliasedRaw(data, size, ptr);
+    } else {
+      return WriteRaw(data, size, ptr);
+    }
+  }
+
+
+  uint8* WriteStringMaybeAliased(uint32 num, const std::string& s, uint8* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringMaybeAliasedOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  uint8* WriteBytesMaybeAliased(uint32 num, const std::string& s, uint8* ptr) {
+    return WriteStringMaybeAliased(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteString(uint32 num, const T& s,
+                                            uint8* ptr) {
+    std::ptrdiff_t size = s.size();
+    if (PROTOBUF_PREDICT_FALSE(
+            size >= 128 || end_ - ptr + 16 - TagSize(num << 3) - 1 < size)) {
+      return WriteStringOutline(num, s, ptr);
+    }
+    ptr = UnsafeVarint((num << 3) | 2, ptr);
+    *ptr++ = static_cast<uint8>(size);
+    std::memcpy(ptr, s.data(), size);
+    return ptr + size;
+  }
+  template <typename T>
+  uint8* WriteBytes(uint32 num, const T& s, uint8* ptr) {
+    return WriteString(num, s, ptr);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteInt32Packed(int num, const T& r, int size,
+                                                 uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteUInt32Packed(int num, const T& r, int size,
+                                                  uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteSInt32Packed(int num, const T& r, int size,
+                                                  uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode32);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteInt64Packed(int num, const T& r, int size,
+                                                 uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteUInt64Packed(int num, const T& r, int size,
+                                                  uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteSInt64Packed(int num, const T& r, int size,
+                                                  uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, ZigZagEncode64);
+  }
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteEnumPacked(int num, const T& r, int size,
+                                                uint8* ptr) {
+    return WriteVarintPacked(num, r, size, ptr, Encode64);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteFixedPacked(int num, const T& r,
+                                                 uint8* ptr) {
+    EnsureSpace(&ptr);
+    constexpr auto element_size = sizeof(typename T::value_type);
+    auto size = r.size() * element_size;
+    ptr = WriteLengthDelim(num, size, ptr);
+    return WriteRawLittleEndian<element_size>(r.data(), static_cast<int>(size),
+                                              ptr);
+  }
+
+  // Returns true if there was an underlying I/O error since this object was
+  // created.
+  bool HadError() const { return had_error_; }
+
+  // Instructs the EpsCopyOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled);
+
+  // Deterministic serialization, if requested, guarantees that for a given
+  // binary, equal messages will always be serialized to the same bytes. This
+  // implies:
+  //   . repeated serialization of a message will return the same bytes
+  //   . different processes of the same binary (which may be executing on
+  //     different machines) will serialize equal messages to the same bytes.
+  //
+  // Note the deterministic serialization is NOT canonical across languages; it
+  // is also unstable across different builds with schema changes due to unknown
+  // fields. Users who need canonical serialization, e.g., persistent storage in
+  // a canonical form, fingerprinting, etc., should define their own
+  // canonicalization specification and implement the serializer using
+  // reflection APIs rather than relying on this API.
+  //
+  // If deterministic serialization is requested, the serializer will
+  // sort map entries by keys in lexicographical order or numerical order.
+  // (This is an implementation detail and may subject to change.)
+  //
+  // There are two ways to determine whether serialization should be
+  // deterministic for this CodedOutputStream.  If SetSerializationDeterministic
+  // has not yet been called, then the default comes from the global default,
+  // which is false, until SetDefaultSerializationDeterministic has been called.
+  // Otherwise, SetSerializationDeterministic has been called, and the last
+  // value passed to it is all that matters.
+  void SetSerializationDeterministic(bool value) {
+    is_serialization_deterministic_ = value;
+  }
+  // See above.  Also, note that users of this CodedOutputStream may need to
+  // call IsSerializationDeterministic() to serialize in the intended way.  This
+  // CodedOutputStream cannot enforce a desire for deterministic serialization
+  // by itself.
+  bool IsSerializationDeterministic() const {
+    return is_serialization_deterministic_;
+  }
+
+  // The number of bytes writen to the stream at position ptr, relative to the
+  // stream's overall position.
+  int64 ByteCount(uint8* ptr) const;
+
+
+ private:
+  uint8* end_;
+  uint8* buffer_end_ = buffer_;
+  uint8 buffer_[2 * kSlopBytes];
+  ZeroCopyOutputStream* stream_;
+  bool had_error_ = false;
+  bool aliasing_enabled_ = false;  // See EnableAliasing().
+  bool is_serialization_deterministic_;
+
+  uint8* EnsureSpaceFallback(uint8* ptr);
+  inline uint8* Next();
+  int Flush(uint8* ptr);
+  std::ptrdiff_t GetSize(uint8* ptr) const {
+    GOOGLE_DCHECK(ptr <= end_ + kSlopBytes);  // NOLINT
+    return end_ + kSlopBytes - ptr;
+  }
+
+  uint8* Error() {
+    had_error_ = true;
+    // We use the patch buffer to always guarantee space to write to.
+    end_ = buffer_ + kSlopBytes;
+    return buffer_;
+  }
+
+  static constexpr int TagSize(uint32 tag) {
+    return (tag < (1 << 7))
+               ? 1
+               : (tag < (1 << 14))
+                     ? 2
+                     : (tag < (1 << 21)) ? 3 : (tag < (1 << 28)) ? 4 : 5;
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8* WriteTag(uint32 num, uint32 wt, uint8* ptr) {
+    GOOGLE_DCHECK(ptr < end_);  // NOLINT
+    return UnsafeVarint((num << 3) | wt, ptr);
+  }
+
+  PROTOBUF_ALWAYS_INLINE uint8* WriteLengthDelim(int num, uint32 size,
+                                                 uint8* ptr) {
+    ptr = WriteTag(num, 2, ptr);
+    return UnsafeWriteSize(size, ptr);
+  }
+
+  uint8* WriteRawFallback(const void* data, int size, uint8* ptr);
+
+  uint8* WriteAliasedRaw(const void* data, int size, uint8* ptr);
+
+  uint8* WriteStringMaybeAliasedOutline(uint32 num, const std::string& s,
+                                        uint8* ptr);
+  uint8* WriteStringOutline(uint32 num, const std::string& s, uint8* ptr);
+
+  template <typename T, typename E>
+  PROTOBUF_ALWAYS_INLINE uint8* WriteVarintPacked(int num, const T& r, int size,
+                                                  uint8* ptr, const E& encode) {
+    EnsureSpace(&ptr);
+    ptr = WriteLengthDelim(num, size, ptr);
+    auto it = r.data();
+    auto end = it + r.size();
+    do {
+      EnsureSpace(&ptr);
+      ptr = UnsafeVarint(encode(*it++), ptr);
+    } while (it < end);
+    return ptr;
+  }
+
+  static uint32 Encode32(uint32 v) { return v; }
+  static uint64 Encode64(uint64 v) { return v; }
+  static uint32 ZigZagEncode32(int32 v) {
+    return (static_cast<uint32>(v) << 1) ^ static_cast<uint32>(v >> 31);
+  }
+  static uint64 ZigZagEncode64(int64 v) {
+    return (static_cast<uint64>(v) << 1) ^ static_cast<uint64>(v >> 63);
+  }
+
+  template <typename T>
+  PROTOBUF_ALWAYS_INLINE static uint8* UnsafeVarint(T value, uint8* ptr) {
+    static_assert(std::is_unsigned<T>::value,
+                  "Varint serialization must be unsigned");
+    if (value < 0x80) {
+      ptr[0] = static_cast<uint8>(value);
+      return ptr + 1;
+    }
+    ptr[0] = static_cast<uint8>(value | 0x80);
+    value >>= 7;
+    if (value < 0x80) {
+      ptr[1] = static_cast<uint8>(value);
+      return ptr + 2;
+    }
+    ptr++;
+    do {
+      *ptr = static_cast<uint8>(value | 0x80);
+      value >>= 7;
+      ++ptr;
+    } while (PROTOBUF_PREDICT_FALSE(value >= 0x80));
+    *ptr++ = static_cast<uint8>(value);
+    return ptr;
+  }
+
+  PROTOBUF_ALWAYS_INLINE static uint8* UnsafeWriteSize(uint32 value,
+                                                       uint8* ptr) {
+    while (PROTOBUF_PREDICT_FALSE(value >= 0x80)) {
+      *ptr = static_cast<uint8>(value | 0x80);
+      value >>= 7;
+      ++ptr;
+    }
+    *ptr++ = static_cast<uint8>(value);
+    return ptr;
+  }
+
+  template <int S>
+  uint8* WriteRawLittleEndian(const void* data, int size, uint8* ptr);
+#ifndef PROTOBUF_LITTLE_ENDIAN
+  uint8* WriteRawLittleEndian32(const void* data, int size, uint8* ptr);
+  uint8* WriteRawLittleEndian64(const void* data, int size, uint8* ptr);
+#endif
+
+  // These methods are for CodedOutputStream. Ideally they should be private
+  // but to match current behavior of CodedOutputStream as close as possible
+  // we allow it some functionality.
+ public:
+  uint8* SetInitialBuffer(void* data, int size) {
+    auto ptr = static_cast<uint8*>(data);
+    if (size > kSlopBytes) {
+      end_ = ptr + size - kSlopBytes;
+      buffer_end_ = nullptr;
+      return ptr;
+    } else {
+      end_ = buffer_ + size;
+      buffer_end_ = ptr;
+      return buffer_;
+    }
+  }
+
+ private:
+  // Needed by CodedOutputStream HadError. HadError needs to flush the patch
+  // buffers to ensure there is no error as of yet.
+  uint8* FlushAndResetBuffer(uint8*);
+
+  // The following functions mimick the old CodedOutputStream behavior as close
+  // as possible. They flush the current state to the stream, behave as
+  // the old CodedOutputStream and then return to normal operation.
+  bool Skip(int count, uint8** pp);
+  bool GetDirectBufferPointer(void** data, int* size, uint8** pp);
+  uint8* GetDirectBufferForNBytesAndAdvance(int size, uint8** pp);
+
+  friend class CodedOutputStream;
+};
+
+template <>
+inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<1>(const void* data,
+                                                           int size,
+                                                           uint8* ptr) {
+  return WriteRaw(data, size, ptr);
+}
+template <>
+inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<4>(const void* data,
+                                                           int size,
+                                                           uint8* ptr) {
+#ifdef PROTOBUF_LITTLE_ENDIAN
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian32(data, size, ptr);
+#endif
+}
+template <>
+inline uint8* EpsCopyOutputStream::WriteRawLittleEndian<8>(const void* data,
+                                                           int size,
+                                                           uint8* ptr) {
+#ifdef PROTOBUF_LITTLE_ENDIAN
+  return WriteRaw(data, size, ptr);
+#else
+  return WriteRawLittleEndian64(data, size, ptr);
+#endif
+}
+
 // Class which encodes and writes binary data which is composed of varint-
 // encoded integers and fixed-width pieces.  Wraps a ZeroCopyOutputStream.
 // Most users will not need to deal with CodedOutputStream.
@@ -674,7 +1059,7 @@
 //
 //   uint8* buffer =
 //       coded_output->GetDirectBufferForNBytesAndAdvance(coded_size);
-//   if (buffer != NULL) {
+//   if (buffer != nullptr) {
 //     // The output stream has enough space in the buffer: write directly to
 //     // the array.
 //     buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number,
@@ -693,19 +1078,29 @@
 class PROTOBUF_EXPORT CodedOutputStream {
  public:
   // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream.
-  explicit CodedOutputStream(ZeroCopyOutputStream* output);
-  CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh);
+  explicit CodedOutputStream(ZeroCopyOutputStream* stream)
+      : CodedOutputStream(stream, true) {}
+  CodedOutputStream(ZeroCopyOutputStream* stream, bool do_eager_refresh);
 
   // Destroy the CodedOutputStream and position the underlying
   // ZeroCopyOutputStream immediately after the last byte written.
   ~CodedOutputStream();
 
+  // Returns true if there was an underlying I/O error since this object was
+  // created. On should call Trim before this function in order to catch all
+  // errors.
+  bool HadError() {
+    cur_ = impl_.FlushAndResetBuffer(cur_);
+    GOOGLE_DCHECK(cur_);
+    return impl_.HadError();
+  }
+
   // Trims any unused space in the underlying buffer so that its size matches
   // the number of bytes written by this stream. The underlying buffer will
   // automatically be trimmed when this stream is destroyed; this call is only
   // necessary if the underlying buffer is accessed *before* the stream is
   // destroyed.
-  void Trim();
+  void Trim() { cur_ = impl_.Trim(cur_); }
 
   // Skips a number of bytes, leaving the bytes unmodified in the underlying
   // buffer.  Returns false if an underlying write error occurs.  This is
@@ -713,7 +1108,7 @@
   // Note of caution, the skipped bytes may contain uninitialized data. The
   // caller must make sure that the skipped bytes are properly initialized,
   // otherwise you might leak bytes from your heap.
-  bool Skip(int count);
+  bool Skip(int count) { return impl_.Skip(count, &cur_); }
 
   // Sets *data to point directly at the unwritten part of the
   // CodedOutputStream's underlying buffer, and *size to the size of that
@@ -723,7 +1118,9 @@
   // the consumed bytes.  This may be useful for implementing external fast
   // serialization routines for types of data not covered by the
   // CodedOutputStream interface.
-  bool GetDirectBufferPointer(void** data, int* size);
+  bool GetDirectBufferPointer(void** data, int* size) {
+    return impl_.GetDirectBufferPointer(data, size, &cur_);
+  }
 
   // If there are at least "size" bytes available in the current buffer,
   // returns a pointer directly into the buffer and advances over these bytes.
@@ -732,10 +1129,14 @@
   // there are not enough bytes available, returns NULL.  The return pointer is
   // invalidated as soon as any other non-const method of CodedOutputStream
   // is called.
-  inline uint8* GetDirectBufferForNBytesAndAdvance(int size);
+  inline uint8* GetDirectBufferForNBytesAndAdvance(int size) {
+    return impl_.GetDirectBufferForNBytesAndAdvance(size, &cur_);
+  }
 
   // Write raw bytes, copying them from the given buffer.
-  void WriteRaw(const void* buffer, int size);
+  void WriteRaw(const void* buffer, int size) {
+    cur_ = impl_.WriteRaw(buffer, size, cur_);
+  }
   // Like WriteRaw()  but will try to write aliased data if aliasing is
   // turned on.
   void WriteRawMaybeAliased(const void* data, int size);
@@ -755,23 +1156,18 @@
                                            uint8* target);
 
 
-  // Instructs the CodedOutputStream to allow the underlying
-  // ZeroCopyOutputStream to hold pointers to the original structure instead of
-  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
-  // underlying stream does not support aliasing, then enabling it has no
-  // affect.  For now, this only affects the behavior of
-  // WriteRawMaybeAliased().
-  //
-  // NOTE: It is caller's responsibility to ensure that the chunk of memory
-  // remains live until all of the data has been consumed from the stream.
-  void EnableAliasing(bool enabled);
-
   // Write a 32-bit little-endian integer.
-  void WriteLittleEndian32(uint32 value);
+  void WriteLittleEndian32(uint32 value) {
+    impl_.EnsureSpace(&cur_);
+    SetCur(WriteLittleEndian32ToArray(value, Cur()));
+  }
   // Like WriteLittleEndian32()  but writing directly to the target array.
   static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target);
   // Write a 64-bit little-endian integer.
-  void WriteLittleEndian64(uint64 value);
+  void WriteLittleEndian64(uint64 value) {
+    impl_.EnsureSpace(&cur_);
+    SetCur(WriteLittleEndian64ToArray(value, Cur()));
+  }
   // Like WriteLittleEndian64()  but writing directly to the target array.
   static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target);
 
@@ -822,45 +1218,31 @@
   };
 
   // Returns the total number of bytes written since this object was created.
-  inline int ByteCount() const;
+  int ByteCount() const {
+    return static_cast<int>(impl_.ByteCount(cur_) - start_count_);
+  }
 
-  // Returns true if there was an underlying I/O error since this object was
-  // created.
-  bool HadError() const { return had_error_; }
+  // Instructs the CodedOutputStream to allow the underlying
+  // ZeroCopyOutputStream to hold pointers to the original structure instead of
+  // copying, if it supports it (i.e. output->AllowsAliasing() is true).  If the
+  // underlying stream does not support aliasing, then enabling it has no
+  // affect.  For now, this only affects the behavior of
+  // WriteRawMaybeAliased().
+  //
+  // NOTE: It is caller's responsibility to ensure that the chunk of memory
+  // remains live until all of the data has been consumed from the stream.
+  void EnableAliasing(bool enabled) { impl_.EnableAliasing(enabled); }
 
-  // Deterministic serialization, if requested, guarantees that for a given
-  // binary, equal messages will always be serialized to the same bytes. This
-  // implies:
-  //   . repeated serialization of a message will return the same bytes
-  //   . different processes of the same binary (which may be executing on
-  //     different machines) will serialize equal messages to the same bytes.
-  //
-  // Note the deterministic serialization is NOT canonical across languages; it
-  // is also unstable across different builds with schema changes due to unknown
-  // fields. Users who need canonical serialization, e.g., persistent storage in
-  // a canonical form, fingerprinting, etc., should define their own
-  // canonicalization specification and implement the serializer using
-  // reflection APIs rather than relying on this API.
-  //
-  // If deterministic serialization is requested, the serializer will
-  // sort map entries by keys in lexicographical order or numerical order.
-  // (This is an implementation detail and may subject to change.)
-  //
-  // There are two ways to determine whether serialization should be
-  // deterministic for this CodedOutputStream.  If SetSerializationDeterministic
-  // has not yet been called, then the default comes from the global default,
-  // which is false, until SetDefaultSerializationDeterministic has been called.
-  // Otherwise, SetSerializationDeterministic has been called, and the last
-  // value passed to it is all that matters.
   void SetSerializationDeterministic(bool value) {
-    is_serialization_deterministic_ = value;
+    impl_.SetSerializationDeterministic(value);
   }
   // See above.  Also, note that users of this CodedOutputStream may need to
   // call IsSerializationDeterministic() to serialize in the intended way.  This
   // CodedOutputStream cannot enforce a desire for deterministic serialization
   // by itself.
+
   bool IsSerializationDeterministic() const {
-    return is_serialization_deterministic_;
+    return impl_.IsSerializationDeterministic();
   }
 
   static bool IsDefaultSerializationDeterministic() {
@@ -868,34 +1250,19 @@
                std::memory_order_relaxed) != 0;
   }
 
+  template <typename Func>
+  void Serialize(const Func& func);
+
+  uint8* Cur() const { return cur_; }
+  void SetCur(uint8* ptr) { cur_ = ptr; }
+  EpsCopyOutputStream* EpsCopy() { return &impl_; }
+
  private:
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
-
-  ZeroCopyOutputStream* output_;
-  uint8* buffer_;
-  int buffer_size_;
-  int total_bytes_;        // Sum of sizes of all buffers seen so far.
-  bool had_error_;         // Whether an error occurred during output.
-  bool aliasing_enabled_;  // See EnableAliasing().
-  bool is_serialization_deterministic_;
+  EpsCopyOutputStream impl_;
+  uint8* cur_;
+  int64 start_count_;
   static std::atomic<bool> default_serialization_deterministic_;
 
-  // Advance the buffer by a given number of bytes.
-  void Advance(int amount);
-
-  // Called when the buffer runs out to request more data.  Implies an
-  // Advance(buffer_size_).
-  bool Refresh();
-
-  // Like WriteRaw() but may avoid copying if the underlying
-  // ZeroCopyOutputStream supports it.
-  void WriteAliasedRaw(const void* buffer, int size);
-
-  // If this write might cross the end of the buffer, we compose the bytes first
-  // then use WriteRaw().
-  void WriteVarint32SlowPath(uint32 value);
-  void WriteVarint64SlowPath(uint64 value);
-
   // See above.  Other projects may use "friend" to allow them to call this.
   // After SetDefaultSerializationDeterministic() completes, all protocol
   // buffer serializations will be deterministic by default.  Thread safe.
@@ -907,6 +1274,7 @@
   static void SetDefaultSerializationDeterministic() {
     default_serialization_deterministic_.store(true, std::memory_order_relaxed);
   }
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream);
 };
 
 // inline methods ====================================================
@@ -1109,7 +1477,7 @@
       return buffer + 2;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 inline void CodedInputStream::GetDirectBufferPointerInline(const void** data,
@@ -1136,36 +1504,109 @@
   return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
 }
 
-inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
-  if (buffer_size_ < size) {
-    return NULL;
-  } else {
-    uint8* result = buffer_;
-    Advance(size);
-    return result;
+inline void CodedInputStream::Advance(int amount) { buffer_ += amount; }
+
+inline void CodedInputStream::SetRecursionLimit(int limit) {
+  recursion_budget_ += limit - recursion_limit_;
+  recursion_limit_ = limit;
+}
+
+inline bool CodedInputStream::IncrementRecursionDepth() {
+  --recursion_budget_;
+  return recursion_budget_ >= 0;
+}
+
+inline void CodedInputStream::DecrementRecursionDepth() {
+  if (recursion_budget_ < recursion_limit_) ++recursion_budget_;
+}
+
+inline void CodedInputStream::UnsafeDecrementRecursionDepth() {
+  assert(recursion_budget_ < recursion_limit_);
+  ++recursion_budget_;
+}
+
+inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
+                                                   MessageFactory* factory) {
+  extension_pool_ = pool;
+  extension_factory_ = factory;
+}
+
+inline const DescriptorPool* CodedInputStream::GetExtensionPool() {
+  return extension_pool_;
+}
+
+inline MessageFactory* CodedInputStream::GetExtensionFactory() {
+  return extension_factory_;
+}
+
+inline int CodedInputStream::BufferSize() const {
+  return static_cast<int>(buffer_end_ - buffer_);
+}
+
+inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
+    : buffer_(nullptr),
+      buffer_end_(nullptr),
+      input_(input),
+      total_bytes_read_(0),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(kint32max),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Eagerly Refresh() so buffer space is immediately available.
+  Refresh();
+}
+
+inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
+    : buffer_(buffer),
+      buffer_end_(buffer + size),
+      input_(nullptr),
+      total_bytes_read_(size),
+      overflow_bytes_(0),
+      last_tag_(0),
+      legitimate_message_end_(false),
+      aliasing_enabled_(false),
+      current_limit_(size),
+      buffer_size_after_limit_(0),
+      total_bytes_limit_(kDefaultTotalBytesLimit),
+      recursion_budget_(default_recursion_limit_),
+      recursion_limit_(default_recursion_limit_),
+      extension_pool_(nullptr),
+      extension_factory_(nullptr) {
+  // Note that setting current_limit_ == size is important to prevent some
+  // code paths from trying to access input_ and segfaulting.
+}
+
+inline bool CodedInputStream::IsFlat() const { return input_ == nullptr; }
+
+inline bool CodedInputStream::Skip(int count) {
+  if (count < 0) return false;  // security: count is often user-supplied
+
+  const int original_buffer_size = BufferSize();
+
+  if (count <= original_buffer_size) {
+    // Just skipping within the current buffer.  Easy.
+    Advance(count);
+    return true;
   }
+
+  return SkipFallback(count, original_buffer_size);
 }
 
 inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value,
                                                       uint8* target) {
-  while (value >= 0x80) {
-    *target = static_cast<uint8>(value | 0x80);
-    value >>= 7;
-    ++target;
-  }
-  *target = static_cast<uint8>(value);
-  return target + 1;
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
 }
 
 inline uint8* CodedOutputStream::WriteVarint64ToArray(uint64 value,
                                                       uint8* target) {
-  while (value >= 0x80) {
-    *target = static_cast<uint8>(value | 0x80);
-    value >>= 7;
-    ++target;
-  }
-  *target = static_cast<uint8>(value);
-  return target + 1;
+  return EpsCopyOutputStream::UnsafeVarint(value, target);
 }
 
 inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) {
@@ -1211,29 +1652,13 @@
 }
 
 inline void CodedOutputStream::WriteVarint32(uint32 value) {
-  if (buffer_size_ >= 5) {
-    // Fast path:  We have enough bytes left in the buffer to guarantee that
-    // this write won't cross the end, so we can skip the checks.
-    uint8* target = buffer_;
-    uint8* end = WriteVarint32ToArray(value, target);
-    int size = static_cast<int>(end - target);
-    Advance(size);
-  } else {
-    WriteVarint32SlowPath(value);
-  }
+  impl_.EnsureSpace(&cur_);
+  SetCur(WriteVarint32ToArray(value, Cur()));
 }
 
 inline void CodedOutputStream::WriteVarint64(uint64 value) {
-  if (buffer_size_ >= 10) {
-    // Fast path:  We have enough bytes left in the buffer to guarantee that
-    // this write won't cross the end, so we can skip the checks.
-    uint8* target = buffer_;
-    uint8* end = WriteVarint64ToArray(value, target);
-    int size = static_cast<int>(end - target);
-    Advance(size);
-  } else {
-    WriteVarint64SlowPath(value);
-  }
+  impl_.EnsureSpace(&cur_);
+  SetCur(WriteVarint64ToArray(value, Cur()));
 }
 
 inline void CodedOutputStream::WriteTag(uint32 value) { WriteVarint32(value); }
@@ -1276,11 +1701,13 @@
 
 inline void CodedOutputStream::WriteRawMaybeAliased(const void* data,
                                                     int size) {
-  if (aliasing_enabled_) {
-    WriteAliasedRaw(data, size);
-  } else {
-    WriteRaw(data, size);
-  }
+  cur_ = impl_.WriteRawMaybeAliased(data, size, cur_);
+}
+
+inline uint8* CodedOutputStream::WriteRawToArray(const void* data, int size,
+                                                 uint8* target) {
+  memcpy(target, data, size);
+  return target + size;
 }
 
 inline uint8* CodedOutputStream::WriteStringToArray(const std::string& str,
@@ -1288,110 +1715,6 @@
   return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
 }
 
-inline int CodedOutputStream::ByteCount() const {
-  return total_bytes_ - buffer_size_;
-}
-
-inline void CodedInputStream::Advance(int amount) { buffer_ += amount; }
-
-inline void CodedOutputStream::Advance(int amount) {
-  buffer_ += amount;
-  buffer_size_ -= amount;
-}
-
-inline void CodedInputStream::SetRecursionLimit(int limit) {
-  recursion_budget_ += limit - recursion_limit_;
-  recursion_limit_ = limit;
-}
-
-inline bool CodedInputStream::IncrementRecursionDepth() {
-  --recursion_budget_;
-  return recursion_budget_ >= 0;
-}
-
-inline void CodedInputStream::DecrementRecursionDepth() {
-  if (recursion_budget_ < recursion_limit_) ++recursion_budget_;
-}
-
-inline void CodedInputStream::UnsafeDecrementRecursionDepth() {
-  assert(recursion_budget_ < recursion_limit_);
-  ++recursion_budget_;
-}
-
-inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
-                                                   MessageFactory* factory) {
-  extension_pool_ = pool;
-  extension_factory_ = factory;
-}
-
-inline const DescriptorPool* CodedInputStream::GetExtensionPool() {
-  return extension_pool_;
-}
-
-inline MessageFactory* CodedInputStream::GetExtensionFactory() {
-  return extension_factory_;
-}
-
-inline int CodedInputStream::BufferSize() const {
-  return static_cast<int>(buffer_end_ - buffer_);
-}
-
-inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
-    : buffer_(NULL),
-      buffer_end_(NULL),
-      input_(input),
-      total_bytes_read_(0),
-      overflow_bytes_(0),
-      last_tag_(0),
-      legitimate_message_end_(false),
-      aliasing_enabled_(false),
-      current_limit_(kint32max),
-      buffer_size_after_limit_(0),
-      total_bytes_limit_(kDefaultTotalBytesLimit),
-      recursion_budget_(default_recursion_limit_),
-      recursion_limit_(default_recursion_limit_),
-      extension_pool_(NULL),
-      extension_factory_(NULL) {
-  // Eagerly Refresh() so buffer space is immediately available.
-  Refresh();
-}
-
-inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
-    : buffer_(buffer),
-      buffer_end_(buffer + size),
-      input_(NULL),
-      total_bytes_read_(size),
-      overflow_bytes_(0),
-      last_tag_(0),
-      legitimate_message_end_(false),
-      aliasing_enabled_(false),
-      current_limit_(size),
-      buffer_size_after_limit_(0),
-      total_bytes_limit_(kDefaultTotalBytesLimit),
-      recursion_budget_(default_recursion_limit_),
-      recursion_limit_(default_recursion_limit_),
-      extension_pool_(NULL),
-      extension_factory_(NULL) {
-  // Note that setting current_limit_ == size is important to prevent some
-  // code paths from trying to access input_ and segfaulting.
-}
-
-inline bool CodedInputStream::IsFlat() const { return input_ == NULL; }
-
-inline bool CodedInputStream::Skip(int count) {
-  if (count < 0) return false;  // security: count is often user-supplied
-
-  const int original_buffer_size = BufferSize();
-
-  if (count <= original_buffer_size) {
-    // Just skipping within the current buffer.  Easy.
-    Advance(count);
-    return true;
-  }
-
-  return SkipFallback(count, original_buffer_size);
-}
-
 }  // namespace io
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index 26e6a7c..52b7a7b 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -1009,41 +1009,6 @@
   EXPECT_EQ(0, size);
 }
 
-TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) {
-  ArrayOutputStream output(buffer_, sizeof(buffer_), 8);
-  CodedOutputStream coded_output(&output);
-
-  void* ptr;
-  int size;
-
-  EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
-  EXPECT_EQ(buffer_, ptr);
-  EXPECT_EQ(8, size);
-
-  // Peeking again should return the same pointer.
-  EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
-  EXPECT_EQ(buffer_, ptr);
-  EXPECT_EQ(8, size);
-
-  // Skip forward in the same buffer then peek again.
-  EXPECT_TRUE(coded_output.Skip(3));
-  EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
-  EXPECT_EQ(buffer_ + 3, ptr);
-  EXPECT_EQ(5, size);
-
-  // Skip to end of buffer and peek -- should get next buffer.
-  EXPECT_TRUE(coded_output.Skip(5));
-  EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
-  EXPECT_EQ(buffer_ + 8, ptr);
-  EXPECT_EQ(8, size);
-
-  // Skip over multiple buffers.
-  EXPECT_TRUE(coded_output.Skip(22));
-  EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
-  EXPECT_EQ(buffer_ + 30, ptr);
-  EXPECT_EQ(2, size);
-}
-
 // -------------------------------------------------------------------
 // Limits
 
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index af7e309..e2d6756 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -111,25 +111,17 @@
   static const int kKeyFieldNumber = 1;
   static const int kValueFieldNumber = 2;
 
-  static void SerializeToCodedStream(int field_number, const Key& key,
-                                     const Value& value,
-                                     io::CodedOutputStream* output) {
-    WireFormatLite::WriteTag(field_number,
-                             WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output->WriteVarint32(GetCachedSize(key, value));
-    KeyTypeHandler::Write(kKeyFieldNumber, key, output);
-    ValueTypeHandler::Write(kValueFieldNumber, value, output);
-  }
+  static uint8* InternalSerialize(int field_number, const Key& key,
+                                  const Value& value, uint8* ptr,
+                                  io::EpsCopyOutputStream* stream) {
+    stream->EnsureSpace(&ptr);
+    ptr = WireFormatLite::WriteTagToArray(
+        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, ptr);
+    ptr = io::CodedOutputStream::WriteVarint32ToArray(GetCachedSize(key, value),
+                                                      ptr);
 
-  static ::google::protobuf::uint8* SerializeToArray(int field_number, const Key& key,
-                                   const Value& value, ::google::protobuf::uint8* output) {
-    output = WireFormatLite::WriteTagToArray(
-        field_number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    output = io::CodedOutputStream::WriteVarint32ToArray(
-        static_cast<uint32>(GetCachedSize(key, value)), output);
-    output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key, output);
-    output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value, output);
-    return output;
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key, ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value, ptr, stream);
   }
 
   static size_t ByteSizeLong(const Key& key, const Value& value) {
@@ -324,16 +316,10 @@
     return size;
   }
 
-  void SerializeWithCachedSizes(io::CodedOutputStream* output) const override {
-    KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
-    ValueTypeHandler::Write(kValueFieldNumber, value(), output);
-  }
-
   ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
-      ::google::protobuf::uint8* output) const override {
-    output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
-    output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
-    return output;
+      ::google::protobuf::uint8* ptr, io::EpsCopyOutputStream* stream) const override {
+    ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
+    return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
   }
 
   // Don't override SerializeWithCachedSizesToArray.  Use MessageLite's.
diff --git a/src/google/protobuf/map_test_util.cc b/src/google/protobuf/map_test_util.cc
deleted file mode 100644
index 468d8ee..0000000
--- a/src/google/protobuf/map_test_util.cc
+++ /dev/null
@@ -1,1603 +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/map_test_util.h>
-#include <google/protobuf/map_test_util_impl.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/message.h>
-
-namespace google {
-namespace protobuf {
-
-void MapTestUtil::SetMapFields(unittest::TestMap* message) {
-  MapTestUtilImpl::SetMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
-                                unittest::MAP_ENUM_BAZ>(message);
-}
-
-void MapTestUtil::SetArenaMapFields(unittest::TestArenaMap* message) {
-  MapTestUtilImpl::SetArenaMapFields<unittest::MapEnum, unittest::MAP_ENUM_BAR,
-                                     unittest::MAP_ENUM_BAZ>(message);
-}
-
-void MapTestUtil::SetMapFieldsInitialized(unittest::TestMap* message) {
-  MapTestUtilImpl::SetMapFieldsInitialized(message);
-}
-
-void MapTestUtil::ModifyMapFields(unittest::TestMap* message) {
-  MapTestUtilImpl::ModifyMapFields<unittest::MapEnum, unittest::MAP_ENUM_FOO>(
-      message);
-}
-
-void MapTestUtil::ExpectClear(const unittest::TestMap& message) {
-  MapTestUtilImpl::ExpectClear(message);
-}
-
-void MapTestUtil::ExpectMapFieldsSet(const unittest::TestMap& message) {
-  MapTestUtilImpl::ExpectMapFieldsSet<unittest::MapEnum, unittest::MAP_ENUM_BAR,
-                                      unittest::MAP_ENUM_BAZ>(message);
-}
-
-void MapTestUtil::ExpectArenaMapFieldsSet(
-    const unittest::TestArenaMap& message) {
-  MapTestUtilImpl::ExpectArenaMapFieldsSet<
-      unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_BAZ>(
-      message);
-}
-
-void MapTestUtil::ExpectMapFieldsSetInitialized(
-    const unittest::TestMap& message) {
-  MapTestUtilImpl::ExpectMapFieldsSetInitialized<unittest::MapEnum,
-                                                 unittest::MAP_ENUM_FOO>(
-      message);
-}
-
-void MapTestUtil::ExpectMapFieldsModified(const unittest::TestMap& message) {
-  MapTestUtilImpl::ExpectMapFieldsModified<
-      unittest::MapEnum, unittest::MAP_ENUM_BAR, unittest::MAP_ENUM_FOO>(
-      message);
-}
-
-void MapTestUtil::ExpectMapsSize(const unittest::TestMap& message, int size) {
-  const Descriptor* descriptor = message.GetDescriptor();
-
-  EXPECT_EQ(size, message.GetReflection()->FieldSize(
-                      message, descriptor->FindFieldByName("map_int32_int32")));
-  EXPECT_EQ(size, message.GetReflection()->FieldSize(
-                      message, descriptor->FindFieldByName("map_int64_int64")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_uint32_uint32")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_uint64_uint64")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_sint32_sint32")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_sint64_sint64")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_fixed32_fixed32")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_fixed64_fixed64")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
-  EXPECT_EQ(size, message.GetReflection()->FieldSize(
-                      message, descriptor->FindFieldByName("map_int32_float")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_int32_double")));
-  EXPECT_EQ(size, message.GetReflection()->FieldSize(
-                      message, descriptor->FindFieldByName("map_bool_bool")));
-  EXPECT_EQ(size,
-            message.GetReflection()->FieldSize(
-                message, descriptor->FindFieldByName("map_string_string")));
-  EXPECT_EQ(size, message.GetReflection()->FieldSize(
-                      message, descriptor->FindFieldByName("map_int32_bytes")));
-  EXPECT_EQ(
-      size,
-      message.GetReflection()->FieldSize(
-          message, descriptor->FindFieldByName("map_int32_foreign_message")));
-}
-
-std::vector<const Message*> MapTestUtil::GetMapEntries(
-    const unittest::TestMap& message, int index) {
-  const Descriptor* descriptor = message.GetDescriptor();
-  std::vector<const Message*> result;
-
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_int32"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int64_int64"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_uint32_uint32"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_uint64_uint64"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_sint32_sint32"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_sint64_sint64"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_fixed32_fixed32"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_fixed64_fixed64"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_sfixed32_sfixed32"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_sfixed64_sfixed64"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_float"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_double"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_bool_bool"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_string_string"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_bytes"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_enum"), index));
-  result.push_back(&message.GetReflection()->GetRepeatedMessage(
-      message, descriptor->FindFieldByName("map_int32_foreign_message"),
-      index));
-
-  return result;
-}
-
-std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease(
-    unittest::TestMap* message) {
-  const Descriptor* descriptor = message->GetDescriptor();
-  std::vector<const Message*> result;
-
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_int32")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int64_int64")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_uint32_uint32")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_uint64_uint64")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_sint32_sint32")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_sint64_sint64")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_fixed32_fixed32")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_fixed64_fixed64")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_float")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_double")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_bool_bool")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_string_string")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_bytes")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_enum")));
-  result.push_back(message->GetReflection()->ReleaseLast(
-      message, descriptor->FindFieldByName("map_int32_foreign_message")));
-
-  return result;
-}
-
-MapReflectionTester::MapReflectionTester(const Descriptor* base_descriptor)
-    : base_descriptor_(base_descriptor) {
-  const DescriptorPool* pool = base_descriptor->file()->pool();
-
-  map_enum_foo_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_FOO");
-  map_enum_bar_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAR");
-  map_enum_baz_ = pool->FindEnumValueByName("protobuf_unittest.MAP_ENUM_BAZ");
-
-  foreign_c_ = pool->FindFieldByName("protobuf_unittest.ForeignMessage.c");
-  map_int32_int32_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32Int32Entry.key");
-  map_int32_int32_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32Int32Entry.value");
-  map_int64_int64_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt64Int64Entry.key");
-  map_int64_int64_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt64Int64Entry.value");
-  map_uint32_uint32_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapUint32Uint32Entry.key");
-  map_uint32_uint32_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapUint32Uint32Entry.value");
-  map_uint64_uint64_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapUint64Uint64Entry.key");
-  map_uint64_uint64_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapUint64Uint64Entry.value");
-  map_sint32_sint32_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapSint32Sint32Entry.key");
-  map_sint32_sint32_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSint32Sint32Entry.value");
-  map_sint64_sint64_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapSint64Sint64Entry.key");
-  map_sint64_sint64_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSint64Sint64Entry.value");
-  map_fixed32_fixed32_key_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.key");
-  map_fixed32_fixed32_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapFixed32Fixed32Entry.value");
-  map_fixed64_fixed64_key_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.key");
-  map_fixed64_fixed64_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapFixed64Fixed64Entry.value");
-  map_sfixed32_sfixed32_key_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.key");
-  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSfixed32Sfixed32Entry.value");
-  map_sfixed64_sfixed64_key_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.key");
-  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapSfixed64Sfixed64Entry.value");
-  map_int32_float_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32FloatEntry.key");
-  map_int32_float_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32FloatEntry.value");
-  map_int32_double_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32DoubleEntry.key");
-  map_int32_double_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapInt32DoubleEntry.value");
-  map_bool_bool_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapBoolBoolEntry.key");
-  map_bool_bool_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapBoolBoolEntry.value");
-  map_string_string_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapStringStringEntry.key");
-  map_string_string_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapStringStringEntry.value");
-  map_int32_bytes_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32BytesEntry.key");
-  map_int32_bytes_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32BytesEntry.value");
-  map_int32_enum_key_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32EnumEntry.key");
-  map_int32_enum_val_ =
-      pool->FindFieldByName("protobuf_unittest.TestMap.MapInt32EnumEntry.value");
-  map_int32_foreign_message_key_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.key");
-  map_int32_foreign_message_val_ = pool->FindFieldByName(
-      "protobuf_unittest.TestMap.MapInt32ForeignMessageEntry.value");
-
-  EXPECT_FALSE(map_enum_foo_ == NULL);
-  EXPECT_FALSE(map_enum_bar_ == NULL);
-  EXPECT_FALSE(map_enum_baz_ == NULL);
-  EXPECT_FALSE(map_int32_int32_key_ == NULL);
-  EXPECT_FALSE(map_int32_int32_val_ == NULL);
-  EXPECT_FALSE(map_int64_int64_key_ == NULL);
-  EXPECT_FALSE(map_int64_int64_val_ == NULL);
-  EXPECT_FALSE(map_uint32_uint32_key_ == NULL);
-  EXPECT_FALSE(map_uint32_uint32_val_ == NULL);
-  EXPECT_FALSE(map_uint64_uint64_key_ == NULL);
-  EXPECT_FALSE(map_uint64_uint64_val_ == NULL);
-  EXPECT_FALSE(map_sint32_sint32_key_ == NULL);
-  EXPECT_FALSE(map_sint32_sint32_val_ == NULL);
-  EXPECT_FALSE(map_sint64_sint64_key_ == NULL);
-  EXPECT_FALSE(map_sint64_sint64_val_ == NULL);
-  EXPECT_FALSE(map_fixed32_fixed32_key_ == NULL);
-  EXPECT_FALSE(map_fixed32_fixed32_val_ == NULL);
-  EXPECT_FALSE(map_fixed64_fixed64_key_ == NULL);
-  EXPECT_FALSE(map_fixed64_fixed64_val_ == NULL);
-  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == NULL);
-  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == NULL);
-  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == NULL);
-  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == NULL);
-  EXPECT_FALSE(map_int32_float_key_ == NULL);
-  EXPECT_FALSE(map_int32_float_val_ == NULL);
-  EXPECT_FALSE(map_int32_double_key_ == NULL);
-  EXPECT_FALSE(map_int32_double_val_ == NULL);
-  EXPECT_FALSE(map_bool_bool_key_ == NULL);
-  EXPECT_FALSE(map_bool_bool_val_ == NULL);
-  EXPECT_FALSE(map_string_string_key_ == NULL);
-  EXPECT_FALSE(map_string_string_val_ == NULL);
-  EXPECT_FALSE(map_int32_bytes_key_ == NULL);
-  EXPECT_FALSE(map_int32_bytes_val_ == NULL);
-  EXPECT_FALSE(map_int32_enum_key_ == NULL);
-  EXPECT_FALSE(map_int32_enum_val_ == NULL);
-  EXPECT_FALSE(map_int32_foreign_message_key_ == NULL);
-  EXPECT_FALSE(map_int32_foreign_message_val_ == NULL);
-}
-
-// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
-const FieldDescriptor* MapReflectionTester::F(const std::string& name) {
-  const FieldDescriptor* result = NULL;
-  result = base_descriptor_->FindFieldByName(name);
-  GOOGLE_CHECK(result != NULL);
-  return result;
-}
-
-void MapReflectionTester::SetMapFieldsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  Message* sub_message = NULL;
-  Message* sub_foreign_message = NULL;
-
-  // Add first element.
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 0);
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 0);
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
-                                         0);
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
-                                         0);
-
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
-                                         0);
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
-                                         0);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
-                                          0);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
-                                          0);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_key_, 0);
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_key_, 0);
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_val_, 0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 0);
-  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
-                                         0.0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 0);
-  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
-                                          0.0);
-
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, false);
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, false);
-
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
-                                          "0");
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
-                                          "0");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 0);
-  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
-                                          "0");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 0);
-  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
-                                        map_enum_bar_);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_int32_foreign_message_key_, 0);
-  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
-      sub_message, map_int32_foreign_message_val_, NULL);
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 0);
-
-  // Add second element
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 1);
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 1);
-  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
-                                         1);
-  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
-                                         1);
-
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
-                                         1);
-  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
-                                         1);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
-                                          1);
-  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
-                                          1);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_key_, 1);
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_sfixed32_sfixed32_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_key_, 1);
-  sub_message->GetReflection()->SetInt64(sub_message,
-                                         map_sfixed64_sfixed64_val_, 1);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 1);
-  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
-                                         1.0);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 1);
-  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
-                                          1.0);
-
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, true);
-  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, true);
-
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
-                                          "1");
-  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
-                                          "1");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 1);
-  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
-                                          "1");
-
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 1);
-  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
-                                        map_enum_baz_);
-
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  sub_message->GetReflection()->SetInt32(sub_message,
-                                         map_int32_foreign_message_key_, 1);
-  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
-      sub_message, map_int32_foreign_message_val_, NULL);
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 1);
-}
-
-void MapReflectionTester::SetMapFieldsViaMapReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  Message* sub_foreign_message = NULL;
-  MapValueRef map_val;
-
-  // Add first element.
-  MapKey map_key;
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetUInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
-
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint64_uint64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint32_sint32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sint64_sint64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetUInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed32_fixed32"), map_key, &map_val));
-  map_val.SetUInt32Value(0);
-
-  map_key.SetUInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_fixed64_fixed64"), map_key, &map_val));
-  map_val.SetUInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
-  map_val.SetInt32Value(0);
-
-  map_key.SetInt64Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
-  map_val.SetInt64Value(0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"),
-                                                 map_key, &map_val));
-  map_val.SetFloatValue(0.0);
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"),
-                                                 map_key, &map_val));
-  map_val.SetDoubleValue(0.0);
-
-  map_key.SetBoolValue(false);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
-                                                 map_key, &map_val));
-  map_val.SetBoolValue(false);
-
-  map_key.SetStringValue("0");
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_string_string"), map_key, &map_val));
-  map_val.SetStringValue("0");
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
-                                                 map_key, &map_val));
-  map_val.SetStringValue("0");
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"),
-                                                 map_key, &map_val));
-  map_val.SetEnumValue(map_enum_bar_->number());
-
-  map_key.SetInt32Value(0);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 0);
-
-  // Add second element
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                 map_key, &map_val));
-  map_val.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-
-  map_key.SetInt64Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                 map_key, &map_val));
-  map_val.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(1);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(1);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(1);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(1.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(1.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(true);
-
-  map_key.SetStringValue("1");
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("1");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("1");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_baz_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 1);
-}
-
-void MapReflectionTester::GetMapValueViaMapReflection(
-    Message* message, const std::string& field_name, const MapKey& map_key,
-    MapValueRef* map_val) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
-                                                  map_key, map_val));
-}
-
-Message* MapReflectionTester::GetMapEntryViaReflection(
-    Message* message, const std::string& field_name, int index) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MutableRepeatedMessage(message, F(field_name), index);
-}
-
-MapIterator MapReflectionTester::MapBegin(Message* message,
-                                          const std::string& field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapBegin(message, F(field_name));
-}
-
-MapIterator MapReflectionTester::MapEnd(Message* message,
-                                        const std::string& field_name) {
-  const Reflection* reflection = message->GetReflection();
-  return reflection->MapEnd(message, F(field_name));
-}
-
-void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  reflection->ClearField(message, F("map_int32_int32"));
-  reflection->ClearField(message, F("map_int64_int64"));
-  reflection->ClearField(message, F("map_uint32_uint32"));
-  reflection->ClearField(message, F("map_uint64_uint64"));
-  reflection->ClearField(message, F("map_sint32_sint32"));
-  reflection->ClearField(message, F("map_sint64_sint64"));
-  reflection->ClearField(message, F("map_fixed32_fixed32"));
-  reflection->ClearField(message, F("map_fixed64_fixed64"));
-  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
-  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
-  reflection->ClearField(message, F("map_int32_float"));
-  reflection->ClearField(message, F("map_int32_double"));
-  reflection->ClearField(message, F("map_bool_bool"));
-  reflection->ClearField(message, F("map_string_string"));
-  reflection->ClearField(message, F("map_int32_bytes"));
-  reflection->ClearField(message, F("map_int32_enum"));
-  reflection->ClearField(message, F("map_int32_foreign_message"));
-}
-
-void MapReflectionTester::ModifyMapFieldsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  MapValueRef map_val;
-  Message* sub_foreign_message;
-
-  // Modify the second element
-  MapKey map_key;
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
-                                                  map_key, &map_val));
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
-                                                  map_key, &map_val));
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_uint32_uint32"), map_key, &map_val));
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
-                                     &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
-                                     &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetUInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
-                                     &map_val);
-  map_val.SetUInt32Value(2);
-
-  map_key.SetUInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
-                                     &map_val);
-  map_val.SetUInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
-                                     map_key, &map_val);
-  map_val.SetInt32Value(2);
-
-  map_key.SetInt64Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
-                                     map_key, &map_val);
-  map_val.SetInt64Value(2);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
-                                     &map_val);
-  map_val.SetFloatValue(2.0);
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
-                                     &map_val);
-  map_val.SetDoubleValue(2.0);
-
-  map_key.SetBoolValue(true);
-  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
-                                     &map_val);
-  map_val.SetBoolValue(false);
-
-  map_key.SetStringValue("1");
-  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
-                                     &map_val);
-  map_val.SetStringValue("2");
-
-  map_key.SetInt32Value(1);
-  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
-                                     &map_val);
-  map_val.SetEnumValue(map_enum_foo_->number());
-
-  map_key.SetInt32Value(1);
-  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
-      message, F("map_int32_foreign_message"), map_key, &map_val));
-  sub_foreign_message = map_val.MutableMessageValue();
-  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
-                                                 foreign_c_, 2);
-}
-
-void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    reflection->RemoveLast(message, field);
-  }
-}
-
-void MapReflectionTester::ReleaseLastMapsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
-
-    Message* released = reflection->ReleaseLast(message, field);
-    ASSERT_TRUE(released != NULL)
-        << "ReleaseLast returned NULL for: " << field->name();
-    delete released;
-  }
-}
-
-void MapReflectionTester::SwapMapsViaReflection(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  std::vector<const FieldDescriptor*> output;
-  reflection->ListFields(*message, &output);
-  for (int i = 0; i < output.size(); ++i) {
-    const FieldDescriptor* field = output[i];
-    if (!field->is_repeated()) continue;
-    reflection->SwapElements(message, field, 0, 1);
-  }
-}
-
-void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
-    Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  Message* sub_message = NULL;
-
-  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int32_float"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int32_double"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_string_string"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
-  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
-              NULL);
-}
-
-void MapReflectionTester::ExpectMapFieldsSetViaReflection(
-    const Message& message) {
-  std::string scratch;
-  const Reflection* reflection = message.GetReflection();
-  const Message* sub_message;
-  MapKey map_key;
-
-  // -----------------------------------------------------------------
-
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
-  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
-
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_int32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_int32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(*sub_message,
-                                                         map_int64_int64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(*sub_message,
-                                                         map_int64_int64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      // Check with RepeatedField Reflection
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
-      uint32 key = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_uint32_uint32_key_);
-      uint32 val = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_uint32_uint32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt32Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_uint32_uint32"), map_key));
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
-      uint64 key = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_uint64_uint64_key_);
-      uint64 val = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_uint64_uint64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt64Value(key);
-      EXPECT_TRUE(
-          reflection->ContainsMapKey(message, F("map_uint64_uint64"), map_key));
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sint32_sint32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sint32_sint32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sint32_sint32"), map_key));
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sint64_sint64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sint64_sint64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sint64_sint64"), map_key));
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_fixed32_fixed32"), i);
-      uint32 key = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_fixed32_fixed32_key_);
-      uint32 val = sub_message->GetReflection()->GetUInt32(
-          *sub_message, map_fixed32_fixed32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_fixed32_fixed32"), map_key));
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_fixed64_fixed64"), i);
-      uint64 key = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_fixed64_fixed64_key_);
-      uint64 val = sub_message->GetReflection()->GetUInt64(
-          *sub_message, map_fixed64_fixed64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetUInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_fixed64_fixed64"), map_key));
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_sfixed32_sfixed32"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sfixed32_sfixed32_key_);
-      int32 val = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_sfixed32_sfixed32_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sfixed32_sfixed32"), map_key));
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_sfixed64_sfixed64"), i);
-      int64 key = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sfixed64_sfixed64_key_);
-      int64 val = sub_message->GetReflection()->GetInt64(
-          *sub_message, map_sfixed64_sfixed64_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt64Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_sfixed64_sfixed64"), map_key));
-    }
-  }
-  {
-    std::map<int32, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_float_key_);
-      float val = sub_message->GetReflection()->GetFloat(*sub_message,
-                                                         map_int32_float_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_float"),
-                                                 map_key));
-    }
-  }
-  {
-    std::map<int32, double> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_double_key_);
-      double val = sub_message->GetReflection()->GetDouble(
-          *sub_message, map_int32_double_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_double"),
-                                                 map_key));
-    }
-  }
-  {
-    std::map<bool, bool> map;
-    map[false] = false;
-    map[true] = true;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
-      bool key = sub_message->GetReflection()->GetBool(*sub_message,
-                                                       map_bool_bool_key_);
-      bool val = sub_message->GetReflection()->GetBool(*sub_message,
-                                                       map_bool_bool_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetBoolValue(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
-                                                 map_key));
-    }
-  }
-  {
-    std::map<std::string, std::string> map;
-    map["0"] = "0";
-    map["1"] = "1";
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
-      std::string key = sub_message->GetReflection()->GetString(
-          *sub_message, map_string_string_key_);
-      std::string val = sub_message->GetReflection()->GetString(
-          *sub_message, map_string_string_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetStringValue(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_string_string"), map_key));
-    }
-  }
-  {
-    std::map<int32, std::string> map;
-    map[0] = "0";
-    map[1] = "1";
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_bytes_key_);
-      std::string val = sub_message->GetReflection()->GetString(
-          *sub_message, map_int32_bytes_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_bytes"),
-                                                 map_key));
-    }
-  }
-  {
-    std::map<int32, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (int i = 0; i < 2; i++) {
-      sub_message =
-          &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
-                                                         map_int32_enum_key_);
-      const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
-          *sub_message, map_int32_enum_val_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
-                                                 map_key));
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (int i = 0; i < 2; i++) {
-      sub_message = &reflection->GetRepeatedMessage(
-          message, F("map_int32_foreign_message"), i);
-      int32 key = sub_message->GetReflection()->GetInt32(
-          *sub_message, map_int32_foreign_message_key_);
-      const Message& foreign_message = sub_message->GetReflection()->GetMessage(
-          *sub_message, map_int32_foreign_message_val_);
-      int32 val = foreign_message.GetReflection()->GetInt32(foreign_message,
-                                                            foreign_c_);
-      EXPECT_EQ(map[key], val);
-      // Check with Map Reflection
-      map_key.SetInt32Value(key);
-      EXPECT_EQ(true, reflection->ContainsMapKey(
-                          message, F("map_int32_foreign_message"), map_key));
-    }
-  }
-}
-
-void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
-    Message* message) {
-  std::string scratch;
-  std::string serialized;
-  const Reflection* reflection = message->GetReflection();
-
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
-  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
-
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    int size = 0;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32"));
-         iter != reflection->MapEnd(message, F("map_int32_int32"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsed();
-      message->ByteSize();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64"));
-         iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_uint32_uint32"));
-         iter != reflection->MapEnd(message, F("map_uint32_uint32")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_uint64_uint64"));
-         iter != reflection->MapEnd(message, F("map_uint64_uint64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sint32_sint32"));
-         iter != reflection->MapEnd(message, F("map_sint32_sint32")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    std::map<int64, int64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sint64_sint64"));
-         iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
-                iter.GetValueRef().GetInt64Value());
-    }
-  }
-  {
-    std::map<uint32, uint32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_fixed32_fixed32"));
-         iter != reflection->MapEnd(message, F("map_fixed32_fixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
-                iter.GetValueRef().GetUInt32Value());
-    }
-  }
-  {
-    std::map<uint64, uint64> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_fixed64_fixed64"));
-         iter != reflection->MapEnd(message, F("map_fixed64_fixed64"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
-                iter.GetValueRef().GetUInt64Value());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_sfixed32_sfixed32"));
-         iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32"));
-         ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetInt32Value());
-    }
-  }
-  {
-    std::map<int32, float> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float"));
-         iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetFloatValue());
-    }
-  }
-  {
-    std::map<int32, double> map;
-    map[0] = 0.0;
-    map[1] = 1.0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_int32_double"));
-         iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetDoubleValue());
-    }
-  }
-  {
-    std::map<bool, bool> map;
-    map[false] = false;
-    map[true] = true;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool"));
-         iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetBoolValue()],
-                iter.GetValueRef().GetBoolValue());
-    }
-  }
-  {
-    std::map<std::string, std::string> map;
-    map["0"] = "0";
-    map["1"] = "1";
-    int size = 0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_string_string"));
-         iter != reflection->MapEnd(message, F("map_string_string"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsed();
-      message->ByteSize();
-      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
-                iter.GetValueRef().GetStringValue());
-    }
-    EXPECT_EQ(size, 2);
-  }
-  {
-    std::map<int32, std::string> map;
-    map[0] = "0";
-    map[1] = "1";
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes"));
-         iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                iter.GetValueRef().GetStringValue());
-    }
-  }
-  {
-    std::map<int32, const EnumValueDescriptor*> map;
-    map[0] = map_enum_bar_;
-    map[1] = map_enum_baz_;
-    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum"));
-         iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) {
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
-                iter.GetValueRef().GetEnumValue());
-    }
-  }
-  {
-    std::map<int32, int32> map;
-    map[0] = 0;
-    map[1] = 1;
-    int size = 0;
-    for (MapIterator iter =
-             reflection->MapBegin(message, F("map_int32_foreign_message"));
-         iter != reflection->MapEnd(message, F("map_int32_foreign_message"));
-         ++iter, ++size) {
-      // Check const methods do not invalidate map.
-      message->DebugString();
-      message->ShortDebugString();
-      message->SerializeToString(&serialized);
-      message->SpaceUsed();
-      message->ByteSize();
-      const Message& sub_message = iter.GetValueRef().GetMessageValue();
-      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
-                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
-    }
-    EXPECT_EQ(size, 2);
-  }
-}
-
-void MapReflectionTester::ExpectClearViaReflection(const Message& message) {
-  const Reflection* reflection = message.GetReflection();
-  // Map fields are empty.
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
-  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
-  EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
-                  ->IsMapValid());
-}
-
-void MapReflectionTester::ExpectClearViaReflectionIterator(Message* message) {
-  const Reflection* reflection = message->GetReflection();
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) ==
-              reflection->MapEnd(message, F("map_int32_int32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) ==
-              reflection->MapEnd(message, F("map_int64_int64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) ==
-              reflection->MapEnd(message, F("map_uint32_uint32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) ==
-              reflection->MapEnd(message, F("map_uint64_uint64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) ==
-              reflection->MapEnd(message, F("map_sint32_sint32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) ==
-              reflection->MapEnd(message, F("map_sint64_sint64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) ==
-              reflection->MapEnd(message, F("map_fixed32_fixed32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) ==
-              reflection->MapEnd(message, F("map_fixed64_fixed64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) ==
-              reflection->MapEnd(message, F("map_sfixed32_sfixed32")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) ==
-              reflection->MapEnd(message, F("map_sfixed64_sfixed64")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) ==
-              reflection->MapEnd(message, F("map_int32_float")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) ==
-              reflection->MapEnd(message, F("map_int32_double")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) ==
-              reflection->MapEnd(message, F("map_bool_bool")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) ==
-              reflection->MapEnd(message, F("map_string_string")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) ==
-              reflection->MapEnd(message, F("map_int32_bytes")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) ==
-              reflection->MapEnd(message, F("map_int32_enum")));
-  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) ==
-              reflection->MapEnd(message, F("map_int32_foreign_message")));
-}
-
-}  // namespace protobuf
-}  // namespace google
diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h
index 8f13e31..54ccfbb 100644
--- a/src/google/protobuf/map_test_util.h
+++ b/src/google/protobuf/map_test_util.h
@@ -33,56 +33,18 @@
 
 #include <google/protobuf/map_unittest.pb.h>
 
+#define UNITTEST ::protobuf_unittest
+// Must define UNITTEST before including map_test_util.inc.
+#include <google/protobuf/map_test_util.inc>
+#undef UNITTEST
+
+#include <google/protobuf/port_def.inc>
+
 namespace google {
 namespace protobuf {
 
 namespace unittest = ::protobuf_unittest;
 
-class MapTestUtil {
- public:
-  // Set every field in the TestMap message to a unique value.
-  static void SetMapFields(unittest::TestMap* message);
-
-  // Set every field in the TestArenaMap message to a unique value.
-  static void SetArenaMapFields(unittest::TestArenaMap* message);
-
-  // Set every field in the message to a default value.
-  static void SetMapFieldsInitialized(unittest::TestMap* message);
-
-  // Modify all the map fields of the message (which should already have been
-  // initialized with SetMapFields()).
-  static void ModifyMapFields(unittest::TestMap* message);
-
-  // Check that all fields have the values that they should have after
-  // SetMapFields() is called.
-  static void ExpectMapFieldsSet(const unittest::TestMap& message);
-
-  // Check that all fields have the values that they should have after
-  // SetMapFields() is called for TestArenaMap.
-  static void ExpectArenaMapFieldsSet(const unittest::TestArenaMap& message);
-
-  // Check that all fields have the values that they should have after
-  // SetMapFieldsInitialized() is called.
-  static void ExpectMapFieldsSetInitialized(const unittest::TestMap& message);
-
-  // Expect that the message is modified as would be expected from
-  // ModifyMapFields().
-  static void ExpectMapFieldsModified(const unittest::TestMap& message);
-
-  // Check that all fields are empty.
-  static void ExpectClear(const unittest::TestMap& message);
-
-  // Check that all map fields have the given size.
-  static void ExpectMapsSize(const unittest::TestMap& message, int size);
-
-  // Get pointers of map entries at given index.
-  static std::vector<const Message*> GetMapEntries(
-      const unittest::TestMap& message, int index);
-
-  // Get pointers of map entries from release.
-  static std::vector<const Message*> GetMapEntriesFromRelease(
-      unittest::TestMap* message);
-};
 
 // Like above, but use the reflection interface.
 class MapReflectionTester {
@@ -158,7 +120,1395 @@
   const FieldDescriptor* map_int32_foreign_message_val_;
 };
 
+inline MapReflectionTester::MapReflectionTester(
+    const Descriptor* base_descriptor)
+    : base_descriptor_(base_descriptor) {
+  const DescriptorPool* pool = base_descriptor->file()->pool();
+  std::string package = base_descriptor->file()->package();
+
+  map_enum_foo_ = pool->FindEnumValueByName(package + ".MAP_ENUM_FOO");
+  map_enum_bar_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAR");
+  map_enum_baz_ = pool->FindEnumValueByName(package + ".MAP_ENUM_BAZ");
+
+  foreign_c_ = pool->FindFieldByName(package + ".ForeignMessage.c");
+  map_int32_int32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.key");
+  map_int32_int32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32Int32Entry.value");
+  map_int64_int64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.key");
+  map_int64_int64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt64Int64Entry.value");
+  map_uint32_uint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.key");
+  map_uint32_uint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint32Uint32Entry.value");
+  map_uint64_uint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.key");
+  map_uint64_uint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapUint64Uint64Entry.value");
+  map_sint32_sint32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.key");
+  map_sint32_sint32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint32Sint32Entry.value");
+  map_sint64_sint64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.key");
+  map_sint64_sint64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapSint64Sint64Entry.value");
+  map_fixed32_fixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.key");
+  map_fixed32_fixed32_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed32Fixed32Entry.value");
+  map_fixed64_fixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.key");
+  map_fixed64_fixed64_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapFixed64Fixed64Entry.value");
+  map_sfixed32_sfixed32_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed32Sfixed32Entry.key");
+  map_sfixed32_sfixed32_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed32Sfixed32Entry.value");
+  map_sfixed64_sfixed64_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapSfixed64Sfixed64Entry.key");
+  map_sfixed64_sfixed64_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapSfixed64Sfixed64Entry.value");
+  map_int32_float_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.key");
+  map_int32_float_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32FloatEntry.value");
+  map_int32_double_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.key");
+  map_int32_double_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32DoubleEntry.value");
+  map_bool_bool_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.key");
+  map_bool_bool_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapBoolBoolEntry.value");
+  map_string_string_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.key");
+  map_string_string_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapStringStringEntry.value");
+  map_int32_bytes_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.key");
+  map_int32_bytes_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32BytesEntry.value");
+  map_int32_enum_key_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.key");
+  map_int32_enum_val_ =
+      pool->FindFieldByName(package + ".TestMap.MapInt32EnumEntry.value");
+  map_int32_foreign_message_key_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.key");
+  map_int32_foreign_message_val_ = pool->FindFieldByName(
+      package + ".TestMap.MapInt32ForeignMessageEntry.value");
+
+  EXPECT_FALSE(map_enum_foo_ == nullptr);
+  EXPECT_FALSE(map_enum_bar_ == nullptr);
+  EXPECT_FALSE(map_enum_baz_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_key_ == nullptr);
+  EXPECT_FALSE(map_int32_int32_val_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_key_ == nullptr);
+  EXPECT_FALSE(map_int64_int64_val_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_key_ == nullptr);
+  EXPECT_FALSE(map_uint32_uint32_val_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_key_ == nullptr);
+  EXPECT_FALSE(map_uint64_uint64_val_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_key_ == nullptr);
+  EXPECT_FALSE(map_sint32_sint32_val_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_key_ == nullptr);
+  EXPECT_FALSE(map_sint64_sint64_val_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_key_ == nullptr);
+  EXPECT_FALSE(map_fixed32_fixed32_val_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_key_ == nullptr);
+  EXPECT_FALSE(map_fixed64_fixed64_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed32_sfixed32_val_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_key_ == nullptr);
+  EXPECT_FALSE(map_sfixed64_sfixed64_val_ == nullptr);
+  EXPECT_FALSE(map_int32_float_key_ == nullptr);
+  EXPECT_FALSE(map_int32_float_val_ == nullptr);
+  EXPECT_FALSE(map_int32_double_key_ == nullptr);
+  EXPECT_FALSE(map_int32_double_val_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_key_ == nullptr);
+  EXPECT_FALSE(map_bool_bool_val_ == nullptr);
+  EXPECT_FALSE(map_string_string_key_ == nullptr);
+  EXPECT_FALSE(map_string_string_val_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_key_ == nullptr);
+  EXPECT_FALSE(map_int32_bytes_val_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_key_ == nullptr);
+  EXPECT_FALSE(map_int32_enum_val_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_key_ == nullptr);
+  EXPECT_FALSE(map_int32_foreign_message_val_ == nullptr);
+}
+
+// Shorthand to get a FieldDescriptor for a field of unittest::TestMap.
+inline const FieldDescriptor* MapReflectionTester::F(const std::string& name) {
+  const FieldDescriptor* result = nullptr;
+  result = base_descriptor_->FindFieldByName(name);
+  GOOGLE_CHECK(result != nullptr);
+  return result;
+}
+
+inline void MapReflectionTester::SetMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+  Message* sub_foreign_message = nullptr;
+
+  // Add first element.
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         0);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          0);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 0);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 0);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 0);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 0);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          0.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, false);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, false);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "0");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 0);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "0");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 0);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_bar_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 0);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 0);
+
+  // Add second element
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_int32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_int64_int64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_uint32_uint32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_uint64_uint64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt32(sub_message, map_sint32_sint32_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_key_,
+                                         1);
+  sub_message->GetReflection()->SetInt64(sub_message, map_sint64_sint64_val_,
+                                         1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt32(sub_message, map_fixed32_fixed32_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_key_,
+                                          1);
+  sub_message->GetReflection()->SetUInt64(sub_message, map_fixed64_fixed64_val_,
+                                          1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_key_, 1);
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_sfixed32_sfixed32_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_key_, 1);
+  sub_message->GetReflection()->SetInt64(sub_message,
+                                         map_sfixed64_sfixed64_val_, 1);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_float_key_, 1);
+  sub_message->GetReflection()->SetFloat(sub_message, map_int32_float_val_,
+                                         1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_double_key_, 1);
+  sub_message->GetReflection()->SetDouble(sub_message, map_int32_double_val_,
+                                          1.0);
+
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_key_, true);
+  sub_message->GetReflection()->SetBool(sub_message, map_bool_bool_val_, true);
+
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_key_,
+                                          "1");
+  sub_message->GetReflection()->SetString(sub_message, map_string_string_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_bytes_key_, 1);
+  sub_message->GetReflection()->SetString(sub_message, map_int32_bytes_val_,
+                                          "1");
+
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  sub_message->GetReflection()->SetInt32(sub_message, map_int32_enum_key_, 1);
+  sub_message->GetReflection()->SetEnum(sub_message, map_int32_enum_val_,
+                                        map_enum_baz_);
+
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  sub_message->GetReflection()->SetInt32(sub_message,
+                                         map_int32_foreign_message_key_, 1);
+  sub_foreign_message = sub_message->GetReflection()->MutableMessage(
+      sub_message, map_int32_foreign_message_val_, nullptr);
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 1);
+}
+
+inline void MapReflectionTester::SetMapFieldsViaMapReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  Message* sub_foreign_message = nullptr;
+  MapValueRef map_val;
+
+  // Add first element.
+  MapKey map_key;
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                 map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                 map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint64_uint64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint32_sint32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sint64_sint64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetUInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed32_fixed32"), map_key, &map_val));
+  map_val.SetUInt32Value(0);
+
+  map_key.SetUInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_fixed64_fixed64"), map_key, &map_val));
+  map_val.SetUInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed32_sfixed32"), map_key, &map_val));
+  map_val.SetInt32Value(0);
+
+  map_key.SetInt64Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_sfixed64_sfixed64"), map_key, &map_val));
+  map_val.SetInt64Value(0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"),
+                                                 map_key, &map_val));
+  map_val.SetFloatValue(0.0);
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"),
+                                                 map_key, &map_val));
+  map_val.SetDoubleValue(0.0);
+
+  map_key.SetBoolValue(false);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"),
+                                                 map_key, &map_val));
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("0");
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_string_string"), map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"),
+                                                 map_key, &map_val));
+  map_val.SetStringValue("0");
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"),
+                                                 map_key, &map_val));
+  map_val.SetEnumValue(map_enum_bar_->number());
+
+  map_key.SetInt32Value(0);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 0);
+
+  // Add second element
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                 map_key, &map_val));
+  map_val.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                  map_key, &map_val));
+
+  map_key.SetInt64Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                 map_key, &map_val));
+  map_val.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                  map_key, &map_val));
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
+                                     &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
+                                     &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(1);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
+                                     map_key, &map_val);
+  map_val.SetInt32Value(1);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
+                                     map_key, &map_val);
+  map_val.SetInt64Value(1);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
+                                     &map_val);
+  map_val.SetFloatValue(1.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
+                                     &map_val);
+  map_val.SetDoubleValue(1.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
+                                     &map_val);
+  map_val.SetBoolValue(true);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("1");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
+                                     &map_val);
+  map_val.SetEnumValue(map_enum_baz_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_TRUE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 1);
+}
+
+inline void MapReflectionTester::GetMapValueViaMapReflection(
+    Message* message, const std::string& field_name, const MapKey& map_key,
+    MapValueRef* map_val) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
+                                                  map_key, map_val));
+}
+
+inline Message* MapReflectionTester::GetMapEntryViaReflection(
+    Message* message, const std::string& field_name, int index) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MutableRepeatedMessage(message, F(field_name), index);
+}
+
+inline MapIterator MapReflectionTester::MapBegin(
+    Message* message, const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapBegin(message, F(field_name));
+}
+
+inline MapIterator MapReflectionTester::MapEnd(Message* message,
+                                               const std::string& field_name) {
+  const Reflection* reflection = message->GetReflection();
+  return reflection->MapEnd(message, F(field_name));
+}
+
+inline void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, F("map_int32_int32"));
+  reflection->ClearField(message, F("map_int64_int64"));
+  reflection->ClearField(message, F("map_uint32_uint32"));
+  reflection->ClearField(message, F("map_uint64_uint64"));
+  reflection->ClearField(message, F("map_sint32_sint32"));
+  reflection->ClearField(message, F("map_sint64_sint64"));
+  reflection->ClearField(message, F("map_fixed32_fixed32"));
+  reflection->ClearField(message, F("map_fixed64_fixed64"));
+  reflection->ClearField(message, F("map_sfixed32_sfixed32"));
+  reflection->ClearField(message, F("map_sfixed64_sfixed64"));
+  reflection->ClearField(message, F("map_int32_float"));
+  reflection->ClearField(message, F("map_int32_double"));
+  reflection->ClearField(message, F("map_bool_bool"));
+  reflection->ClearField(message, F("map_string_string"));
+  reflection->ClearField(message, F("map_int32_bytes"));
+  reflection->ClearField(message, F("map_int32_enum"));
+  reflection->ClearField(message, F("map_int32_foreign_message"));
+}
+
+inline void MapReflectionTester::ModifyMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  MapValueRef map_val;
+  Message* sub_foreign_message;
+
+  // Modify the second element
+  MapKey map_key;
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"),
+                                                  map_key, &map_val));
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"),
+                                                  map_key, &map_val));
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_uint32_uint32"), map_key, &map_val));
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key,
+                                     &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key,
+                                     &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetUInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key,
+                                     &map_val);
+  map_val.SetUInt32Value(2);
+
+  map_key.SetUInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key,
+                                     &map_val);
+  map_val.SetUInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"),
+                                     map_key, &map_val);
+  map_val.SetInt32Value(2);
+
+  map_key.SetInt64Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"),
+                                     map_key, &map_val);
+  map_val.SetInt64Value(2);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key,
+                                     &map_val);
+  map_val.SetFloatValue(2.0);
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key,
+                                     &map_val);
+  map_val.SetDoubleValue(2.0);
+
+  map_key.SetBoolValue(true);
+  reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key,
+                                     &map_val);
+  map_val.SetBoolValue(false);
+
+  map_key.SetStringValue("1");
+  reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key,
+                                     &map_val);
+  map_val.SetStringValue("2");
+
+  map_key.SetInt32Value(1);
+  reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key,
+                                     &map_val);
+  map_val.SetEnumValue(map_enum_foo_->number());
+
+  map_key.SetInt32Value(1);
+  EXPECT_FALSE(reflection->InsertOrLookupMapValue(
+      message, F("map_int32_foreign_message"), map_key, &map_val));
+  sub_foreign_message = map_val.MutableMessageValue();
+  sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message,
+                                                 foreign_c_, 2);
+}
+
+inline void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->RemoveLast(message, field);
+  }
+}
+
+inline void MapReflectionTester::ReleaseLastMapsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
+
+    Message* released = reflection->ReleaseLast(message, field);
+    ASSERT_TRUE(released != nullptr)
+        << "ReleaseLast returned nullptr for: " << field->name();
+    delete released;
+  }
+}
+
+inline void MapReflectionTester::SwapMapsViaReflection(Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  std::vector<const FieldDescriptor*> output;
+  reflection->ListFields(*message, &output);
+  for (int i = 0; i < output.size(); ++i) {
+    const FieldDescriptor* field = output[i];
+    if (!field->is_repeated()) continue;
+    reflection->SwapElements(message, field, 0, 1);
+  }
+}
+
+inline void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  Message* sub_message = nullptr;
+
+  sub_message = reflection->AddMessage(message, F("map_int32_int32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int64_int64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint32_uint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_uint64_uint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint32_sint32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sint64_sint64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed32_fixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_fixed64_fixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed32_sfixed32"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_sfixed64_sfixed64"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_float"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_double"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_bool_bool"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_string_string"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_bytes"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_enum"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+  sub_message = reflection->AddMessage(message, F("map_int32_foreign_message"));
+  EXPECT_TRUE(sub_message->GetReflection()->MutableUnknownFields(sub_message) !=
+              nullptr);
+}
+
+inline void MapReflectionTester::ExpectMapFieldsSetViaReflection(
+    const Message& message) {
+  std::string scratch;
+  const Reflection* reflection = message.GetReflection();
+  const Message* sub_message;
+  MapKey map_key;
+
+  // -----------------------------------------------------------------
+
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_int32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_int32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_TRUE(
+          reflection->ContainsMapKey(message, F("map_int32_int32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(*sub_message,
+                                                         map_int64_int64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(*sub_message,
+                                                         map_int64_int64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_TRUE(
+          reflection->ContainsMapKey(message, F("map_int64_int64"), map_key));
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      // Check with RepeatedField Reflection
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i);
+      uint32 key = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_uint32_uint32_key_);
+      uint32 val = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_uint32_uint32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt32Value(key);
+      EXPECT_TRUE(
+          reflection->ContainsMapKey(message, F("map_uint32_uint32"), map_key));
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i);
+      uint64 key = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_uint64_uint64_key_);
+      uint64 val = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_uint64_uint64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt64Value(key);
+      EXPECT_TRUE(
+          reflection->ContainsMapKey(message, F("map_uint64_uint64"), map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sint32_sint32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sint32_sint32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_sint32_sint32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sint64_sint64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sint64_sint64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_sint64_sint64"), map_key));
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_fixed32_fixed32"), i);
+      uint32 key = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_fixed32_fixed32_key_);
+      uint32 val = sub_message->GetReflection()->GetUInt32(
+          *sub_message, map_fixed32_fixed32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_fixed32_fixed32"), map_key));
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_fixed64_fixed64"), i);
+      uint64 key = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_fixed64_fixed64_key_);
+      uint64 val = sub_message->GetReflection()->GetUInt64(
+          *sub_message, map_fixed64_fixed64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetUInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_fixed64_fixed64"), map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_sfixed32_sfixed32"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sfixed32_sfixed32_key_);
+      int32 val = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_sfixed32_sfixed32_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_sfixed32_sfixed32"), map_key));
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_sfixed64_sfixed64"), i);
+      int64 key = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sfixed64_sfixed64_key_);
+      int64 val = sub_message->GetReflection()->GetInt64(
+          *sub_message, map_sfixed64_sfixed64_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt64Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_sfixed64_sfixed64"), map_key));
+    }
+  }
+  {
+    std::map<int32, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_float"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_float_key_);
+      float val = sub_message->GetReflection()->GetFloat(*sub_message,
+                                                         map_int32_float_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_float"),
+                                                 map_key));
+    }
+  }
+  {
+    std::map<int32, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_double"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_double_key_);
+      double val = sub_message->GetReflection()->GetDouble(
+          *sub_message, map_int32_double_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_double"),
+                                                 map_key));
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i);
+      bool key = sub_message->GetReflection()->GetBool(*sub_message,
+                                                       map_bool_bool_key_);
+      bool val = sub_message->GetReflection()->GetBool(*sub_message,
+                                                       map_bool_bool_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetBoolValue(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"),
+                                                 map_key));
+    }
+  }
+  {
+    std::map<std::string, std::string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_string_string"), i);
+      std::string key = sub_message->GetReflection()->GetString(
+          *sub_message, map_string_string_key_);
+      std::string val = sub_message->GetReflection()->GetString(
+          *sub_message, map_string_string_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetStringValue(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_string_string"), map_key));
+    }
+  }
+  {
+    std::map<int32, std::string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_bytes_key_);
+      std::string val = sub_message->GetReflection()->GetString(
+          *sub_message, map_int32_bytes_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_bytes"),
+                                                 map_key));
+    }
+  }
+  {
+    std::map<int32, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (int i = 0; i < 2; i++) {
+      sub_message =
+          &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(*sub_message,
+                                                         map_int32_enum_key_);
+      const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum(
+          *sub_message, map_int32_enum_val_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"),
+                                                 map_key));
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (int i = 0; i < 2; i++) {
+      sub_message = &reflection->GetRepeatedMessage(
+          message, F("map_int32_foreign_message"), i);
+      int32 key = sub_message->GetReflection()->GetInt32(
+          *sub_message, map_int32_foreign_message_key_);
+      const Message& foreign_message = sub_message->GetReflection()->GetMessage(
+          *sub_message, map_int32_foreign_message_val_);
+      int32 val = foreign_message.GetReflection()->GetInt32(foreign_message,
+                                                            foreign_c_);
+      EXPECT_EQ(map[key], val);
+      // Check with Map Reflection
+      map_key.SetInt32Value(key);
+      EXPECT_EQ(true, reflection->ContainsMapKey(
+                          message, F("map_int32_foreign_message"), map_key));
+    }
+  }
+}
+
+inline void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator(
+    Message* message) {
+  std::string scratch;
+  std::string serialized;
+  const Reflection* reflection = message->GetReflection();
+
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum")));
+  ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message")));
+
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32"));
+         iter != reflection->MapEnd(message, F("map_int32_int32"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64"));
+         iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_uint32_uint32"));
+         iter != reflection->MapEnd(message, F("map_uint32_uint32")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_uint64_uint64"));
+         iter != reflection->MapEnd(message, F("map_uint64_uint64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sint32_sint32"));
+         iter != reflection->MapEnd(message, F("map_sint32_sint32")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int64, int64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sint64_sint64"));
+         iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt64Value()],
+                iter.GetValueRef().GetInt64Value());
+    }
+  }
+  {
+    std::map<uint32, uint32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_fixed32_fixed32"));
+         iter != reflection->MapEnd(message, F("map_fixed32_fixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt32Value()],
+                iter.GetValueRef().GetUInt32Value());
+    }
+  }
+  {
+    std::map<uint64, uint64> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_fixed64_fixed64"));
+         iter != reflection->MapEnd(message, F("map_fixed64_fixed64"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetUInt64Value()],
+                iter.GetValueRef().GetUInt64Value());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_sfixed32_sfixed32"));
+         iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32"));
+         ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetInt32Value());
+    }
+  }
+  {
+    std::map<int32, float> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float"));
+         iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetFloatValue());
+    }
+  }
+  {
+    std::map<int32, double> map;
+    map[0] = 0.0;
+    map[1] = 1.0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_int32_double"));
+         iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetDoubleValue());
+    }
+  }
+  {
+    std::map<bool, bool> map;
+    map[false] = false;
+    map[true] = true;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool"));
+         iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetBoolValue()],
+                iter.GetValueRef().GetBoolValue());
+    }
+  }
+  {
+    std::map<std::string, std::string> map;
+    map["0"] = "0";
+    map["1"] = "1";
+    int size = 0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_string_string"));
+         iter != reflection->MapEnd(message, F("map_string_string"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      EXPECT_EQ(map[iter.GetKey().GetStringValue()],
+                iter.GetValueRef().GetStringValue());
+    }
+    EXPECT_EQ(size, 2);
+  }
+  {
+    std::map<int32, std::string> map;
+    map[0] = "0";
+    map[1] = "1";
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes"));
+         iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                iter.GetValueRef().GetStringValue());
+    }
+  }
+  {
+    std::map<int32, const EnumValueDescriptor*> map;
+    map[0] = map_enum_bar_;
+    map[1] = map_enum_baz_;
+    for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum"));
+         iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) {
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(),
+                iter.GetValueRef().GetEnumValue());
+    }
+  }
+  {
+    std::map<int32, int32> map;
+    map[0] = 0;
+    map[1] = 1;
+    int size = 0;
+    for (MapIterator iter =
+             reflection->MapBegin(message, F("map_int32_foreign_message"));
+         iter != reflection->MapEnd(message, F("map_int32_foreign_message"));
+         ++iter, ++size) {
+      // Check const methods do not invalidate map.
+      message->DebugString();
+      message->ShortDebugString();
+      message->SerializeToString(&serialized);
+      message->SpaceUsedLong();
+      message->ByteSizeLong();
+      const Message& sub_message = iter.GetValueRef().GetMessageValue();
+      EXPECT_EQ(map[iter.GetKey().GetInt32Value()],
+                sub_message.GetReflection()->GetInt32(sub_message, foreign_c_));
+    }
+    EXPECT_EQ(size, 2);
+  }
+}
+
+inline void MapReflectionTester::ExpectClearViaReflection(
+    const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+  // Map fields are empty.
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum")));
+  EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message")));
+  EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message"))
+                  ->IsMapValid());
+}
+
+inline void MapReflectionTester::ExpectClearViaReflectionIterator(
+    Message* message) {
+  const Reflection* reflection = message->GetReflection();
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) ==
+              reflection->MapEnd(message, F("map_int32_int32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) ==
+              reflection->MapEnd(message, F("map_int64_int64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) ==
+              reflection->MapEnd(message, F("map_uint32_uint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) ==
+              reflection->MapEnd(message, F("map_uint64_uint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) ==
+              reflection->MapEnd(message, F("map_sint32_sint32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) ==
+              reflection->MapEnd(message, F("map_sint64_sint64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) ==
+              reflection->MapEnd(message, F("map_fixed32_fixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) ==
+              reflection->MapEnd(message, F("map_fixed64_fixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) ==
+              reflection->MapEnd(message, F("map_sfixed32_sfixed32")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) ==
+              reflection->MapEnd(message, F("map_sfixed64_sfixed64")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) ==
+              reflection->MapEnd(message, F("map_int32_float")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) ==
+              reflection->MapEnd(message, F("map_int32_double")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) ==
+              reflection->MapEnd(message, F("map_bool_bool")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) ==
+              reflection->MapEnd(message, F("map_string_string")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) ==
+              reflection->MapEnd(message, F("map_int32_bytes")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) ==
+              reflection->MapEnd(message, F("map_int32_enum")));
+  EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) ==
+              reflection->MapEnd(message, F("map_int32_foreign_message")));
+}
+
 }  // namespace protobuf
 }  // namespace google
 
+#include <google/protobuf/port_undef.inc>
+
 #endif  // GOOGLE_PROTOBUF_MAP_TEST_UTIL_H__
diff --git a/src/google/protobuf/map_test_util.inc b/src/google/protobuf/map_test_util.inc
new file mode 100755
index 0000000..600fdc3
--- /dev/null
+++ b/src/google/protobuf/map_test_util.inc
@@ -0,0 +1,271 @@
+// 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/map_test_util_impl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+
+class MapTestUtil {
+ public:
+  // Set every field in the TestMap message to a unique value.
+  static void SetMapFields(UNITTEST::TestMap* message);
+
+  // Set every field in the TestArenaMap message to a unique value.
+  static void SetArenaMapFields(UNITTEST::TestArenaMap* message);
+
+  // Set every field in the message to a default value.
+  static void SetMapFieldsInitialized(UNITTEST::TestMap* message);
+
+  // Modify all the map fields of the message (which should already have been
+  // initialized with SetMapFields()).
+  static void ModifyMapFields(UNITTEST::TestMap* message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called.
+  static void ExpectMapFieldsSet(const UNITTEST::TestMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFields() is called for TestArenaMap.
+  static void ExpectArenaMapFieldsSet(const UNITTEST::TestArenaMap& message);
+
+  // Check that all fields have the values that they should have after
+  // SetMapFieldsInitialized() is called.
+  static void ExpectMapFieldsSetInitialized(const UNITTEST::TestMap& message);
+
+  // Expect that the message is modified as would be expected from
+  // ModifyMapFields().
+  static void ExpectMapFieldsModified(const UNITTEST::TestMap& message);
+
+  // Check that all fields are empty.
+  static void ExpectClear(const UNITTEST::TestMap& message);
+
+  // Check that all map fields have the given size.
+  static void ExpectMapsSize(const UNITTEST::TestMap& message, int size);
+
+  // Get pointers of map entries at given index.
+  static std::vector<const Message*> GetMapEntries(
+      const UNITTEST::TestMap& message, int index);
+
+  // Get pointers of map entries from release.
+  static std::vector<const Message*> GetMapEntriesFromRelease(
+      UNITTEST::TestMap* message);
+};
+
+inline void MapTestUtil::SetMapFields(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::SetMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::SetArenaMapFields(UNITTEST::TestArenaMap* message) {
+  MapTestUtilImpl::SetArenaMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                     UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::SetMapFieldsInitialized(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::SetMapFieldsInitialized(message);
+}
+
+inline void MapTestUtil::ModifyMapFields(UNITTEST::TestMap* message) {
+  MapTestUtilImpl::ModifyMapFields<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectClear(const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectClear(message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsSet(const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSet<UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR,
+                                      UNITTEST::MAP_ENUM_BAZ>(message);
+}
+
+inline void MapTestUtil::ExpectArenaMapFieldsSet(
+    const UNITTEST::TestArenaMap& message) {
+  MapTestUtilImpl::ExpectArenaMapFieldsSet<
+      UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR, UNITTEST::MAP_ENUM_BAZ>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsSetInitialized(
+    const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsSetInitialized<UNITTEST::MapEnum,
+                                                 UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapFieldsModified(
+    const UNITTEST::TestMap& message) {
+  MapTestUtilImpl::ExpectMapFieldsModified<
+      UNITTEST::MapEnum, UNITTEST::MAP_ENUM_BAR, UNITTEST::MAP_ENUM_FOO>(
+      message);
+}
+
+inline void MapTestUtil::ExpectMapsSize(const UNITTEST::TestMap& message,
+                                        int size) {
+  const Descriptor* descriptor = message.GetDescriptor();
+
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_int32")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int64_int64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_uint32_uint32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_uint64_uint64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sint32_sint32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sint64_sint64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_float")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_int32_double")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_bool_bool")));
+  EXPECT_EQ(size,
+            message.GetReflection()->FieldSize(
+                message, descriptor->FindFieldByName("map_string_string")));
+  EXPECT_EQ(size, message.GetReflection()->FieldSize(
+                      message, descriptor->FindFieldByName("map_int32_bytes")));
+  EXPECT_EQ(
+      size,
+      message.GetReflection()->FieldSize(
+          message, descriptor->FindFieldByName("map_int32_foreign_message")));
+}
+
+inline std::vector<const Message*> MapTestUtil::GetMapEntries(
+    const UNITTEST::TestMap& message, int index) {
+  const Descriptor* descriptor = message.GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_int32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int64_int64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_uint32_uint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_uint64_uint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sint32_sint32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sint64_sint64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_fixed32_fixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_fixed64_fixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sfixed32_sfixed32"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_sfixed64_sfixed64"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_float"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_double"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_bool_bool"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_string_string"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_bytes"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_enum"), index));
+  result.push_back(&message.GetReflection()->GetRepeatedMessage(
+      message, descriptor->FindFieldByName("map_int32_foreign_message"),
+      index));
+
+  return result;
+}
+
+inline std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease(
+    UNITTEST::TestMap* message) {
+  const Descriptor* descriptor = message->GetDescriptor();
+  std::vector<const Message*> result;
+
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_int32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int64_int64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_uint32_uint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_uint64_uint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sint32_sint32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sint64_sint64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_fixed32_fixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_fixed64_fixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sfixed32_sfixed32")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_sfixed64_sfixed64")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_float")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_double")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_bool_bool")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_string_string")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_bytes")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_enum")));
+  result.push_back(message->GetReflection()->ReleaseLast(
+      message, descriptor->FindFieldByName("map_int32_foreign_message")));
+
+  return result;
+}
+
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 7964a97..4bfa64d 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -172,11 +172,8 @@
   static inline const char* Read(const char* ptr, ParseContext* ctx,
                                  MapEntryAccessorType* value);
 
-  static inline void Write(int field, const MapEntryAccessorType& value,
-                           io::CodedOutputStream* output);
-  static inline uint8* WriteToArray(int field,
-                                    const MapEntryAccessorType& value,
-                                    uint8* target);
+  static inline uint8* Write(int field, const MapEntryAccessorType& value,
+                             uint8* ptr, io::EpsCopyOutputStream* stream);
 
   // Functions to manipulate data on memory. ========================
   static inline const Type& GetExternalReference(const Type* value);
@@ -230,11 +227,8 @@
                             MapEntryAccessorType* value);                     \
     static inline const char* Read(const char* begin, ParseContext* ctx,      \
                                    MapEntryAccessorType* value);              \
-    static inline void Write(int field, const MapEntryAccessorType& value,    \
-                             io::CodedOutputStream* output);                  \
-    static inline uint8* WriteToArray(int field,                              \
-                                      const MapEntryAccessorType& value,      \
-                                      uint8* target);                         \
+    static inline uint8* Write(int field, const MapEntryAccessorType& value,  \
+                               uint8* ptr, io::EpsCopyOutputStream* stream);  \
     static inline const MapEntryAccessorType& GetExternalReference(           \
         const TypeOnMemory& value);                                           \
     static inline void DeleteNoArena(const TypeOnMemory& x);                  \
@@ -365,34 +359,35 @@
 #undef GET_FIXED_CACHED_SIZE
 
 template <typename Type>
-inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
-    int field, const MapEntryAccessorType& value,
-    io::CodedOutputStream* output) {
-  WireFormatLite::WriteMessageMaybeToArray(field, value, output);
-}
-
-template <typename Type>
-inline uint8* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray(
-    int field, const MapEntryAccessorType& value, uint8* target) {
-  return WireFormatLite::InternalWriteMessageToArray(field, value, target);
+inline uint8* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write(
+    int field, const MapEntryAccessorType& value, uint8* ptr,
+    io::EpsCopyOutputStream* stream) {
+  stream->EnsureSpace(&ptr);
+  return WireFormatLite::InternalWriteMessageToArray(field, value, ptr, stream);
 }
 
 #define WRITE_METHOD(FieldType, DeclaredType)                                  \
   template <typename Type>                                                     \
-  inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write(   \
-      int field, const MapEntryAccessorType& value,                            \
-      io::CodedOutputStream* output) {                                         \
-    return WireFormatLite::Write##DeclaredType(field, value, output);          \
-  }                                                                            \
-  template <typename Type>                                                     \
-  inline uint8*                                                                \
-  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray(        \
-      int field, const MapEntryAccessorType& value, uint8* target) {           \
-    return WireFormatLite::Write##DeclaredType##ToArray(field, value, target); \
+  inline uint8* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \
+      int field, const MapEntryAccessorType& value, uint8* ptr,                \
+      io::EpsCopyOutputStream* stream) {                                       \
+    stream->EnsureSpace(&ptr);                                                 \
+    return stream->Write##DeclaredType(field, value, ptr);                     \
   }
 
 WRITE_METHOD(STRING, String)
 WRITE_METHOD(BYTES, Bytes)
+
+#undef WRITE_METHOD
+#define WRITE_METHOD(FieldType, DeclaredType)                                  \
+  template <typename Type>                                                     \
+  inline uint8* MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \
+      int field, const MapEntryAccessorType& value, uint8* ptr,                \
+      io::EpsCopyOutputStream* stream) {                                       \
+    stream->EnsureSpace(&ptr);                                                 \
+    return WireFormatLite::Write##DeclaredType##ToArray(field, value, ptr);    \
+  }
+
 WRITE_METHOD(INT64, Int64)
 WRITE_METHOD(UINT64, UInt64)
 WRITE_METHOD(INT32, Int32)
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 804c2ce..ab7f5a2 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -527,14 +527,10 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Message::SerializeWithCachedSizes(io::CodedOutputStream* output) const {
-  const internal::SerializationTable* table =
-      static_cast<const internal::SerializationTable*>(InternalGetTable());
-  if (table == 0) {
-    WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output);
-  } else {
-    internal::TableSerialize(*this, table, output);
-  }
+uint8* Message::InternalSerializeWithCachedSizesToArray(
+    uint8* target, io::EpsCopyOutputStream* stream) const {
+  return WireFormat::InternalSerializeWithCachedSizesToArray(*this, target,
+                                                             stream);
 }
 
 size_t Message::ByteSizeLong() const {
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index da44a36..19d77b1 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -304,7 +304,8 @@
   bool MergePartialFromCodedStream(io::CodedInputStream* input) override;
 #endif
   size_t ByteSizeLong() const override;
-  void SerializeWithCachedSizes(io::CodedOutputStream* output) const override;
+  uint8* InternalSerializeWithCachedSizesToArray(
+      uint8* target, io::EpsCopyOutputStream* stream) const override;
 
  private:
   // This is called only by the default implementation of ByteSize(), to
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 0848f34..2babba0 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -341,30 +341,38 @@
 
 // ===================================================================
 
-uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
-  const internal::SerializationTable* table =
-      static_cast<const internal::SerializationTable*>(InternalGetTable());
-  auto deterministic =
-      io::CodedOutputStream::IsDefaultSerializationDeterministic();
-  if (table) {
-    return internal::TableSerializeToArray(*this, table, deterministic, target);
+inline uint8* SerializeToArrayImpl(const MessageLite& msg, uint8* target,
+                                   int size) {
+  constexpr bool debug = false;
+  if (debug) {
+    // Force serialization to a stream with a block size of 1, which forces
+    // all writes to the stream to cross buffers triggering all fallback paths
+    // in the unittests when serializing to string / array.
+    io::ArrayOutputStream stream(target, size, 1);
+    uint8* ptr;
+    io::EpsCopyOutputStream out(
+        &stream, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+        &ptr);
+    ptr = msg.InternalSerializeWithCachedSizesToArray(ptr, &out);
+    out.Trim(ptr);
+    GOOGLE_DCHECK(!out.HadError() && stream.ByteCount() == size);
+    return target + size;
   } else {
-    if (deterministic) {
-      // We only optimize this when using optimize_for = SPEED.  In other cases
-      // we just use the CodedOutputStream path.
-      int size = GetCachedSize();
-      io::ArrayOutputStream out(target, size);
-      io::CodedOutputStream coded_out(&out);
-      coded_out.SetSerializationDeterministic(true);
-      SerializeWithCachedSizes(&coded_out);
-      GOOGLE_CHECK(!coded_out.HadError());
-      return target + size;
-    } else {
-      return InternalSerializeWithCachedSizesToArray(target);
-    }
+    io::EpsCopyOutputStream out(
+        target, size,
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    auto res = msg.InternalSerializeWithCachedSizesToArray(target, &out);
+    GOOGLE_DCHECK(target + size == res);
+    return res;
   }
 }
 
+uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
+  // We only optimize this when using optimize_for = SPEED.  In other cases
+  // we just use the CodedOutputStream path.
+  return SerializeToArrayImpl(*this, target, GetCachedSize());
+}
+
 bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
   return SerializePartialToCodedStream(output);
@@ -379,16 +387,6 @@
     return false;
   }
 
-  if (!output->IsSerializationDeterministic()) {
-    uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
-    if (buffer != nullptr) {
-      uint8* end = InternalSerializeWithCachedSizesToArray(buffer);
-      if (end - buffer != size) {
-        ByteSizeConsistencyError(size, ByteSizeLong(), end - buffer, *this);
-      }
-      return true;
-    }
-  }
   int original_byte_count = output->ByteCount();
   SerializeWithCachedSizes(output);
   if (output->HadError()) {
@@ -406,14 +404,27 @@
 
 bool MessageLite::SerializeToZeroCopyStream(
     io::ZeroCopyOutputStream* output) const {
-  io::CodedOutputStream encoder(output);
-  return SerializeToCodedStream(&encoder);
+  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+  return SerializePartialToZeroCopyStream(output);
 }
 
 bool MessageLite::SerializePartialToZeroCopyStream(
     io::ZeroCopyOutputStream* output) const {
-  io::CodedOutputStream encoder(output);
-  return SerializePartialToCodedStream(&encoder);
+  const size_t size = ByteSizeLong();  // Force size to be cached.
+  if (size > INT_MAX) {
+    GOOGLE_LOG(ERROR) << GetTypeName()
+               << " exceeded maximum protobuf size of 2GB: " << size;
+    return false;
+  }
+
+  uint8* target;
+  io::EpsCopyOutputStream stream(
+      output, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
+      &target);
+  target = InternalSerializeWithCachedSizesToArray(target, &stream);
+  stream.Trim(target);
+  if (stream.HadError()) return false;
+  return true;
 }
 
 bool MessageLite::SerializeToFileDescriptor(int file_descriptor) const {
@@ -456,10 +467,7 @@
   STLStringResizeUninitialized(output, old_size + byte_size);
   uint8* start =
       reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
-  uint8* end = SerializeWithCachedSizesToArray(start);
-  if (end - start != byte_size) {
-    ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
-  }
+  SerializeToArrayImpl(*this, start, byte_size);
   return true;
 }
 
@@ -487,10 +495,7 @@
   }
   if (size < byte_size) return false;
   uint8* start = reinterpret_cast<uint8*>(data);
-  uint8* end = SerializeWithCachedSizesToArray(start);
-  if (end - start != byte_size) {
-    ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
-  }
+  SerializeToArrayImpl(*this, start, byte_size);
   return true;
 }
 
@@ -510,38 +515,6 @@
   return output;
 }
 
-void MessageLite::SerializeWithCachedSizes(
-    io::CodedOutputStream* output) const {
-  GOOGLE_DCHECK(InternalGetTable());
-  internal::TableSerialize(
-      *this,
-      static_cast<const internal::SerializationTable*>(InternalGetTable()),
-      output);
-}
-
-
-// The table driven code optimizes the case that the CodedOutputStream buffer
-// is large enough to serialize into it directly.
-// If the proto is optimized for speed, this method will be overridden by
-// generated code for maximum speed. If the proto is optimized for size or
-// is lite, then we need to specialize this to avoid infinite recursion.
-uint8* MessageLite::InternalSerializeWithCachedSizesToArray(
-    uint8* target) const {
-  const internal::SerializationTable* table =
-      static_cast<const internal::SerializationTable*>(InternalGetTable());
-  if (table == NULL) {
-    // We only optimize this when using optimize_for = SPEED.  In other cases
-    // we just use the CodedOutputStream path.
-    int size = GetCachedSize();
-    io::ArrayOutputStream out(target, size);
-    io::CodedOutputStream coded_out(&out);
-    SerializeWithCachedSizes(&coded_out);
-    GOOGLE_CHECK(!coded_out.HadError());
-    return target + size;
-  } else {
-    return internal::TableSerializeToArray(*this, table, false, target);
-  }
-}
 
 namespace internal {
 
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index a9abb94..949e200 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -44,6 +44,7 @@
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/arena.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/port.h>
@@ -320,7 +321,7 @@
   // (for groups) or input->ConsumedEntireMessage() (for non-groups) after
   // this returns to verify that the message's end was delimited correctly.
   //
-  // ParsefromCodedStream() is implemented as Clear() followed by
+  // ParseFromCodedStream() is implemented as Clear() followed by
   // MergeFromCodedStream().
   bool MergeFromCodedStream(io::CodedInputStream* input);
 
@@ -407,7 +408,10 @@
   // Serializes the message without recomputing the size.  The message must not
   // have changed since the last call to ByteSize(), and the value returned by
   // ByteSize must be non-negative.  Otherwise the results are undefined.
-  virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const;
+  void SerializeWithCachedSizes(io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeWithCachedSizesToArray(output->Cur(),
+                                                           output->EpsCopy()));
+  }
 
   // Functions below here are not part of the public interface.  It isn't
   // enforced, but they should be treated as private, and will be private
@@ -419,7 +423,7 @@
   // must point at a byte array of at least ByteSize() bytes.  Whether to use
   // deterministic serialization, e.g., maps in sorted order, is determined by
   // CodedOutputStream::IsDefaultSerializationDeterministic().
-  virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
+  uint8* SerializeWithCachedSizesToArray(uint8* target) const;
 
   // Returns the result of the last call to ByteSize().  An embedded message's
   // size is needed both to serialize it (because embedded messages are
@@ -477,15 +481,15 @@
   template <ParseFlags flags, typename T>
   bool ParseFrom(const T& input);
 
+  // Fast path when conditions match (ie. non-deterministic)
+  //  uint8* InternalSerializeWithCachedSizesToArray(uint8* ptr) const;
+  virtual uint8* InternalSerializeWithCachedSizesToArray(
+      uint8* ptr, io::EpsCopyOutputStream* stream) const = 0;
+
  private:
   // TODO(gerbens) make this a pure abstract function
   virtual const void* InternalGetTable() const { return NULL; }
 
-  // Fast path when conditions match (ie. non-deterministic)
- public:
-  virtual uint8* InternalSerializeWithCachedSizesToArray(uint8* target) const;
-
- private:
   friend class internal::WireFormatLite;
   friend class Message;
   friend class internal::WeakFieldMap;
diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h
index 6345226..555fd4e 100644
--- a/src/google/protobuf/port.h
+++ b/src/google/protobuf/port.h
@@ -1,6 +1,43 @@
-#ifndef THIRD_PARTY_PROTOBUF_TESTING_PROTOBUF_SRC_GOOGLE_PROTOBUF_PORT_H_
-#define THIRD_PARTY_PROTOBUF_TESTING_PROTOBUF_SRC_GOOGLE_PROTOBUF_PORT_H_
+// 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.
+
+// A common header that is included across all protobuf headers.  We do our best
+// to avoid #defining any macros here; instead we generally put macros in
+// port_def.inc and port_undef.inc so they are not visible from outside of
+// protobuf.
+
+#ifndef GOOGLE_PROTOBUF_PORT_H__
+#define GOOGLE_PROTOBUF_PORT_H__
+
 
 #include <google/protobuf/stubs/port.h>
 
-#endif  // THIRD_PARTY_PROTOBUF_TESTING_PROTOBUF_SRC_GOOGLE_PROTOBUF_PORT_H_
+
+#endif  // GOOGLE_PROTOBUF_PORT_H__
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 3964d44..dd79d42 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -1835,7 +1835,9 @@
   }
 
   virtual void TearDown() {
-    STLDeleteContainerPointers(nested_ptrs.begin(), nested_ptrs.end());
+    for (auto ptr : nested_ptrs) {
+      delete ptr;
+    }
   }
 };
 
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 5263fc6..877814b 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -220,31 +219,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void SourceContext::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.SourceContext)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string file_name = 1;
-  if (this->file_name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->file_name().data(), static_cast<int>(this->file_name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.SourceContext.file_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->file_name(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.SourceContext)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* SourceContext::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -255,14 +231,13 @@
       this->file_name().data(), static_cast<int>(this->file_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.SourceContext.file_name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->file_name(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.SourceContext)
   return target;
@@ -272,11 +247,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -288,6 +258,10 @@
         this->file_name());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index cd11d23..13c4e07 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -141,10 +141,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 124fdfa..2f9876f 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -352,62 +351,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Struct::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Struct)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // map<string, .google.protobuf.Value> fields = 1;
-  if (!this->fields().empty()) {
-    typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_pointer
-        ConstPtr;
-    typedef ConstPtr SortItem;
-    typedef ::PROTOBUF_NAMESPACE_ID::internal::CompareByDerefFirst<SortItem> Less;
-    struct Utf8Check {
-      static void Check(ConstPtr p) {
-        ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-          p->first.data(), static_cast<int>(p->first.length()),
-          ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-          "google.protobuf.Struct.FieldsEntry.key");
-      }
-    };
-
-    if (output->IsSerializationDeterministic() &&
-        this->fields().size() > 1) {
-      ::std::unique_ptr<SortItem[]> items(
-          new SortItem[this->fields().size()]);
-      typedef ::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::size_type size_type;
-      size_type n = 0;
-      for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
-          it = this->fields().begin();
-          it != this->fields().end(); ++it, ++n) {
-        items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);
-      }
-      ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
-      for (size_type i = 0; i < n; i++) {
-        Struct_FieldsEntry_DoNotUse::Funcs::SerializeToCodedStream(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, output);
-        Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
-      }
-    } else {
-      for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
-          it = this->fields().begin();
-          it != this->fields().end(); ++it) {
-        Struct_FieldsEntry_DoNotUse::Funcs::SerializeToCodedStream(1, it->first, it->second, output);
-        Utf8Check::Check(&(*it));
-      }
-    }
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Struct)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Struct::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -427,7 +372,7 @@
       }
     };
 
-    if (false &&
+    if (stream->IsSerializationDeterministic() &&
         this->fields().size() > 1) {
       ::std::unique_ptr<SortItem[]> items(
           new SortItem[this->fields().size()]);
@@ -440,22 +385,22 @@
       }
       ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());
       for (size_type i = 0; i < n; i++) {
-        target = Struct_FieldsEntry_DoNotUse::Funcs::SerializeToArray(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, target);
+        target = Struct_FieldsEntry_DoNotUse::Funcs::InternalSerialize(1, items[static_cast<ptrdiff_t>(i)]->first, items[static_cast<ptrdiff_t>(i)]->second, target, stream);
         Utf8Check::Check(&(*items[static_cast<ptrdiff_t>(i)]));
       }
     } else {
       for (::PROTOBUF_NAMESPACE_ID::Map< std::string, PROTOBUF_NAMESPACE_ID::Value >::const_iterator
           it = this->fields().begin();
           it != this->fields().end(); ++it) {
-        target = Struct_FieldsEntry_DoNotUse::Funcs::SerializeToArray(1, it->first, it->second, target);
+        target = Struct_FieldsEntry_DoNotUse::Funcs::InternalSerialize(1, it->first, it->second, target, stream);
         Utf8Check::Check(&(*it));
       }
     }
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Struct)
   return target;
@@ -465,11 +410,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -483,6 +423,10 @@
     total_size += Struct_FieldsEntry_DoNotUse::Funcs::ByteSizeLong(it->first, it->second);
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -912,71 +856,22 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Value::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Value)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // .google.protobuf.NullValue null_value = 1;
-  if (has_null_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      1, this->null_value(), output);
-  }
-
-  // double number_value = 2;
-  if (has_number_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDouble(2, this->number_value(), output);
-  }
-
-  // string string_value = 3;
-  if (has_string_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->string_value().data(), static_cast<int>(this->string_value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Value.string_value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      3, this->string_value(), output);
-  }
-
-  // bool bool_value = 4;
-  if (has_bool_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(4, this->bool_value(), output);
-  }
-
-  // .google.protobuf.Struct struct_value = 5;
-  if (has_struct_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5, _Internal::struct_value(this), output);
-  }
-
-  // .google.protobuf.ListValue list_value = 6;
-  if (has_list_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6, _Internal::list_value(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Value)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Value::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // .google.protobuf.NullValue null_value = 1;
   if (has_null_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       1, this->null_value(), target);
   }
 
   // double number_value = 2;
   if (has_number_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(2, this->number_value(), target);
   }
 
@@ -986,33 +881,35 @@
       this->string_value().data(), static_cast<int>(this->string_value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Value.string_value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         3, this->string_value(), target);
   }
 
   // bool bool_value = 4;
   if (has_bool_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(4, this->bool_value(), target);
   }
 
   // .google.protobuf.Struct struct_value = 5;
   if (has_struct_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        5, _Internal::struct_value(this), target);
+        5, _Internal::struct_value(this), target, stream);
   }
 
   // .google.protobuf.ListValue list_value = 6;
   if (has_list_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        6, _Internal::list_value(this), target);
+        6, _Internal::list_value(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
   return target;
@@ -1022,11 +919,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1073,6 +965,10 @@
       break;
     }
   }
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1311,45 +1207,23 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void ListValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.ListValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // repeated .google.protobuf.Value values = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->values_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      1,
-      this->values(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.ListValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* ListValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // repeated .google.protobuf.Value values = 1;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->values_size()); i < n; i++) {
+  for (auto it = this->values().pointer_begin(),
+            end = this->values().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        1, this->values(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(1, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
   return target;
@@ -1359,11 +1233,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1379,6 +1248,10 @@
     }
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index c4c8a15..c7c08f1 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -228,10 +228,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -401,10 +399,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -645,10 +641,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/stubs/map_util.h b/src/google/protobuf/stubs/map_util.h
index b04d9d4..24e098a 100644
--- a/src/google/protobuf/stubs/map_util.h
+++ b/src/google/protobuf/stubs/map_util.h
@@ -620,9 +620,8 @@
 // twice. Unlike UpdateReturnCopy this also does not come with the issue of an
 // undefined previous* in case new data was inserted.
 template <class Collection>
-typename Collection::value_type::second_type*
-InsertOrReturnExisting(Collection* const collection,
-                       const typename Collection::value_type& vt) {
+typename Collection::value_type::second_type* InsertOrReturnExisting(
+    Collection* const collection, const typename Collection::value_type& vt) {
   std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
   if (ret.second) {
     return nullptr;  // Inserted, no existing previous value.
@@ -633,8 +632,7 @@
 
 // Same as above, except for explicit key and data.
 template <class Collection>
-typename Collection::value_type::second_type*
-InsertOrReturnExisting(
+typename Collection::value_type::second_type* InsertOrReturnExisting(
     Collection* const collection,
     const typename Collection::value_type::first_type& key,
     const typename Collection::value_type::second_type& data) {
diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h
index 2c265e9..aa81eb6 100644
--- a/src/google/protobuf/stubs/stl_util.h
+++ b/src/google/protobuf/stubs/stl_util.h
@@ -38,26 +38,6 @@
 namespace google {
 namespace protobuf {
 
-// STLDeleteContainerPointers()
-//  For a range within a container of pointers, calls delete
-//  (non-array version) on these pointers.
-// NOTE: for these three functions, we could just implement a DeleteObject
-// functor and then call for_each() on the range and functor, but this
-// requires us to pull in all of algorithm.h, which seems expensive.
-// For hash_[multi]set, it is important that this deletes behind the iterator
-// because the hash_set may call the hash function on the iterator when it is
-// advanced, which could result in the hash function trying to deference a
-// stale pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPointers(ForwardIterator begin,
-                                ForwardIterator end) {
-  while (begin != end) {
-    ForwardIterator temp = begin;
-    ++begin;
-    delete *temp;
-  }
-}
-
 // Inside Google, this function implements a horrible, disgusting hack in which
 // we reach into the string's private implementation and resize it without
 // initializing the new bytes.  In some cases doing this can significantly
@@ -85,36 +65,6 @@
   return str->empty() ? nullptr : &*str->begin();
 }
 
-// STLDeleteElements() deletes all the elements in an STL container and clears
-// the container.  This function is suitable for use with a vector, set,
-// hash_set, or any other STL container which defines sensible begin(), end(),
-// and clear() methods.
-//
-// If container is nullptr, this function is a no-op.
-//
-// As an alternative to calling STLDeleteElements() directly, consider
-// ElementDeleter (defined below), which ensures that your container's elements
-// are deleted when the ElementDeleter goes out of scope.
-template <class T>
-void STLDeleteElements(T *container) {
-  if (!container) return;
-  STLDeleteContainerPointers(container->begin(), container->end());
-  container->clear();
-}
-
-// Given an STL container consisting of (key, value) pairs, STLDeleteValues
-// deletes all the "value" components and clears the container.  Does nothing
-// in the case it's given a null pointer.
-
-template <class T>
-void STLDeleteValues(T *v) {
-  if (!v) return;
-  for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
-    delete i->second;
-  }
-  v->clear();
-}
-
 }  // namespace protobuf
 }  // namespace google
 
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index e04ae3d..420c1e8 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -128,15 +128,6 @@
 
 // ===========================================================================
 // Implementation of the parse information tree class.
-TextFormat::ParseInfoTree::ParseInfoTree() {}
-
-TextFormat::ParseInfoTree::~ParseInfoTree() {
-  // Remove any nested information trees, as they are owned by this tree.
-  for (NestedMap::iterator it = nested_.begin(); it != nested_.end(); ++it) {
-    STLDeleteElements(&(it->second));
-  }
-}
-
 void TextFormat::ParseInfoTree::RecordLocation(
     const FieldDescriptor* field, TextFormat::ParseLocation location) {
   locations_[field].push_back(location);
@@ -145,11 +136,9 @@
 TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
     const FieldDescriptor* field) {
   // Owned by us in the map.
-  TextFormat::ParseInfoTree* instance = new TextFormat::ParseInfoTree();
-  std::vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
-  GOOGLE_CHECK(trees);
-  trees->push_back(instance);
-  return instance;
+  auto& vec = nested_[field];
+  vec.emplace_back(new TextFormat::ParseInfoTree());
+  return vec.back().get();
 }
 
 void CheckFieldIndex(const FieldDescriptor* field, int index) {
@@ -189,13 +178,12 @@
     index = 0;
   }
 
-  const std::vector<TextFormat::ParseInfoTree*>* trees =
-      FindOrNull(nested_, field);
-  if (trees == nullptr || index >= trees->size()) {
+  auto it = nested_.find(field);
+  if (it == nested_.end() || index >= it->second.size()) {
     return nullptr;
   }
 
-  return (*trees)[index];
+  return it->second[index].get();
 }
 
 namespace {
@@ -1807,11 +1795,6 @@
   SetUseUtf8StringEscaping(false);
 }
 
-TextFormat::Printer::~Printer() {
-  STLDeleteValues(&custom_printers_);
-  STLDeleteValues(&custom_message_printers_);
-}
-
 void TextFormat::Printer::SetUseUtf8StringEscaping(bool as_utf8) {
   SetDefaultFieldValuePrinter(as_utf8 ? new FastFieldValuePrinterUtf8Escaping()
                                       : new FastFieldValuePrinter());
@@ -1832,28 +1815,45 @@
   if (field == nullptr || printer == nullptr) {
     return false;
   }
-  FieldValuePrinterWrapper* const wrapper =
-      new FieldValuePrinterWrapper(nullptr);
-  if (custom_printers_.insert(std::make_pair(field, wrapper)).second) {
+  std::unique_ptr<FieldValuePrinterWrapper> wrapper(
+      new FieldValuePrinterWrapper(nullptr));
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
     wrapper->SetDelegate(printer);
+    pair.first->second = std::move(wrapper);
     return true;
   } else {
-    delete wrapper;
     return false;
   }
 }
 
 bool TextFormat::Printer::RegisterFieldValuePrinter(
     const FieldDescriptor* field, const FastFieldValuePrinter* printer) {
-  return field != nullptr && printer != nullptr &&
-         custom_printers_.insert(std::make_pair(field, printer)).second;
+  if (field == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair = custom_printers_.insert(std::make_pair(field, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
 }
 
 bool TextFormat::Printer::RegisterMessagePrinter(
     const Descriptor* descriptor, const MessagePrinter* printer) {
-  return descriptor != nullptr && printer != nullptr &&
-         custom_message_printers_.insert(std::make_pair(descriptor, printer))
-             .second;
+  if (descriptor == nullptr || printer == nullptr) {
+    return false;
+  }
+  auto pair =
+      custom_message_printers_.insert(std::make_pair(descriptor, nullptr));
+  if (pair.second) {
+    pair.first->second.reset(printer);
+    return true;
+  } else {
+    return false;
+  }
 }
 
 bool TextFormat::Printer::PrintToString(const Message& message,
@@ -1954,8 +1954,7 @@
   generator->PrintLiteral("[");
   generator->PrintString(type_url);
   generator->PrintLiteral("]");
-  const FastFieldValuePrinter* printer = FindWithDefault(
-      custom_printers_, value_field, default_field_value_printer_.get());
+  const FastFieldValuePrinter* printer = GetFieldPrinter(value_field);
   printer->PrintMessageStart(message, -1, 0, single_line_mode_, generator);
   generator->Indent();
   Print(*value_message, generator);
@@ -2230,8 +2229,7 @@
     PrintFieldName(message, field_index, count, reflection, field, generator);
 
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      const FastFieldValuePrinter* printer = FindWithDefault(
-          custom_printers_, field, default_field_value_printer_.get());
+      const FastFieldValuePrinter* printer = GetFieldPrinter(field);
       const Message& sub_message =
           field->is_repeated()
               ? (is_map ? *sorted_map_field[j]
@@ -2294,8 +2292,7 @@
     return;
   }
 
-  const FastFieldValuePrinter* printer = FindWithDefault(
-      custom_printers_, field, default_field_value_printer_.get());
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
   printer->PrintFieldName(message, field_index, field_count, reflection, field,
                           generator);
 }
@@ -2308,8 +2305,7 @@
   GOOGLE_DCHECK(field->is_repeated() || (index == -1))
       << "Index must be -1 for non-repeated fields";
 
-  const FastFieldValuePrinter* printer = FindWithDefault(
-      custom_printers_, field, default_field_value_printer_.get());
+  const FastFieldValuePrinter* printer = GetFieldPrinter(field);
 
   switch (field->cpp_type()) {
 #define OUTPUT_FIELD(CPPTYPE, METHOD)                                \
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 4ebab0e..2d755a9 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -234,7 +234,6 @@
   class PROTOBUF_EXPORT Printer {
    public:
     Printer();
-    ~Printer();
 
     // Like TextFormat::Print
     bool Print(const Message& message, io::ZeroCopyOutputStream* output) const;
@@ -392,28 +391,29 @@
 
     bool PrintAny(const Message& message, TextGenerator* generator) const;
 
+    const FastFieldValuePrinter* GetFieldPrinter(
+        const FieldDescriptor* field) const {
+      auto it = custom_printers_.find(field);
+      return it == custom_printers_.end() ? default_field_value_printer_.get()
+                                          : it->second.get();
+    }
+
     int initial_indent_level_;
-
     bool single_line_mode_;
-
     bool use_field_number_;
-
     bool use_short_repeated_primitives_;
-
     bool hide_unknown_fields_;
-
     bool print_message_fields_in_index_order_;
-
     bool expand_any_;
-
     int64 truncate_string_field_longer_than_;
 
     std::unique_ptr<const FastFieldValuePrinter> default_field_value_printer_;
-    typedef std::map<const FieldDescriptor*, const FastFieldValuePrinter*>
+    typedef std::map<const FieldDescriptor*,
+                     std::unique_ptr<const FastFieldValuePrinter>>
         CustomPrinterMap;
     CustomPrinterMap custom_printers_;
 
-    typedef std::map<const Descriptor*, const MessagePrinter*>
+    typedef std::map<const Descriptor*, std::unique_ptr<const MessagePrinter>>
         CustomMessagePrinterMap;
     CustomMessagePrinterMap custom_message_printers_;
 
@@ -466,8 +466,9 @@
   // value parsed from the text.
   class PROTOBUF_EXPORT ParseInfoTree {
    public:
-    ParseInfoTree();
-    ~ParseInfoTree();
+    ParseInfoTree() = default;
+    ParseInfoTree(const ParseInfoTree&) = delete;
+    ParseInfoTree& operator=(const ParseInfoTree&) = delete;
 
     // Returns the parse location for index-th value of the field in the parsed
     // text. If none exists, returns a location with line = -1. Index should be
@@ -496,13 +497,12 @@
 
     // Defines the map from the index-th field descriptor to the nested parse
     // info tree.
-    typedef std::map<const FieldDescriptor*, std::vector<ParseInfoTree*> >
+    typedef std::map<const FieldDescriptor*,
+                     std::vector<std::unique_ptr<ParseInfoTree>>>
         NestedMap;
 
     LocationMap locations_;
     NestedMap nested_;
-
-    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParseInfoTree);
   };
 
   // For more control over parsing, use this class.
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index c05fb12..009320e 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -254,48 +253,27 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Timestamp::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Timestamp)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // int64 seconds = 1;
-  if (this->seconds() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64(1, this->seconds(), output);
-  }
-
-  // int32 nanos = 2;
-  if (this->nanos() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->nanos(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Timestamp)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Timestamp::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // int64 seconds = 1;
   if (this->seconds() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->seconds(), target);
   }
 
   // int32 nanos = 2;
   if (this->nanos() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->nanos(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Timestamp)
   return target;
@@ -305,11 +283,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -328,6 +301,10 @@
         this->nanos());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 85d0454..4c42992 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -156,10 +156,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index e6c061f..734010d 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -672,71 +671,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Type::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Type)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Type.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.Field fields = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->fields_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->fields(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated string oneofs = 3;
-  for (int i = 0, n = this->oneofs_size(); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->oneofs(i).data(), static_cast<int>(this->oneofs(i).length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Type.oneofs");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteString(
-      3, this->oneofs(i), output);
-  }
-
-  // repeated .google.protobuf.Option options = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  // .google.protobuf.SourceContext source_context = 5;
-  if (this->has_source_context()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5, _Internal::source_context(this), output);
-  }
-
-  // .google.protobuf.Syntax syntax = 6;
-  if (this->syntax() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      6, this->syntax(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Type)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Type::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -747,53 +683,55 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Type.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.Field fields = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->fields_size()); i < n; i++) {
+  for (auto it = this->fields().pointer_begin(),
+            end = this->fields().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->fields(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // repeated string oneofs = 3;
-  for (int i = 0, n = this->oneofs_size(); i < n; i++) {
+  for (auto it = this->oneofs().pointer_begin(),
+            end = this->oneofs().pointer_end(); it < end; ++it) {
+    const auto& s = **it;
     ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->oneofs(i).data(), static_cast<int>(this->oneofs(i).length()),
+      s.data(), static_cast<int>(s.length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Type.oneofs");
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      WriteStringToArray(3, this->oneofs(i), target);
+    target = stream->WriteString(3, s, target);
   }
 
   // repeated .google.protobuf.Option options = 4;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        4, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(4, **it, target, stream);
   }
 
   // .google.protobuf.SourceContext source_context = 5;
   if (this->has_source_context()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        5, _Internal::source_context(this), target);
+        5, _Internal::source_context(this), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 6;
   if (this->syntax() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       6, this->syntax(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type)
   return target;
@@ -803,11 +741,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -862,6 +795,10 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->syntax());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1321,115 +1258,29 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Field::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Field)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // .google.protobuf.Field.Kind kind = 1;
-  if (this->kind() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      1, this->kind(), output);
-  }
-
-  // .google.protobuf.Field.Cardinality cardinality = 2;
-  if (this->cardinality() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      2, this->cardinality(), output);
-  }
-
-  // int32 number = 3;
-  if (this->number() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(3, this->number(), output);
-  }
-
-  // string name = 4;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Field.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      4, this->name(), output);
-  }
-
-  // string type_url = 6;
-  if (this->type_url().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->type_url().data(), static_cast<int>(this->type_url().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Field.type_url");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      6, this->type_url(), output);
-  }
-
-  // int32 oneof_index = 7;
-  if (this->oneof_index() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(7, this->oneof_index(), output);
-  }
-
-  // bool packed = 8;
-  if (this->packed() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(8, this->packed(), output);
-  }
-
-  // repeated .google.protobuf.Option options = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      9,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  // string json_name = 10;
-  if (this->json_name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->json_name().data(), static_cast<int>(this->json_name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Field.json_name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      10, this->json_name(), output);
-  }
-
-  // string default_value = 11;
-  if (this->default_value().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->default_value().data(), static_cast<int>(this->default_value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Field.default_value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      11, this->default_value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Field)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Field::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // .google.protobuf.Field.Kind kind = 1;
   if (this->kind() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       1, this->kind(), target);
   }
 
   // .google.protobuf.Field.Cardinality cardinality = 2;
   if (this->cardinality() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       2, this->cardinality(), target);
   }
 
   // int32 number = 3;
   if (this->number() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(3, this->number(), target);
   }
 
@@ -1439,8 +1290,7 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Field.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         4, this->name(), target);
   }
 
@@ -1450,27 +1300,28 @@
       this->type_url().data(), static_cast<int>(this->type_url().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Field.type_url");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         6, this->type_url(), target);
   }
 
   // int32 oneof_index = 7;
   if (this->oneof_index() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(7, this->oneof_index(), target);
   }
 
   // bool packed = 8;
   if (this->packed() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(8, this->packed(), target);
   }
 
   // repeated .google.protobuf.Option options = 9;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        9, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(9, **it, target, stream);
   }
 
   // string json_name = 10;
@@ -1479,8 +1330,7 @@
       this->json_name().data(), static_cast<int>(this->json_name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Field.json_name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         10, this->json_name(), target);
   }
 
@@ -1490,14 +1340,13 @@
       this->default_value().data(), static_cast<int>(this->default_value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Field.default_value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         11, this->default_value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field)
   return target;
@@ -1507,11 +1356,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1586,6 +1430,10 @@
     total_size += 1 + 1;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1972,61 +1820,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Enum::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Enum)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Enum.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // repeated .google.protobuf.EnumValue enumvalue = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enumvalue_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2,
-      this->enumvalue(static_cast<int>(i)),
-      output);
-  }
-
-  // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  // .google.protobuf.SourceContext source_context = 4;
-  if (this->has_source_context()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      4, _Internal::source_context(this), output);
-  }
-
-  // .google.protobuf.Syntax syntax = 5;
-  if (this->syntax() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnum(
-      5, this->syntax(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Enum)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Enum::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2037,43 +1832,44 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Enum.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // repeated .google.protobuf.EnumValue enumvalue = 2;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->enumvalue_size()); i < n; i++) {
+  for (auto it = this->enumvalue().pointer_begin(),
+            end = this->enumvalue().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        2, this->enumvalue(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(2, **it, target, stream);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        3, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(3, **it, target, stream);
   }
 
   // .google.protobuf.SourceContext source_context = 4;
   if (this->has_source_context()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        4, _Internal::source_context(this), target);
+        4, _Internal::source_context(this), target, stream);
   }
 
   // .google.protobuf.Syntax syntax = 5;
   if (this->syntax() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteEnumToArray(
       5, this->syntax(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum)
   return target;
@@ -2083,11 +1879,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2134,6 +1925,10 @@
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::EnumSize(this->syntax());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2411,45 +2206,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void EnumValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.EnumValue.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // int32 number = 2;
-  if (this->number() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(2, this->number(), output);
-  }
-
-  // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3,
-      this->options(static_cast<int>(i)),
-      output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* EnumValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2460,27 +2218,27 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.EnumValue.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // int32 number = 2;
   if (this->number() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(2, this->number(), target);
   }
 
   // repeated .google.protobuf.Option options = 3;
-  for (unsigned int i = 0,
-      n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
+  for (auto it = this->options().pointer_begin(),
+            end = this->options().pointer_end(); it < end; ++it) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
-      InternalWriteMessageToArray(
-        3, this->options(static_cast<int>(i)), target);
+      InternalWriteMessageToArray(3, **it, target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
   return target;
@@ -2490,11 +2248,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2524,6 +2277,10 @@
         this->number());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2801,37 +2558,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Option::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Option)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string name = 1;
-  if (this->name().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->name().data(), static_cast<int>(this->name().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.Option.name");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->name(), output);
-  }
-
-  // .google.protobuf.Any value = 2;
-  if (this->has_value()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2, _Internal::value(this), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Option)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Option::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2842,21 +2570,21 @@
       this->name().data(), static_cast<int>(this->name().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.Option.name");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->name(), target);
   }
 
   // .google.protobuf.Any value = 2;
   if (this->has_value()) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
       InternalWriteMessageToArray(
-        2, _Internal::value(this), target);
+        2, _Internal::value(this), target, stream);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
   return target;
@@ -2866,11 +2594,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2889,6 +2612,10 @@
         *value_);
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index b16b298..4742aec 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -269,10 +269,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -503,10 +501,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -884,10 +880,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1099,10 +1093,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1288,10 +1280,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 92e1cfe..935b760 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/parse_context.h>
+#include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -268,19 +269,12 @@
 }
 
 
-void UnknownField::SerializeLengthDelimitedNoTag(
-    io::CodedOutputStream* output) const {
-  GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
-  const std::string& data = *data_.length_delimited_.string_value;
-  output->WriteVarint32(data.size());
-  output->WriteRawMaybeAliased(data.data(), data.size());
-}
-
-uint8* UnknownField::SerializeLengthDelimitedNoTagToArray(uint8* target) const {
+uint8* UnknownField::InternalSerializeLengthDelimitedNoTag(
+    uint8* target, io::EpsCopyOutputStream* stream) const {
   GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type());
   const std::string& data = *data_.length_delimited_.string_value;
   target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target);
-  target = io::CodedOutputStream::WriteStringToArray(data, target);
+  target = stream->WriteRaw(data.data(), data.size(), target);
   return target;
 }
 
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 9f4a474..4d46ff4 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -56,11 +56,6 @@
 
 namespace google {
 namespace protobuf {
-namespace io {
-class CodedInputStream;     // coded_stream.h
-class CodedOutputStream;    // coded_stream.h
-class ZeroCopyInputStream;  // zero_copy_stream.h
-}  // namespace io
 namespace internal {
 class InternalMetadataWithArena;  // metadata.h
 class WireFormat;                 // wire_format.h
@@ -256,10 +251,14 @@
   // These methods can take advantage of the underlying implementation and may
   // archieve a better performance than using getters to retrieve the data and
   // do the serialization yourself.
-  void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const;
-  uint8* SerializeLengthDelimitedNoTagToArray(uint8* target) const;
+  void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const {
+    output->SetCur(InternalSerializeLengthDelimitedNoTag(output->Cur(),
+                                                         output->EpsCopy()));
+  }
 
   inline size_t GetLengthDelimitedSize() const;
+  uint8* InternalSerializeLengthDelimitedNoTag(
+      uint8* target, io::EpsCopyOutputStream* stream) const;
 
 
   // If this UnknownField contains a pointer, delete it.
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 74fe0f4..8704898 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -439,7 +439,7 @@
 
 void ProtoWriter::InvalidName(StringPiece unknown_name,
                               StringPiece message) {
-  listener_->InvalidName(location(), ToSnakeCase(unknown_name), message);
+  listener_->InvalidName(location(), unknown_name, message);
 }
 
 void ProtoWriter::InvalidValue(StringPiece type_name,
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 252184d..1e247eb 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -332,7 +332,6 @@
   return util::Status();
 }
 
-
 Status ProtoStreamObjectSource::RenderTimestamp(
     const ProtoStreamObjectSource* os, const google::protobuf::Type& type,
     StringPiece field_name, ObjectWriter* ow) {
@@ -747,7 +746,6 @@
   ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
 }
 
-
 void ProtoStreamObjectSource::DeleteRendererMap() {
   delete ProtoStreamObjectSource::renderers_;
   renderers_ = NULL;
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index af51a27..366b45c 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -185,7 +185,6 @@
   util::Status RenderPacked(const google::protobuf::Field* field,
                               ObjectWriter* ow) const;
 
-
   // Renders a google.protobuf.Timestamp value to ObjectWriter
   static util::Status RenderTimestamp(const ProtoStreamObjectSource* os,
                                         const google::protobuf::Type& type,
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index fe0714b..e42ac13 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -32,12 +32,12 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/wire_format.h>
+
 #include <stack>
 #include <string>
 #include <vector>
 
-#include <google/protobuf/wire_format.h>
-
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/stringprintf.h>
@@ -49,6 +49,7 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/message_lite.h>
 #include <google/protobuf/unknown_field_set.h>
 
 
@@ -188,53 +189,17 @@
   return true;
 }
 
-void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
-                                        io::CodedOutputStream* output) {
-  for (int i = 0; i < unknown_fields.field_count(); i++) {
-    const UnknownField& field = unknown_fields.field(i);
-    switch (field.type()) {
-      case UnknownField::TYPE_VARINT:
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_VARINT));
-        output->WriteVarint64(field.varint());
-        break;
-      case UnknownField::TYPE_FIXED32:
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_FIXED32));
-        output->WriteLittleEndian32(field.fixed32());
-        break;
-      case UnknownField::TYPE_FIXED64:
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_FIXED64));
-        output->WriteLittleEndian64(field.fixed64());
-        break;
-      case UnknownField::TYPE_LENGTH_DELIMITED:
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
-        output->WriteVarint32(field.length_delimited().size());
-        output->WriteRawMaybeAliased(field.length_delimited().data(),
-                                     field.length_delimited().size());
-        break;
-      case UnknownField::TYPE_GROUP:
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_START_GROUP));
-        SerializeUnknownFields(field.group(), output);
-        output->WriteVarint32(WireFormatLite::MakeTag(
-            field.number(), WireFormatLite::WIRETYPE_END_GROUP));
-        break;
-    }
-  }
-}
-
-uint8* WireFormat::SerializeUnknownFieldsToArray(
-    const UnknownFieldSet& unknown_fields, uint8* target) {
+uint8* WireFormat::InternalSerializeUnknownFieldsToArray(
+    const UnknownFieldSet& unknown_fields, uint8* target,
+    io::EpsCopyOutputStream* stream) {
   for (int i = 0; i < unknown_fields.field_count(); i++) {
     const UnknownField& field = unknown_fields.field(i);
 
+    stream->EnsureSpace(&target);
     switch (field.type()) {
       case UnknownField::TYPE_VARINT:
-        target = WireFormatLite::WriteInt64ToArray(field.number(),
-                                                   field.varint(), target);
+        target = WireFormatLite::WriteUInt64ToArray(field.number(),
+                                                    field.varint(), target);
         break;
       case UnknownField::TYPE_FIXED32:
         target = WireFormatLite::WriteFixed32ToArray(field.number(),
@@ -245,13 +210,15 @@
                                                      field.fixed64(), target);
         break;
       case UnknownField::TYPE_LENGTH_DELIMITED:
-        target = WireFormatLite::WriteBytesToArray(
-            field.number(), field.length_delimited(), target);
+        target = stream->WriteString(field.number(), field.length_delimited(),
+                                     target);
         break;
       case UnknownField::TYPE_GROUP:
         target = WireFormatLite::WriteTagToArray(
             field.number(), WireFormatLite::WIRETYPE_START_GROUP, target);
-        target = SerializeUnknownFieldsToArray(field.group(), target);
+        target = InternalSerializeUnknownFieldsToArray(field.group(), target,
+                                                       stream);
+        stream->EnsureSpace(&target);
         target = WireFormatLite::WriteTagToArray(
             field.number(), WireFormatLite::WIRETYPE_END_GROUP, target);
         break;
@@ -260,38 +227,16 @@
   return target;
 }
 
-void WireFormat::SerializeUnknownMessageSetItems(
-    const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) {
-  for (int i = 0; i < unknown_fields.field_count(); i++) {
-    const UnknownField& field = unknown_fields.field(i);
-    // The only unknown fields that are allowed to exist in a MessageSet are
-    // messages, which are length-delimited.
-    if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
-      // Start group.
-      output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag);
-
-      // Write type ID.
-      output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag);
-      output->WriteVarint32(field.number());
-
-      // Write message.
-      output->WriteVarint32(WireFormatLite::kMessageSetMessageTag);
-      field.SerializeLengthDelimitedNoTag(output);
-
-      // End group.
-      output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag);
-    }
-  }
-}
-
-uint8* WireFormat::SerializeUnknownMessageSetItemsToArray(
-    const UnknownFieldSet& unknown_fields, uint8* target) {
+uint8* WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8* target,
+    io::EpsCopyOutputStream* stream) {
   for (int i = 0; i < unknown_fields.field_count(); i++) {
     const UnknownField& field = unknown_fields.field(i);
 
     // The only unknown fields that are allowed to exist in a MessageSet are
     // messages, which are length-delimited.
     if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) {
+      stream->EnsureSpace(&target);
       // Start group.
       target = io::CodedOutputStream::WriteTagToArray(
           WireFormatLite::kMessageSetItemStartTag, target);
@@ -305,8 +250,10 @@
       // Write message.
       target = io::CodedOutputStream::WriteTagToArray(
           WireFormatLite::kMessageSetMessageTag, target);
-      target = field.SerializeLengthDelimitedNoTagToArray(target);
 
+      target = field.InternalSerializeLengthDelimitedNoTag(target, stream);
+
+      stream->EnsureSpace(&target);
       // End group.
       target = io::CodedOutputStream::WriteTagToArray(
           WireFormatLite::kMessageSetItemEndTag, target);
@@ -708,11 +655,10 @@
 
 // ===================================================================
 
-void WireFormat::SerializeWithCachedSizes(const Message& message, int size,
-                                          io::CodedOutputStream* output) {
+uint8* WireFormat::InternalSerializeWithCachedSizesToArray(
+    const Message& message, uint8* target, io::EpsCopyOutputStream* stream) {
   const Descriptor* descriptor = message.GetDescriptor();
   const Reflection* message_reflection = message.GetReflection();
-  int expected_endpoint = output->ByteCount() + size;
 
   std::vector<const FieldDescriptor*> fields;
 
@@ -725,27 +671,23 @@
     message_reflection->ListFields(message, &fields);
   }
 
-  for (int i = 0; i < fields.size(); i++) {
-    SerializeFieldWithCachedSizes(fields[i], message, output);
+  for (auto field : fields) {
+    target = InternalSerializeField(field, message, target, stream);
   }
 
   if (descriptor->options().message_set_wire_format()) {
-    SerializeUnknownMessageSetItems(
-        message_reflection->GetUnknownFields(message), output);
+    return InternalSerializeUnknownMessageSetItemsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
   } else {
-    SerializeUnknownFields(message_reflection->GetUnknownFields(message),
-                           output);
+    return InternalSerializeUnknownFieldsToArray(
+        message_reflection->GetUnknownFields(message), target, stream);
   }
-
-  GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint)
-      << ": Protocol message serialized to a size different from what was "
-         "originally expected.  Perhaps it was modified by another thread "
-         "during serialization?";
 }
 
-static void SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
-                                           const MapKey& value,
-                                           io::CodedOutputStream* output) {
+static uint8* SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
+                                             const MapKey& value, uint8* target,
+                                             io::EpsCopyOutputStream* stream) {
+  stream->EnsureSpace(&target);
   switch (field->type()) {
     case FieldDescriptor::TYPE_DOUBLE:
     case FieldDescriptor::TYPE_FLOAT:
@@ -755,10 +697,10 @@
     case FieldDescriptor::TYPE_ENUM:
       GOOGLE_LOG(FATAL) << "Unsupported";
       break;
-#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)                     \
-  case FieldDescriptor::TYPE_##FieldType:                                      \
-    WireFormatLite::Write##CamelFieldType(1, value.Get##CamelCppType##Value(), \
-                                          output);                             \
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        1, value.Get##CamelCppType##Value(), target);        \
     break;
       CASE_TYPE(INT64, Int64, Int64)
       CASE_TYPE(UINT64, UInt64, UInt64)
@@ -771,19 +713,23 @@
       CASE_TYPE(SFIXED64, SFixed64, Int64)
       CASE_TYPE(SINT32, SInt32, Int32)
       CASE_TYPE(SINT64, SInt64, Int64)
-      CASE_TYPE(STRING, String, String)
 #undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+      target = stream->WriteString(1, value.GetStringValue(), target);
+      break;
   }
+  return target;
 }
 
-static void SerializeMapValueRefWithCachedSizes(const FieldDescriptor* field,
-                                                const MapValueRef& value,
-                                                io::CodedOutputStream* output) {
+static uint8* SerializeMapValueRefWithCachedSizes(
+    const FieldDescriptor* field, const MapValueRef& value, uint8* target,
+    io::EpsCopyOutputStream* stream) {
+  stream->EnsureSpace(&target);
   switch (field->type()) {
-#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)                     \
-  case FieldDescriptor::TYPE_##FieldType:                                      \
-    WireFormatLite::Write##CamelFieldType(2, value.Get##CamelCppType##Value(), \
-                                          output);                             \
+#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType)   \
+  case FieldDescriptor::TYPE_##FieldType:                    \
+    target = WireFormatLite::Write##CamelFieldType##ToArray( \
+        2, value.Get##CamelCppType##Value(), target);        \
     break;
     CASE_TYPE(INT64, Int64, Int64)
     CASE_TYPE(UINT64, UInt64, UInt64)
@@ -799,12 +745,21 @@
     CASE_TYPE(ENUM, Enum, Enum)
     CASE_TYPE(DOUBLE, Double, Double)
     CASE_TYPE(FLOAT, Float, Float)
-    CASE_TYPE(STRING, String, String)
-    CASE_TYPE(BYTES, Bytes, String)
-    CASE_TYPE(MESSAGE, Message, Message)
-    CASE_TYPE(GROUP, Group, Message)
 #undef CASE_TYPE
+    case FieldDescriptor::TYPE_STRING:
+    case FieldDescriptor::TYPE_BYTES:
+      target = stream->WriteString(2, value.GetStringValue(), target);
+      break;
+    case FieldDescriptor::TYPE_MESSAGE:
+      target = WireFormatLite::InternalWriteMessageToArray(
+          2, value.GetMessageValue(), target, stream);
+      break;
+    case FieldDescriptor::TYPE_GROUP:
+      target = WireFormatLite::InternalWriteGroupToArray(
+          2, value.GetMessageValue(), target, stream);
+      break;
   }
+  return target;
 }
 
 class MapKeySorter {
@@ -850,33 +805,36 @@
   };
 };
 
-static void SerializeMapEntry(const FieldDescriptor* field, const MapKey& key,
-                              const MapValueRef& value,
-                              io::CodedOutputStream* output) {
+static uint8* InternalSerializeMapEntry(const FieldDescriptor* field,
+                                        const MapKey& key,
+                                        const MapValueRef& value, uint8* target,
+                                        io::EpsCopyOutputStream* stream) {
   const FieldDescriptor* key_field = field->message_type()->field(0);
   const FieldDescriptor* value_field = field->message_type()->field(1);
 
-  WireFormatLite::WriteTag(field->number(),
-                           WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
   size_t size = kMapEntryTagByteSize;
   size += MapKeyDataOnlyByteSize(key_field, key);
   size += MapValueRefDataOnlyByteSize(value_field, value);
-  output->WriteVarint32(size);
-  SerializeMapKeyWithCachedSizes(key_field, key, output);
-  SerializeMapValueRefWithCachedSizes(value_field, value, output);
+  stream->EnsureSpace(&target);
+  target = WireFormatLite::WriteTagToArray(
+      field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
+  target = io::CodedOutputStream::WriteVarint32ToArray(size, target);
+  target = SerializeMapKeyWithCachedSizes(key_field, key, target, stream);
+  target =
+      SerializeMapValueRefWithCachedSizes(value_field, value, target, stream);
+  return target;
 }
 
-void WireFormat::SerializeFieldWithCachedSizes(const FieldDescriptor* field,
-                                               const Message& message,
-                                               io::CodedOutputStream* output) {
+uint8* WireFormat::InternalSerializeField(const FieldDescriptor* field,
+                                          const Message& message, uint8* target,
+                                          io::EpsCopyOutputStream* stream) {
   const Reflection* message_reflection = message.GetReflection();
 
   if (field->is_extension() &&
       field->containing_type()->options().message_set_wire_format() &&
       field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
       !field->is_repeated()) {
-    SerializeMessageSetItemWithCachedSizes(field, message, output);
-    return;
+    return InternalSerializeMessageSetItem(field, message, target, stream);
   }
 
   // For map fields, we can use either repeated field reflection or map
@@ -897,7 +855,7 @@
     const MapFieldBase* map_field =
         message_reflection->GetMapData(message, field);
     if (map_field->IsMapValid()) {
-      if (output->IsSerializationDeterministic()) {
+      if (stream->IsSerializationDeterministic()) {
         std::vector<MapKey> sorted_key_list =
             MapKeySorter::SortKey(message, message_reflection, field);
         for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
@@ -905,7 +863,8 @@
           MapValueRef map_value;
           message_reflection->InsertOrLookupMapValue(
               const_cast<Message*>(&message), field, *it, &map_value);
-          SerializeMapEntry(field, *it, map_value, output);
+          target =
+              InternalSerializeMapEntry(field, *it, map_value, target, stream);
         }
       } else {
         for (MapIterator it = message_reflection->MapBegin(
@@ -913,14 +872,14 @@
              it !=
              message_reflection->MapEnd(const_cast<Message*>(&message), field);
              ++it) {
-          SerializeMapEntry(field, it.GetKey(), it.GetValueRef(), output);
+          target = InternalSerializeMapEntry(field, it.GetKey(),
+                                             it.GetValueRef(), target, stream);
         }
       }
 
-      return;
+      return target;
     }
   }
-
   int count = 0;
 
   if (field->is_repeated()) {
@@ -934,20 +893,57 @@
 
   // map_entries is for maps that'll be deterministically serialized.
   std::vector<const Message*> map_entries;
-  if (count > 1 && field->is_map() && output->IsSerializationDeterministic()) {
+  if (count > 1 && field->is_map() && stream->IsSerializationDeterministic()) {
     map_entries =
         DynamicMapSorter::Sort(message, count, message_reflection, field);
   }
 
-  const bool is_packed = field->is_packed();
-  if (is_packed && count > 0) {
-    WireFormatLite::WriteTag(field->number(),
-                             WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
-    const size_t data_size = FieldDataOnlyByteSize(field, message);
-    output->WriteVarint32(data_size);
+  if (field->is_packed()) {
+    if (count == 0) return target;
+    stream->EnsureSpace(&target);
+    switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)   \
+  case FieldDescriptor::TYPE_##TYPE: {                                      \
+    auto r = message_reflection->GetRepeatedField<CPPTYPE>(message, field); \
+    target = stream->Write##TYPE_METHOD##Packed(                            \
+        field->number(), r, FieldDataOnlyByteSize(field, message), target); \
+    break;                                                                  \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(INT32, int32, Int32, Int32)
+      HANDLE_PRIMITIVE_TYPE(INT64, int64, Int64, Int64)
+      HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64)
+      HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(ENUM, int, Enum, Enum)
+
+#undef HANDLE_PRIMITIVE_TYPE
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)   \
+  case FieldDescriptor::TYPE_##TYPE: {                                      \
+    auto r = message_reflection->GetRepeatedField<CPPTYPE>(message, field); \
+    target = stream->WriteFixedPacked(field->number(), r, target);          \
+    break;                                                                  \
+  }
+
+      HANDLE_PRIMITIVE_TYPE(FIXED32, uint32, Fixed32, UInt32)
+      HANDLE_PRIMITIVE_TYPE(FIXED64, uint64, Fixed64, UInt64)
+      HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32)
+      HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64)
+
+      HANDLE_PRIMITIVE_TYPE(FLOAT, float, Float, Float)
+      HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+      HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+      default:
+        GOOGLE_LOG(FATAL) << "Invalid descriptor";
+    }
+    return target;
   }
 
   for (int j = 0; j < count; j++) {
+    stream->EnsureSpace(&target);
     switch (field->type()) {
 #define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD)     \
   case FieldDescriptor::TYPE_##TYPE: {                                        \
@@ -956,11 +952,8 @@
             ? message_reflection->GetRepeated##CPPTYPE_METHOD(message, field, \
                                                               j)              \
             : message_reflection->Get##CPPTYPE_METHOD(message, field);        \
-    if (is_packed) {                                                          \
-      WireFormatLite::Write##TYPE_METHOD##NoTag(value, output);               \
-    } else {                                                                  \
-      WireFormatLite::Write##TYPE_METHOD(field->number(), value, output);     \
-    }                                                                         \
+    target = WireFormatLite::Write##TYPE_METHOD##ToArray(field->number(),     \
+                                                         value, target);      \
     break;                                                                    \
   }
 
@@ -984,7 +977,7 @@
 
 #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD)                         \
   case FieldDescriptor::TYPE_##TYPE:                                           \
-    WireFormatLite::Write##TYPE_METHOD(                                        \
+    target = WireFormatLite::InternalWrite##TYPE_METHOD##ToArray(              \
         field->number(),                                                       \
         field->is_repeated()                                                   \
             ? (map_entries.empty()                                             \
@@ -992,7 +985,7 @@
                                                                      field, j) \
                    : *map_entries[j])                                          \
             : message_reflection->Get##CPPTYPE_METHOD(message, field),         \
-        output);                                                               \
+        target, stream);                                                       \
     break;
 
       HANDLE_TYPE(GROUP, Group, Message)
@@ -1004,11 +997,8 @@
             field->is_repeated()
                 ? message_reflection->GetRepeatedEnum(message, field, j)
                 : message_reflection->GetEnum(message, field);
-        if (is_packed) {
-          WireFormatLite::WriteEnumNoTag(value->number(), output);
-        } else {
-          WireFormatLite::WriteEnum(field->number(), value->number(), output);
-        }
+        target = WireFormatLite::WriteEnumToArray(field->number(),
+                                                  value->number(), target);
         break;
       }
 
@@ -1031,7 +1021,7 @@
           VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE,
                                      field->full_name().c_str());
         }
-        WireFormatLite::WriteString(field->number(), value, output);
+        target = stream->WriteString(field->number(), value, target);
         break;
       }
 
@@ -1043,34 +1033,35 @@
                                                                  j, &scratch)
                 : message_reflection->GetStringReference(message, field,
                                                          &scratch);
-        WireFormatLite::WriteBytes(field->number(), value, output);
+        target = stream->WriteString(field->number(), value, target);
         break;
       }
     }
   }
+  return target;
 }
 
-void WireFormat::SerializeMessageSetItemWithCachedSizes(
-    const FieldDescriptor* field, const Message& message,
-    io::CodedOutputStream* output) {
+uint8* WireFormat::InternalSerializeMessageSetItem(
+    const FieldDescriptor* field, const Message& message, uint8* target,
+    io::EpsCopyOutputStream* stream) {
   const Reflection* message_reflection = message.GetReflection();
 
+  stream->EnsureSpace(&target);
   // Start group.
-  output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag);
-
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemStartTag, target);
   // Write type ID.
-  output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag);
-  output->WriteVarint32(field->number());
-
+  target = WireFormatLite::WriteUInt32ToArray(
+      WireFormatLite::kMessageSetTypeIdNumber, field->number(), target);
   // Write message.
-  output->WriteVarint32(WireFormatLite::kMessageSetMessageTag);
-
-  const Message& sub_message = message_reflection->GetMessage(message, field);
-  output->WriteVarint32(sub_message.GetCachedSize());
-  sub_message.SerializeWithCachedSizes(output);
-
+  target = WireFormatLite::InternalWriteMessageToArray(
+      WireFormatLite::kMessageSetMessageNumber,
+      message_reflection->GetMessage(message, field), target, stream);
   // End group.
-  output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag);
+  stream->EnsureSpace(&target);
+  target = io::CodedOutputStream::WriteTagToArray(
+      WireFormatLite::kMessageSetItemEndTag, target);
+  return target;
 }
 
 // ===================================================================
@@ -1355,6 +1346,14 @@
   return our_size;
 }
 
+// Compute the size of the UnknownFieldSet on the wire.
+size_t ComputeUnknownFieldsSize(const InternalMetadataWithArena& metadata,
+                                size_t total_size, CachedSize* cached_size) {
+  total_size += WireFormat::ComputeUnknownFieldsSize(metadata.unknown_fields());
+  cached_size->Set(ToCachedSize(total_size));
+  return total_size;
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index 1e03151..9721fe0 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -40,7 +40,9 @@
 #define GOOGLE_PROTOBUF_WIRE_FORMAT_H__
 
 #include <string>
+
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -54,10 +56,6 @@
 
 namespace google {
 namespace protobuf {
-namespace io {
-class CodedInputStream;   // coded_stream.h
-class CodedOutputStream;  // coded_stream.h
-}  // namespace io
 class UnknownFieldSet;  // unknown_field_set.h
 }  // namespace protobuf
 }  // namespace google
@@ -116,7 +114,17 @@
   //
   // These return false iff the underlying stream returns a write error.
   static void SerializeWithCachedSizes(const Message& message, int size,
-                                       io::CodedOutputStream* output);
+                                       io::CodedOutputStream* output) {
+    int expected_endpoint = output->ByteCount() + size;
+    output->SetCur(InternalSerializeWithCachedSizesToArray(
+        message, output->Cur(), output->EpsCopy()));
+    GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint)
+        << ": Protocol message serialized to a size different from what was "
+           "originally expected.  Perhaps it was modified by another thread "
+           "during serialization?";
+  }
+  static uint8* InternalSerializeWithCachedSizesToArray(
+      const Message& message, uint8* target, io::EpsCopyOutputStream* stream);
 
   // Implements Message::ByteSize() via reflection.  WARNING:  The result
   // of this method is *not* cached anywhere.  However, all embedded messages
@@ -150,19 +158,34 @@
 
   // Write the contents of an UnknownFieldSet to the output.
   static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields,
-                                     io::CodedOutputStream* output);
+                                     io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownFieldsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
   // Same as above, except writing directly to the provided buffer.
   // Requires that the buffer have sufficient capacity for
   // ComputeUnknownFieldsSize(unknown_fields).
   //
   // Returns a pointer past the last written byte.
   static uint8* SerializeUnknownFieldsToArray(
-      const UnknownFieldSet& unknown_fields, uint8* target);
+      const UnknownFieldSet& unknown_fields, uint8* target) {
+    io::EpsCopyOutputStream stream(
+        target, static_cast<int>(ComputeUnknownFieldsSize(unknown_fields)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalSerializeUnknownFieldsToArray(unknown_fields, target,
+                                                 &stream);
+  }
+  static uint8* InternalSerializeUnknownFieldsToArray(
+      const UnknownFieldSet& unknown_fields, uint8* target,
+      io::EpsCopyOutputStream* stream);
 
   // Same thing except for messages that have the message_set_wire_format
   // option.
   static void SerializeUnknownMessageSetItems(
-      const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output);
+      const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeUnknownMessageSetItemsToArray(
+        unknown_fields, output->Cur(), output->EpsCopy()));
+  }
   // Same as above, except writing directly to the provided buffer.
   // Requires that the buffer have sufficient capacity for
   // ComputeUnknownMessageSetItemsSize(unknown_fields).
@@ -170,6 +193,9 @@
   // Returns a pointer past the last written byte.
   static uint8* SerializeUnknownMessageSetItemsToArray(
       const UnknownFieldSet& unknown_fields, uint8* target);
+  static uint8* InternalSerializeUnknownMessageSetItemsToArray(
+      const UnknownFieldSet& unknown_fields, uint8* target,
+      io::EpsCopyOutputStream* stream);
 
   // Compute the size of the UnknownFieldSet on the wire.
   static size_t ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields);
@@ -196,7 +222,13 @@
   // Serialize a single field.
   static void SerializeFieldWithCachedSizes(
       const FieldDescriptor* field,  // Cannot be NULL
-      const Message& message, io::CodedOutputStream* output);
+      const Message& message, io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeField(field, message, output->Cur(),
+                                          output->EpsCopy()));
+  }
+  static uint8* InternalSerializeField(
+      const FieldDescriptor* field,  // Cannot be NULL
+      const Message& message, uint8* target, io::EpsCopyOutputStream* stream);
 
   // Compute size of a single field.  If the field is a message type, this
   // will call ByteSize() for the embedded message, insuring that it caches
@@ -210,7 +242,13 @@
                                           Message* message);
   static void SerializeMessageSetItemWithCachedSizes(
       const FieldDescriptor* field, const Message& message,
-      io::CodedOutputStream* output);
+      io::CodedOutputStream* output) {
+    output->SetCur(InternalSerializeMessageSetItem(
+        field, message, output->Cur(), output->EpsCopy()));
+  }
+  static uint8* InternalSerializeMessageSetItem(
+      const FieldDescriptor* field, const Message& message, uint8* target,
+      io::EpsCopyOutputStream* stream);
   static size_t MessageSetItemByteSize(const FieldDescriptor* field,
                                        const Message& message);
 
@@ -328,9 +366,11 @@
 }
 
 
-inline void SerializeUnknownMessageSetItems(
-    const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) {
-  WireFormat::SerializeUnknownMessageSetItems(unknown_fields, output);
+inline uint8* InternalSerializeUnknownMessageSetItemsToArray(
+    const UnknownFieldSet& unknown_fields, uint8* target,
+    io::EpsCopyOutputStream* stream) {
+  return WireFormat::InternalSerializeUnknownMessageSetItemsToArray(
+      unknown_fields, target, stream);
 }
 
 inline size_t ComputeUnknownMessageSetItemsSize(
@@ -338,6 +378,11 @@
   return WireFormat::ComputeUnknownMessageSetItemsSize(unknown_fields);
 }
 
+// Compute the size of the UnknownFieldSet on the wire.
+PROTOBUF_EXPORT
+size_t ComputeUnknownFieldsSize(const InternalMetadataWithArena& metadata,
+                                size_t size, CachedSize* cached_size);
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc
index b61697f..b48815e 100644
--- a/src/google/protobuf/wire_format_lite.cc
+++ b/src/google/protobuf/wire_format_lite.cc
@@ -524,15 +524,8 @@
 
 void WireFormatLite::WriteSubMessageMaybeToArray(
     int size, const MessageLite& value, io::CodedOutputStream* output) {
-  if (!output->IsSerializationDeterministic()) {
-    uint8* target = output->GetDirectBufferForNBytesAndAdvance(size);
-    if (target != nullptr) {
-      uint8* end = value.InternalSerializeWithCachedSizesToArray(target);
-      GOOGLE_DCHECK_EQ(end - target, size);
-      return;
-    }
-  }
-  value.SerializeWithCachedSizes(output);
+  output->SetCur(value.InternalSerializeWithCachedSizesToArray(
+      output->Cur(), output->EpsCopy()));
 }
 
 void WireFormatLite::WriteGroupMaybeToArray(int field_number,
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 244edf1..0f9687b 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -622,10 +622,12 @@
   // telling them whether to serialize deterministically.
   template <typename MessageType>
   PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteGroupToArray(
-      int field_number, const MessageType& value, uint8* target);
+      int field_number, const MessageType& value, uint8* target,
+      io::EpsCopyOutputStream* stream);
   template <typename MessageType>
   PROTOBUF_ALWAYS_INLINE static uint8* InternalWriteMessageToArray(
-      int field_number, const MessageType& value, uint8* target);
+      int field_number, const MessageType& value, uint8* target,
+      io::EpsCopyOutputStream* stream);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
@@ -641,11 +643,24 @@
   // that are non-deterministic always.
   PROTOBUF_ALWAYS_INLINE static uint8* WriteGroupToArray(
       int field_number, const MessageLite& value, uint8* target) {
-    return InternalWriteGroupToArray(field_number, value, target);
+    io::EpsCopyOutputStream stream(
+        target,
+        value.GetCachedSize() +
+            static_cast<int>(2 * io::CodedOutputStream::VarintSize32(
+                                     static_cast<uint32>(field_number) << 3)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteGroupToArray(field_number, value, target, &stream);
   }
   PROTOBUF_ALWAYS_INLINE static uint8* WriteMessageToArray(
       int field_number, const MessageLite& value, uint8* target) {
-    return InternalWriteMessageToArray(field_number, value, target);
+    int size = value.GetCachedSize();
+    io::EpsCopyOutputStream stream(
+        target,
+        size + static_cast<int>(io::CodedOutputStream::VarintSize32(
+                                    static_cast<uint32>(field_number) << 3) +
+                                io::CodedOutputStream::VarintSize32(size)),
+        io::CodedOutputStream::IsDefaultSerializationDeterministic());
+    return InternalWriteMessageToArray(field_number, value, target, &stream);
   }
 
   // Compute the byte size of a field.  The XxSize() functions do NOT include
@@ -885,9 +900,11 @@
   return ReadBytes(input, p);
 }
 
-inline void SerializeUnknownMessageSetItems(const std::string& unknown_fields,
-                                            io::CodedOutputStream* output) {
-  output->WriteString(unknown_fields);
+inline uint8* InternalSerializeUnknownMessageSetItemsToArray(
+    const std::string& unknown_fields, uint8* target,
+    io::EpsCopyOutputStream* stream) {
+  return stream->WriteRaw(unknown_fields.data(),
+                          static_cast<int>(unknown_fields.size()), target);
 }
 
 inline size_t ComputeUnknownMessageSetItemsSize(
@@ -1682,18 +1699,21 @@
 
 template <typename MessageType>
 inline uint8* WireFormatLite::InternalWriteGroupToArray(
-    int field_number, const MessageType& value, uint8* target) {
+    int field_number, const MessageType& value, uint8* target,
+    io::EpsCopyOutputStream* stream) {
   target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
-  target = value.InternalSerializeWithCachedSizesToArray(target);
+  target = value.InternalSerializeWithCachedSizesToArray(target, stream);
+  stream->EnsureSpace(&target);
   return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
 }
 template <typename MessageType>
 inline uint8* WireFormatLite::InternalWriteMessageToArray(
-    int field_number, const MessageType& value, uint8* target) {
+    int field_number, const MessageType& value, uint8* target,
+    io::EpsCopyOutputStream* stream) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   target = io::CodedOutputStream::WriteVarint32ToArray(
       static_cast<uint32>(value.GetCachedSize()), target);
-  return value.InternalSerializeWithCachedSizesToArray(target);
+  return value.InternalSerializeWithCachedSizesToArray(target, stream);
 }
 
 // See comment on ReadGroupNoVirtual to understand the need for this template
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 73d8c42..8cb2094 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -5,7 +5,6 @@
 
 #include <algorithm>
 
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/wire_format_lite.h>
@@ -449,38 +448,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void DoubleValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.DoubleValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // double value = 1;
-  if (!(this->value() <= 0 && this->value() >= 0)) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDouble(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.DoubleValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* DoubleValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // double value = 1;
   if (!(this->value() <= 0 && this->value() >= 0)) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DoubleValue)
   return target;
@@ -490,11 +472,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -504,6 +481,10 @@
     total_size += 1 + 8;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -711,38 +692,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void FloatValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.FloatValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // float value = 1;
-  if (!(this->value() <= 0 && this->value() >= 0)) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloat(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.FloatValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* FloatValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // float value = 1;
   if (!(this->value() <= 0 && this->value() >= 0)) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.FloatValue)
   return target;
@@ -752,11 +716,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -766,6 +725,10 @@
     total_size += 1 + 4;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -973,38 +936,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Int64Value::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Int64Value)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // int64 value = 1;
-  if (this->value() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Int64Value)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Int64Value::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // int64 value = 1;
   if (this->value() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt64ToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int64Value)
   return target;
@@ -1014,11 +960,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1030,6 +971,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1237,38 +1182,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void UInt64Value::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.UInt64Value)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // uint64 value = 1;
-  if (this->value() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.UInt64Value)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* UInt64Value::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // uint64 value = 1;
   if (this->value() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt64ToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt64Value)
   return target;
@@ -1278,11 +1206,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1294,6 +1217,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1501,38 +1428,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void Int32Value::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.Int32Value)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // int32 value = 1;
-  if (this->value() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.Int32Value)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* Int32Value::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // int32 value = 1;
   if (this->value() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteInt32ToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Int32Value)
   return target;
@@ -1542,11 +1452,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1558,6 +1463,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -1765,38 +1674,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void UInt32Value::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.UInt32Value)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // uint32 value = 1;
-  if (this->value() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.UInt32Value)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* UInt32Value::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // uint32 value = 1;
   if (this->value() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteUInt32ToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.UInt32Value)
   return target;
@@ -1806,11 +1698,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -1822,6 +1709,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2029,38 +1920,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void BoolValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.BoolValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // bool value = 1;
-  if (this->value() != 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBool(1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.BoolValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* BoolValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // bool value = 1;
   if (this->value() != 0) {
+    stream->EnsureSpace(&target);
     target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBoolToArray(1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BoolValue)
   return target;
@@ -2070,11 +1944,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2084,6 +1953,10 @@
     total_size += 1 + 1;
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2299,31 +2172,8 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void StringValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.StringValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // string value = 1;
-  if (this->value().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
-      this->value().data(), static_cast<int>(this->value().length()),
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
-      "google.protobuf.StringValue.value");
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringMaybeAliased(
-      1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.StringValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* StringValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
@@ -2334,14 +2184,13 @@
       this->value().data(), static_cast<int>(this->value().length()),
       ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
       "google.protobuf.StringValue.value");
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteStringToArray(
+    target = stream->WriteStringMaybeAliased(
         1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.StringValue)
   return target;
@@ -2351,11 +2200,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2367,6 +2211,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
@@ -2579,41 +2427,21 @@
 }
 #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
 
-void BytesValue::SerializeWithCachedSizes(
-    ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const {
-  // @@protoc_insertion_point(serialize_start:google.protobuf.BytesValue)
-  ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
-  (void) cached_has_bits;
-
-  // bytes value = 1;
-  if (this->value().size() > 0) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesMaybeAliased(
-      1, this->value(), output);
-  }
-
-  if (_internal_metadata_.have_unknown_fields()) {
-    ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFields(
-        _internal_metadata_.unknown_fields(), output);
-  }
-  // @@protoc_insertion_point(serialize_end:google.protobuf.BytesValue)
-}
-
 ::PROTOBUF_NAMESPACE_ID::uint8* BytesValue::InternalSerializeWithCachedSizesToArray(
-    ::PROTOBUF_NAMESPACE_ID::uint8* target) const {
+    ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   (void) cached_has_bits;
 
   // bytes value = 1;
   if (this->value().size() > 0) {
-    target =
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteBytesToArray(
+    target = stream->WriteBytesMaybeAliased(
         1, this->value(), target);
   }
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::SerializeUnknownFieldsToArray(
-        _internal_metadata_.unknown_fields(), target);
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::InternalSerializeUnknownFieldsToArray(
+        _internal_metadata_.unknown_fields(), target, stream);
   }
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.BytesValue)
   return target;
@@ -2623,11 +2451,6 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue)
   size_t total_size = 0;
 
-  if (_internal_metadata_.have_unknown_fields()) {
-    total_size +=
-      ::PROTOBUF_NAMESPACE_ID::internal::WireFormat::ComputeUnknownFieldsSize(
-        _internal_metadata_.unknown_fields());
-  }
   ::PROTOBUF_NAMESPACE_ID::uint32 cached_has_bits = 0;
   // Prevent compiler warnings about cached_has_bits being unused
   (void) cached_has_bits;
@@ -2639,6 +2462,10 @@
         this->value());
   }
 
+  if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
+    return ::PROTOBUF_NAMESPACE_ID::internal::ComputeUnknownFieldsSize(
+        _internal_metadata_, total_size, &_cached_size_);
+  }
   int cached_size = ::PROTOBUF_NAMESPACE_ID::internal::ToCachedSize(total_size);
   SetCachedSize(cached_size);
   return total_size;
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index b445c9a..f99c822 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -188,10 +188,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -342,10 +340,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -496,10 +492,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -650,10 +644,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -804,10 +796,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -958,10 +948,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1112,10 +1100,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1266,10 +1252,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private:
@@ -1435,10 +1419,8 @@
   bool MergePartialFromCodedStream(
       ::PROTOBUF_NAMESPACE_ID::io::CodedInputStream* input) final;
   #endif  // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER
-  void SerializeWithCachedSizes(
-      ::PROTOBUF_NAMESPACE_ID::io::CodedOutputStream* output) const final;
   ::PROTOBUF_NAMESPACE_ID::uint8* InternalSerializeWithCachedSizesToArray(
-      ::PROTOBUF_NAMESPACE_ID::uint8* target) const final;
+      ::PROTOBUF_NAMESPACE_ID::uint8* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const final;
   int GetCachedSize() const final { return _cached_size_.Get(); }
 
   private: