File protobuf-51026d922970e06475f005b39287963594134b96.patch of Package protobuf.36265

From 51026d922970e06475f005b39287963594134b96 Mon Sep 17 00:00:00 2001
From: Hao Nguyen <haon@google.com>
Date: Wed, 26 Jun 2019 11:01:34 -0700
Subject: [PATCH] Down integrate to GitHub

---
 java/core/src/main/java/com/google/protobuf/BooleanArrayList.java           |   19 
 java/core/src/main/java/com/google/protobuf/CodedInputStream.java           |    4 
 java/core/src/main/java/com/google/protobuf/DiscardUnknownFieldsParser.java |    2 
 java/core/src/main/java/com/google/protobuf/DoubleArrayList.java            |   19 
 java/core/src/main/java/com/google/protobuf/FloatArrayList.java             |   19 
 java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java         |  662 ++++++++--
 java/core/src/main/java/com/google/protobuf/IntArrayList.java               |   19 
 java/core/src/main/java/com/google/protobuf/LongArrayList.java              |   19 
 java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java          |  104 +
 java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java       |   37 
 java/core/src/test/java/com/google/protobuf/TestUtil.java                   |    2 
 src/google/protobuf/compiler/java/java_file.cc                              |    2 
 12 files changed, 744 insertions(+), 164 deletions(-)

--- 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 @@ final class BooleanArrayList extends Abs
     implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -161,6 +160,12 @@ final class BooleanArrayList extends Abs
   }
 
   @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 @@ final class BooleanArrayList extends Abs
   /** 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. */
--- 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 @@ public abstract class CodedInputStream {
   /**
    * 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;
 
--- 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 @@ package com.google.protobuf;
 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:
--- 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 @@ final class DoubleArrayList extends Abst
     implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(new double[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -161,6 +160,12 @@ final class DoubleArrayList extends Abst
   }
 
   @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 @@ final class DoubleArrayList extends Abst
   /** 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. */
--- 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 @@ final class FloatArrayList extends Abstr
     implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList(new float[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@ final class FloatArrayList extends Abstr
   }
 
   @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 @@ final class FloatArrayList extends Abstr
   /** 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. */
--- 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.IOException;
 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 @@ import java.util.TreeMap;
 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 @@ public abstract class GeneratedMessageV3
   }
 
  /**
-  * 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 @@ public abstract class GeneratedMessageV3
     }
   }
 
+  /** 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 @@ public abstract class GeneratedMessageV3
     // ---------------------------------------------------------------
 
     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 @@ public abstract class GeneratedMessageV3
       }
       @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 @@ public abstract class GeneratedMessageV3
       }
       @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 @@ public abstract class GeneratedMessageV3
       }
       @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 @@ public abstract class GeneratedMessageV3
 
         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 @@ public abstract class GeneratedMessageV3
 
         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 @@ public abstract class GeneratedMessageV3
       }
 
       @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 @@ public abstract class GeneratedMessageV3
           // 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 @@ public abstract class GeneratedMessageV3
           // 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 @@ public abstract class GeneratedMessageV3
   }
 
   /**
-   * 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.");
     }
--- 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 @@ final class IntArrayList extends Abstrac
     implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final IntArrayList EMPTY_LIST = new IntArrayList(new int[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@ final class IntArrayList extends Abstrac
   }
 
   @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 @@ final class IntArrayList extends Abstrac
   /** 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. */
--- 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 @@ final class LongArrayList extends Abstra
     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
 
   private static final LongArrayList EMPTY_LIST = new LongArrayList(new long[0], 0);
-
   static {
     EMPTY_LIST.makeImmutable();
   }
@@ -160,6 +159,12 @@ final class LongArrayList extends Abstra
   }
 
   @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 @@ final class LongArrayList extends Abstra
   /** 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. */
--- 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 @@ final class ProtobufArrayList<E> extends
     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;
   }
 }
--- 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.Collections;
 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 @@ public class GeneratedMessageTest extend
   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 class GeneratedMessageTest extend
   }
 
   public void testInvalidations() throws Exception {
-    GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
+    GeneratedMessageV3.setAlwaysUseFieldBuildersForTesting(true);
     TestAllTypes.NestedMessage nestedMessage1 = TestAllTypes.NestedMessage.newBuilder().build();
     TestAllTypes.NestedMessage nestedMessage2 = TestAllTypes.NestedMessage.newBuilder().build();
 
--- 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 @@ public final class TestUtil {
     }
 
     /** 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);
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -521,7 +521,7 @@ void FileGenerator::GenerateDescriptorIn
         // 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_));
openSUSE Build Service is sponsored by