Ver Fonte

Integrated internal changes from Google

Adam Cozzette há 7 anos atrás
pai
commit
92a7e778e7
100 ficheiros alterados com 3202 adições e 2379 exclusões
  1. 2 0
      cmake/libprotobuf-lite.cmake
  2. 0 1
      conformance/failure_list_cpp.txt
  3. 4 1
      conformance/failure_list_java.txt
  4. 3 0
      conformance/failure_list_python.txt
  5. 3 0
      conformance/failure_list_python_cpp.txt
  6. 13 8
      csharp/src/Google.Protobuf/WellKnownTypes/Any.cs
  7. 2 2
      csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs
  8. 57 0
      java/core/src/main/java/com/google/protobuf/Android.java
  9. 2 8
      java/core/src/main/java/com/google/protobuf/ByteString.java
  10. 5 0
      java/core/src/main/java/com/google/protobuf/FieldSet.java
  11. 24 18
      java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  12. 35 0
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  13. 0 9
      java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
  14. 5 7
      java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java
  15. 6 0
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  16. 78 10
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  17. 46 11
      java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
  18. 9 2
      java/util/src/main/java/com/google/protobuf/util/Timestamps.java
  19. 15 0
      java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
  20. 1 1
      js/binary/arith.js
  21. 5 5
      js/binary/decoder.js
  22. 2 2
      js/binary/encoder.js
  23. 25 25
      js/binary/reader.js
  24. 4 4
      js/binary/utils.js
  25. 1 1
      js/binary/utils_test.js
  26. 53 53
      js/binary/writer.js
  27. 8 1
      js/debug.js
  28. 11 0
      js/debug_test.js
  29. 53 11
      js/message.js
  30. 20 0
      js/message_test.js
  31. 13 8
      objectivec/google/protobuf/Any.pbobjc.h
  32. 2 2
      objectivec/google/protobuf/Timestamp.pbobjc.h
  33. 2 2
      python/google/protobuf/descriptor.py
  34. 18 8
      python/google/protobuf/descriptor_database.py
  35. 42 1
      python/google/protobuf/descriptor_pool.py
  36. 21 0
      python/google/protobuf/internal/descriptor_database_test.py
  37. 56 0
      python/google/protobuf/internal/descriptor_pool_test.py
  38. 2 1
      python/google/protobuf/internal/encoder.py
  39. 5 2
      python/google/protobuf/internal/text_format_test.py
  40. 266 264
      python/google/protobuf/pyext/descriptor_containers.cc
  41. 43 47
      python/google/protobuf/pyext/message.cc
  42. 6 6
      python/google/protobuf/pyext/message.h
  43. 1 1
      python/google/protobuf/text_format.py
  44. 2 0
      src/Makefile.am
  45. 7 7
      src/google/protobuf/any.pb.cc
  46. 11 2
      src/google/protobuf/any.pb.h
  47. 13 8
      src/google/protobuf/any.proto
  48. 40 36
      src/google/protobuf/api.pb.cc
  49. 67 47
      src/google/protobuf/api.pb.h
  50. 203 168
      src/google/protobuf/arena.cc
  51. 65 18
      src/google/protobuf/arena.h
  52. 117 41
      src/google/protobuf/arena_impl.h
  53. 22 10
      src/google/protobuf/arena_unittest.cc
  54. 21 0
      src/google/protobuf/arenastring.h
  55. 4 22
      src/google/protobuf/compiler/annotation_test_util.cc
  56. 6 11
      src/google/protobuf/compiler/annotation_test_util.h
  57. 1 1
      src/google/protobuf/compiler/code_generator.h
  58. 3 3
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc
  59. 2 15
      src/google/protobuf/compiler/cpp/cpp_field.cc
  60. 4 0
      src/google/protobuf/compiler/cpp/cpp_field.h
  61. 81 14
      src/google/protobuf/compiler/cpp/cpp_file.cc
  62. 31 8
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  63. 1 1
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  64. 4 0
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  65. 419 350
      src/google/protobuf/compiler/cpp/cpp_message.cc
  66. 3 0
      src/google/protobuf/compiler/cpp/cpp_message.h
  67. 196 405
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  68. 1 8
      src/google/protobuf/compiler/cpp/cpp_message_field.h
  69. 2 0
      src/google/protobuf/compiler/cpp/cpp_options.h
  70. 4 4
      src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
  71. 59 47
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  72. 2 0
      src/google/protobuf/compiler/cpp/cpp_string_field.h
  73. 23 22
      src/google/protobuf/compiler/cpp/cpp_unittest.cc
  74. 1 3
      src/google/protobuf/compiler/cpp/metadata_test.cc
  75. 15 13
      src/google/protobuf/compiler/java/java_message.cc
  76. 31 31
      src/google/protobuf/compiler/java/java_message_lite.cc
  77. 24 11
      src/google/protobuf/compiler/js/js_generator.cc
  78. 1 1
      src/google/protobuf/compiler/mock_code_generator.cc
  79. 38 44
      src/google/protobuf/compiler/plugin.pb.cc
  80. 54 29
      src/google/protobuf/compiler/plugin.pb.h
  81. 65 47
      src/google/protobuf/descriptor.cc
  82. 143 176
      src/google/protobuf/descriptor.pb.cc
  83. 263 154
      src/google/protobuf/descriptor.pb.h
  84. 3 0
      src/google/protobuf/descriptor_unittest.cc
  85. 7 3
      src/google/protobuf/duration.pb.cc
  86. 11 2
      src/google/protobuf/duration.pb.h
  87. 44 34
      src/google/protobuf/dynamic_message.cc
  88. 51 17
      src/google/protobuf/dynamic_message_unittest.cc
  89. 7 3
      src/google/protobuf/empty.pb.cc
  90. 11 2
      src/google/protobuf/empty.pb.h
  91. 12 4
      src/google/protobuf/extension_set.cc
  92. 2 0
      src/google/protobuf/extension_set.h
  93. 7 3
      src/google/protobuf/extension_set_heavy.cc
  94. 7 2
      src/google/protobuf/extension_set_unittest.cc
  95. 8 8
      src/google/protobuf/field_mask.pb.cc
  96. 11 2
      src/google/protobuf/field_mask.pb.h
  97. 0 1
      src/google/protobuf/generated_enum_reflection.h
  98. 1 1
      src/google/protobuf/generated_enum_util.h
  99. 0 12
      src/google/protobuf/generated_message_reflection.cc
  100. 2 6
      src/google/protobuf/generated_message_reflection.h

+ 2 - 0
cmake/libprotobuf-lite.cmake

@@ -4,6 +4,7 @@ set(libprotobuf_lite_files
   ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
   ${protobuf_source_dir}/src/google/protobuf/extension_set.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.cc
+  ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.cc
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -31,6 +32,7 @@ set(libprotobuf_lite_includes
   ${protobuf_source_dir}/src/google/protobuf/arenastring.h
   ${protobuf_source_dir}/src/google/protobuf/arenastring.h
   ${protobuf_source_dir}/src/google/protobuf/extension_set.h
   ${protobuf_source_dir}/src/google/protobuf/extension_set.h
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.h
   ${protobuf_source_dir}/src/google/protobuf/generated_message_util.h
+  ${protobuf_source_dir}/src/google/protobuf/implicit_weak_message.h
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/coded_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.h
   ${protobuf_source_dir}/src/google/protobuf/io/zero_copy_stream_impl_lite.h

+ 0 - 1
conformance/failure_list_cpp.txt

@@ -54,4 +54,3 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
-

+ 4 - 1
conformance/failure_list_java.txt

@@ -44,4 +44,7 @@ Required.Proto3.JsonInput.StringFieldNotAString
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto3.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
 Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
-Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+Required.Proto2.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
+# This test will be fixed as soon as we internally make the switch to
+# preserving unknowns in proto3.
+Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput

+ 3 - 0
conformance/failure_list_python.txt

@@ -19,3 +19,6 @@ Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_0
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_1
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_2
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
 Required.Proto3.ProtobufInput.IllegalZeroFieldNum_Case_3
+# This test will be fixed as soon as we internally make the switch to
+# preserving unknowns in proto3.
+Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput

+ 3 - 0
conformance/failure_list_python_cpp.txt

@@ -52,3 +52,6 @@ Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.SINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT32
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
 Required.Proto2.ProtobufInput.PrematureEofInPackedField.UINT64
+# This test will be fixed as soon as we internally make the switch to
+# preserving unknowns in proto3.
+Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput

+ 13 - 8
csharp/src/Google.Protobuf/WellKnownTypes/Any.cs

@@ -154,17 +154,18 @@ namespace Google.Protobuf.WellKnownTypes {
     public const int TypeUrlFieldNumber = 1;
     public const int TypeUrlFieldNumber = 1;
     private string typeUrl_ = "";
     private string typeUrl_ = "";
     /// <summary>
     /// <summary>
-    /// A URL/resource name whose content describes the type of the
-    /// serialized protocol buffer message.
+    /// A URL/resource name that uniquely identifies the type of the serialized
+    /// protocol buffer message. The last segment of the URL's path must represent
+    /// the fully qualified name of the type (as in
+    /// `path/google.protobuf.Duration`). The name should be in a canonical form
+    /// (e.g., leading "." is not accepted).
     ///
     ///
-    /// For URLs which use the scheme `http`, `https`, or no scheme, the
-    /// following restrictions and interpretations apply:
+    /// In practice, teams usually precompile into the binary all types that they
+    /// expect it to use in the context of Any. However, for URLs which use the
+    /// scheme `http`, `https`, or no scheme, one can optionally set up a type
+    /// server that maps type URLs to message definitions as follows:
     ///
     ///
     /// * If no scheme is provided, `https` is assumed.
     /// * If no scheme is provided, `https` is assumed.
-    /// * The last segment of the URL's path must represent the fully
-    ///   qualified name of the type (as in `path/google.protobuf.Duration`).
-    ///   The name should be in a canonical form (e.g., leading "." is
-    ///   not accepted).
     /// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
     /// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
     ///   value in binary format, or produce an error.
     ///   value in binary format, or produce an error.
     /// * Applications are allowed to cache lookup results based on the
     /// * Applications are allowed to cache lookup results based on the
@@ -173,6 +174,10 @@ namespace Google.Protobuf.WellKnownTypes {
     ///   on changes to types. (Use versioned type names to manage
     ///   on changes to types. (Use versioned type names to manage
     ///   breaking changes.)
     ///   breaking changes.)
     ///
     ///
+    /// Note: this functionality is not currently available in the official
+    /// protobuf release, and it is not used for type URLs beginning with
+    /// type.googleapis.com.
+    ///
     /// Schemes other than `http`, `https` (or the empty scheme) might be
     /// Schemes other than `http`, `https` (or the empty scheme) might be
     /// used with implementation specific semantics.
     /// used with implementation specific semantics.
     /// </summary>
     /// </summary>

+ 2 - 2
csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs

@@ -112,8 +112,8 @@ namespace Google.Protobuf.WellKnownTypes {
   /// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
   /// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
   /// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
   /// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
   /// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
   /// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
-  /// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
-  /// to obtain a formatter capable of generating timestamps in this format.
+  /// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
+  /// ) to obtain a formatter capable of generating timestamps in this format.
   /// </summary>
   /// </summary>
   public sealed partial class Timestamp : pb::IMessage<Timestamp> {
   public sealed partial class Timestamp : pb::IMessage<Timestamp> {
     private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
     private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());

+ 57 - 0
java/core/src/main/java/com/google/protobuf/Android.java

@@ -0,0 +1,57 @@
+// 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.
+
+package com.google.protobuf;
+
+final class Android {
+
+  private static final Class<?> MEMORY_CLASS = getClassForName("libcore.io.Memory");
+  private static final boolean IS_ROBOLECTRIC =
+      getClassForName("org.robolectric.Robolectric") != null;
+
+  /** Returns {@code true} if running on an Android device. */
+  static boolean isOnAndroidDevice() {
+    return MEMORY_CLASS != null && !IS_ROBOLECTRIC;
+  }
+
+  /** Returns the memory class or {@code null} if not on Android device. */
+  static Class<?> getMemoryClass() {
+    return MEMORY_CLASS;
+  }
+
+  @SuppressWarnings("unchecked")
+  private static <T> Class<T> getClassForName(String name) {
+    try {
+      return (Class<T>) Class.forName(name);
+    } catch (Throwable e) {
+      return null;
+    }
+  }
+}

+ 2 - 8
java/core/src/main/java/com/google/protobuf/ByteString.java

@@ -124,14 +124,8 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
 
 
   private static final ByteArrayCopier byteArrayCopier;
   private static final ByteArrayCopier byteArrayCopier;
   static {
   static {
-    boolean isAndroid = true;
-    try {
-      Class.forName("android.content.Context");
-    } catch (ClassNotFoundException e) {
-      isAndroid = false;
-    }
-
-    byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
+    byteArrayCopier =
+        Android.isOnAndroidDevice() ? new SystemByteArrayCopier() : new ArraysByteArrayCopier();
   }
   }
 
 
   /**
   /**

+ 5 - 0
java/core/src/main/java/com/google/protobuf/FieldSet.java

@@ -102,6 +102,11 @@ final class FieldSet<FieldDescriptorType extends
   @SuppressWarnings("rawtypes")
   @SuppressWarnings("rawtypes")
   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
 
 
+  /** Returns {@code true} if empty, {@code false} otherwise. */
+  boolean isEmpty() {
+    return fields.isEmpty();
+  }
+
   /** Make this FieldSet immutable from this point forward. */
   /** Make this FieldSet immutable from this point forward. */
   @SuppressWarnings("unchecked")
   @SuppressWarnings("unchecked")
   public void makeImmutable() {
   public void makeImmutable() {

+ 24 - 18
java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -504,11 +504,8 @@ public abstract class GeneratedMessageLite<
             extends GeneratedMessageLite<MessageType, BuilderType>
             extends GeneratedMessageLite<MessageType, BuilderType>
             implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
             implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
 
 
-    /**
-     * Represents the set of extensions on this message. For use by generated
-     * code only.
-     */
-    protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
+    /** Represents the set of extensions on this message. For use by generated code only. */
+    protected FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
 
 
     @SuppressWarnings("unchecked")
     @SuppressWarnings("unchecked")
     protected final void mergeExtensionFields(final MessageType other) {
     protected final void mergeExtensionFields(final MessageType other) {
@@ -578,7 +575,11 @@ public abstract class GeneratedMessageLite<
       if (unknown) {  // Unknown field or wrong wire type.  Skip.
       if (unknown) {  // Unknown field or wrong wire type.  Skip.
         return parseUnknownField(tag, input);
         return parseUnknownField(tag, input);
       }
       }
-      
+
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+      }
+
       if (packed) {
       if (packed) {
         int length = input.readRawVarint32();
         int length = input.readRawVarint32();
         int limit = input.pushLimit(length);
         int limit = input.pushLimit(length);
@@ -942,12 +943,6 @@ public abstract class GeneratedMessageLite<
       implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
       implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
     protected ExtendableBuilder(MessageType defaultInstance) {
     protected ExtendableBuilder(MessageType defaultInstance) {
       super(defaultInstance);
       super(defaultInstance);
-
-      // TODO(dweis): This is kind of an unnecessary clone since we construct a
-      //     new instance in the parent constructor which makes the extensions
-      //     immutable. This extra allocation shouldn't matter in practice
-      //     though.
-      instance.extensions = instance.extensions.clone();
     }
     }
 
 
     // For immutable message conversion.
     // For immutable message conversion.
@@ -966,6 +961,15 @@ public abstract class GeneratedMessageLite<
       instance.extensions = instance.extensions.clone();
       instance.extensions = instance.extensions.clone();
     }
     }
 
 
+    private FieldSet<ExtensionDescriptor> ensureExtensionsAreMutable() {
+      FieldSet<ExtensionDescriptor> extensions = instance.extensions;
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
+        instance.extensions = extensions;
+      }
+      return extensions;
+    }
+
     @Override
     @Override
     public final MessageType buildPartial() {
     public final MessageType buildPartial() {
       if (isBuilt) {
       if (isBuilt) {
@@ -1024,7 +1028,8 @@ public abstract class GeneratedMessageLite<
 
 
       verifyExtensionContainingType(extensionLite);
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       copyOnWrite();
-      instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
       return (BuilderType) this;
       return (BuilderType) this;
     }
     }
 
 
@@ -1037,8 +1042,9 @@ public abstract class GeneratedMessageLite<
 
 
       verifyExtensionContainingType(extensionLite);
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       copyOnWrite();
-      instance.extensions.setRepeatedField(
-          extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .setRepeatedField(
+              extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
       return (BuilderType) this;
     }
     }
 
 
@@ -1051,8 +1057,8 @@ public abstract class GeneratedMessageLite<
 
 
       verifyExtensionContainingType(extensionLite);
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       copyOnWrite();
-      instance.extensions.addRepeatedField(
-          extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
+      ensureExtensionsAreMutable()
+          .addRepeatedField(extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
       return (BuilderType) this;
     }
     }
 
 
@@ -1063,7 +1069,7 @@ public abstract class GeneratedMessageLite<
 
 
       verifyExtensionContainingType(extensionLite);
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       copyOnWrite();
-      instance.extensions.clearField(extensionLite.descriptor);
+      ensureExtensionsAreMutable().clearField(extensionLite.descriptor);
       return (BuilderType) this;
       return (BuilderType) this;
     }
     }
   }
   }

+ 35 - 0
java/core/src/main/java/com/google/protobuf/TextFormat.java

@@ -1223,6 +1223,22 @@ public final class TextFormat {
     PARSER.merge(input, builder);
     PARSER.merge(input, builder);
   }
   }
 
 
+  /**
+   * Parse a text-format message from {@code input}.
+   *
+   * @return the parsed message, guaranteed initialized
+   */
+  public static <T extends Message> T parse(final CharSequence input,
+                                            final Class<T> protoClass)
+                                            throws ParseException {
+    Message.Builder builder =
+        Internal.getDefaultInstance(protoClass).newBuilderForType();
+    merge(input, builder);
+    @SuppressWarnings("unchecked")
+    T output = (T) builder.build();
+    return output;
+  }
+
   /**
   /**
    * Parse a text-format message from {@code input} and merge the contents
    * Parse a text-format message from {@code input} and merge the contents
    * into {@code builder}.  Extensions will be recognized if they are
    * into {@code builder}.  Extensions will be recognized if they are
@@ -1248,6 +1264,25 @@ public final class TextFormat {
     PARSER.merge(input, extensionRegistry, builder);
     PARSER.merge(input, extensionRegistry, builder);
   }
   }
 
 
+  /**
+   * Parse a text-format message from {@code input}.  Extensions will be
+   * recognized if they are registered in {@code extensionRegistry}.
+   *
+   * @return the parsed message, guaranteed initialized
+   */
+  public static <T extends Message> T parse(
+      final CharSequence input,
+      final ExtensionRegistry extensionRegistry,
+      final Class<T> protoClass)
+      throws ParseException {
+    Message.Builder builder =
+        Internal.getDefaultInstance(protoClass).newBuilderForType();
+    merge(input, extensionRegistry, builder);
+    @SuppressWarnings("unchecked")
+    T output = (T) builder.build();
+    return output;
+  }
+
 
 
   /**
   /**
    * Parser for text-format proto2 instances. This class is thread-safe.
    * Parser for text-format proto2 instances. This class is thread-safe.

+ 0 - 9
java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

@@ -364,15 +364,6 @@ final class UnsafeUtil {
   }
   }
 
 
 
 
-  @SuppressWarnings("unchecked")
-  private static <T> Class<T> getClassForName(String name) {
-    try {
-      return (Class<T>) Class.forName(name);
-    } catch (Throwable e) {
-      return null;
-    }
-  }
-
   /** Finds the address field within a direct {@link Buffer}. */
   /** Finds the address field within a direct {@link Buffer}. */
   private static Field bufferAddressField() {
   private static Field bufferAddressField() {
     return field(Buffer.class, "address");
     return field(Buffer.class, "address");

+ 5 - 7
java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java

@@ -30,6 +30,9 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
 import protobuf_unittest.UnittestProto;
 import protobuf_unittest.UnittestProto;
@@ -346,11 +349,6 @@ public class AbstractMessageTest extends TestCase {
   // -----------------------------------------------------------------
   // -----------------------------------------------------------------
   // Tests for isInitialized().
   // Tests for isInitialized().
 
 
-  private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
-    TestRequired.getDefaultInstance();
-  private static final TestRequired TEST_REQUIRED_INITIALIZED =
-    TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
-
   public void testIsInitialized() throws Exception {
   public void testIsInitialized() throws Exception {
     TestRequired.Builder builder = TestRequired.newBuilder();
     TestRequired.Builder builder = TestRequired.newBuilder();
     AbstractMessageWrapper.Builder abstractBuilder =
     AbstractMessageWrapper.Builder abstractBuilder =
@@ -380,7 +378,7 @@ public class AbstractMessageTest extends TestCase {
     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
     assertFalse(abstractBuilder.isInitialized());
     assertFalse(abstractBuilder.isInitialized());
     assertEquals(
     assertEquals(
-        "optional_message.a, optional_message.b, optional_message.c",
+        "optional_message.b, optional_message.c",
         abstractBuilder.getInitializationErrorString());
         abstractBuilder.getInitializationErrorString());
 
 
     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
@@ -390,7 +388,7 @@ public class AbstractMessageTest extends TestCase {
     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
     assertFalse(abstractBuilder.isInitialized());
     assertFalse(abstractBuilder.isInitialized());
     assertEquals(
     assertEquals(
-        "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
+        "repeated_message[0].b, repeated_message[0].c",
         abstractBuilder.getInitializationErrorString());
         abstractBuilder.getInitializationErrorString());
 
 
     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);

+ 6 - 0
java/core/src/test/java/com/google/protobuf/TestUtil.java

@@ -231,6 +231,7 @@ import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
@@ -252,6 +253,11 @@ import junit.framework.Assert;
 public final class TestUtil {
 public final class TestUtil {
   private TestUtil() {}
   private TestUtil() {}
 
 
+  public static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+      TestRequired.newBuilder().setA(1).buildPartial();
+  public static final TestRequired TEST_REQUIRED_INITIALIZED =
+      TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
   /** Helper to convert a String to ByteString. */
   /** Helper to convert a String to ByteString. */
   static ByteString toBytes(String str) {
   static ByteString toBytes(String str) {
     return ByteString.copyFrom(str.getBytes(Internal.UTF_8));
     return ByteString.copyFrom(str.getBytes(Internal.UTF_8));

+ 78 - 10
java/core/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -30,6 +30,9 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_INITIALIZED;
+import static com.google.protobuf.TestUtil.TEST_REQUIRED_UNINITIALIZED;
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
@@ -42,6 +45,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneof2;
+import protobuf_unittest.UnittestProto.TestRequired;
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 import java.io.StringReader;
 import java.io.StringReader;
 import java.util.List;
 import java.util.List;
@@ -326,19 +330,58 @@ public class TextFormatTest extends TestCase {
 
 
   // =================================================================
   // =================================================================
 
 
-  public void testParse() throws Exception {
+  public void testMerge() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(allFieldsSetText, builder);
     TextFormat.merge(allFieldsSetText, builder);
     TestUtil.assertAllFieldsSet(builder.build());
     TestUtil.assertAllFieldsSet(builder.build());
   }
   }
 
 
-  public void testParseReader() throws Exception {
+  public void testParse() throws Exception {
+    TestUtil.assertAllFieldsSet(
+        TextFormat.parse(allFieldsSetText, TestAllTypes.class));
+  }
+
+  public void testMergeInitialized() throws Exception {
+    TestRequired.Builder builder = TestRequired.newBuilder();
+    TextFormat.merge(TEST_REQUIRED_INITIALIZED.toString(), builder);
+    assertEquals(TEST_REQUIRED_INITIALIZED.toString(),
+                 builder.buildPartial().toString());
+    assertTrue(builder.isInitialized());
+  }
+
+  public void testParseInitialized() throws Exception {
+    TestRequired parsed =
+        TextFormat.parse(TEST_REQUIRED_INITIALIZED.toString(),
+                         TestRequired.class);
+    assertEquals(TEST_REQUIRED_INITIALIZED.toString(), parsed.toString());
+    assertTrue(parsed.isInitialized());
+  }
+
+  public void testMergeUninitialized() throws Exception {
+    TestRequired.Builder builder = TestRequired.newBuilder();
+    TextFormat.merge(TEST_REQUIRED_UNINITIALIZED.toString(), builder);
+    assertEquals(TEST_REQUIRED_UNINITIALIZED.toString(),
+                 builder.buildPartial().toString());
+    assertFalse(builder.isInitialized());
+  }
+
+  public void testParseUninitialized() throws Exception {
+    try {
+      TextFormat.parse(TEST_REQUIRED_UNINITIALIZED.toString(),
+                       TestRequired.class);
+      fail("Expected UninitializedMessageException.");
+    } catch (UninitializedMessageException e) {
+      assertEquals("Message missing required fields: b, c", e.getMessage());
+    }
+  }
+
+  public void testMergeReader() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(new StringReader(allFieldsSetText), builder);
     TextFormat.merge(new StringReader(allFieldsSetText), builder);
     TestUtil.assertAllFieldsSet(builder.build());
     TestUtil.assertAllFieldsSet(builder.build());
   }
   }
 
 
-  public void testParseExtensions() throws Exception {
+  public void testMergeExtensions() throws Exception {
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
     TextFormat.merge(allExtensionsSetText,
     TextFormat.merge(allExtensionsSetText,
                      TestUtil.getExtensionRegistry(),
                      TestUtil.getExtensionRegistry(),
@@ -346,7 +389,14 @@ public class TextFormatTest extends TestCase {
     TestUtil.assertAllExtensionsSet(builder.build());
     TestUtil.assertAllExtensionsSet(builder.build());
   }
   }
 
 
-  public void testParseCompatibility() throws Exception {
+  public void testParseExtensions() throws Exception {
+    TestUtil.assertAllExtensionsSet(
+        TextFormat.parse(allExtensionsSetText,
+                         TestUtil.getExtensionRegistry(),
+                         TestAllExtensions.class));
+  }
+
+  public void testMergeAndParseCompatibility() throws Exception {
     String original = "repeated_float: inf\n" +
     String original = "repeated_float: inf\n" +
                       "repeated_float: -inf\n" +
                       "repeated_float: -inf\n" +
                       "repeated_float: nan\n" +
                       "repeated_float: nan\n" +
@@ -371,21 +421,29 @@ public class TextFormatTest extends TestCase {
                         "repeated_double: Infinity\n" +
                         "repeated_double: Infinity\n" +
                         "repeated_double: -Infinity\n" +
                         "repeated_double: -Infinity\n" +
                         "repeated_double: NaN\n";
                         "repeated_double: NaN\n";
+
+    // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(original, builder);
     TextFormat.merge(original, builder);
     assertEquals(canonical, builder.build().toString());
     assertEquals(canonical, builder.build().toString());
+
+    // Test parse().
+    assertEquals(canonical,
+                 TextFormat.parse(original, TestAllTypes.class).toString());
   }
   }
 
 
-  public void testParseExotic() throws Exception {
+  public void testMergeAndParseExotic() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(exoticText, builder);
     TextFormat.merge(exoticText, builder);
 
 
     // Too lazy to check things individually.  Don't try to debug this
     // Too lazy to check things individually.  Don't try to debug this
     // if testPrintExotic() is failing.
     // if testPrintExotic() is failing.
     assertEquals(canonicalExoticText, builder.build().toString());
     assertEquals(canonicalExoticText, builder.build().toString());
+    assertEquals(canonicalExoticText,
+                 TextFormat.parse(exoticText, TestAllTypes.class).toString());
   }
   }
 
 
-  public void testParseMessageSet() throws Exception {
+  public void testMergeMessageSet() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -411,7 +469,7 @@ public class TextFormatTest extends TestCase {
       TestMessageSetExtension1.messageSetExtension).getI());
       TestMessageSetExtension1.messageSetExtension).getI());
   }
   }
 
 
-  public void testParseMessageSetWithOverwriteForbidden() throws Exception {
+  public void testMergeMessageSetWithOverwriteForbidden() throws Exception {
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
@@ -438,20 +496,20 @@ public class TextFormatTest extends TestCase {
     }
     }
   }
   }
 
 
-  public void testParseNumericEnum() throws Exception {
+  public void testMergeNumericEnum() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("optional_nested_enum: 2", builder);
     TextFormat.merge("optional_nested_enum: 2", builder);
     assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
     assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
   }
   }
 
 
-  public void testParseAngleBrackets() throws Exception {
+  public void testMergeAngleBrackets() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
     TextFormat.merge("OptionalGroup: < a: 1 >", builder);
     assertTrue(builder.hasOptionalGroup());
     assertTrue(builder.hasOptionalGroup());
     assertEquals(1, builder.getOptionalGroup().getA());
     assertEquals(1, builder.getOptionalGroup().getA());
   }
   }
 
 
-  public void testParseComment() throws Exception {
+  public void testMergeComment() throws Exception {
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TextFormat.merge(
     TextFormat.merge(
       "# this is a comment\n" +
       "# this is a comment\n" +
@@ -463,6 +521,7 @@ public class TextFormatTest extends TestCase {
   }
   }
 
 
   private void assertParseError(String error, String text) {
   private void assertParseError(String error, String text) {
+    // Test merge().
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     try {
     try {
       TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
       TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
@@ -470,6 +529,15 @@ public class TextFormatTest extends TestCase {
     } catch (TextFormat.ParseException e) {
     } catch (TextFormat.ParseException e) {
       assertEquals(error, e.getMessage());
       assertEquals(error, e.getMessage());
     }
     }
+
+    // Test parse().
+    try {
+      TextFormat.parse(
+          text, TestUtil.getExtensionRegistry(), TestAllTypes.class);
+      fail("Expected parse exception.");
+    } catch (TextFormat.ParseException e) {
+      assertEquals(error, e.getMessage());
+    }
   }
   }
 
 
 
 

+ 46 - 11
java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

@@ -105,7 +105,7 @@ public class JsonFormat {
   public static Printer printer() {
   public static Printer printer() {
     return new Printer(
     return new Printer(
         TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
         TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
-        false, false);
+        false, false, false);
   }
   }
 
 
   /**
   /**
@@ -125,18 +125,21 @@ public class JsonFormat {
     private Set<FieldDescriptor> includingDefaultValueFields;
     private Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
     private final boolean preservingProtoFieldNames;
     private final boolean omittingInsignificantWhitespace;
     private final boolean omittingInsignificantWhitespace;
+    private final boolean printingEnumsAsInts;
 
 
     private Printer(
     private Printer(
         TypeRegistry registry,
         TypeRegistry registry,
         boolean alwaysOutputDefaultValueFields,
         boolean alwaysOutputDefaultValueFields,
         Set<FieldDescriptor> includingDefaultValueFields,
         Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
         boolean preservingProtoFieldNames,
-        boolean omittingInsignificantWhitespace) {
+        boolean omittingInsignificantWhitespace,
+        boolean printingEnumsAsInts) {
       this.registry = registry;
       this.registry = registry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
       this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
+      this.printingEnumsAsInts = printingEnumsAsInts;
     }
     }
 
 
     /**
     /**
@@ -154,7 +157,8 @@ public class JsonFormat {
           alwaysOutputDefaultValueFields,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           includingDefaultValueFields,
           preservingProtoFieldNames,
           preservingProtoFieldNames,
-          omittingInsignificantWhitespace);
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
     }
     }
 
 
     /**
     /**
@@ -170,7 +174,31 @@ public class JsonFormat {
           true,
           true,
           Collections.<FieldDescriptor>emptySet(),
           Collections.<FieldDescriptor>emptySet(),
           preservingProtoFieldNames,
           preservingProtoFieldNames,
-          omittingInsignificantWhitespace);
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
+    }
+
+    /**
+     * Creates a new {@link Printer} that will print enum field values as integers instead of as
+     * string.
+     * The new Printer clones all other configurations from the current
+     * {@link Printer}.
+     */
+    public Printer printingEnumsAsInts() {
+      checkUnsetPrintingEnumsAsInts();
+      return new Printer(
+          registry,
+          alwaysOutputDefaultValueFields,
+          Collections.<FieldDescriptor>emptySet(),
+          preservingProtoFieldNames,
+          omittingInsignificantWhitespace,
+          true);
+    }
+
+    private void checkUnsetPrintingEnumsAsInts() {
+      if (printingEnumsAsInts) {
+        throw new IllegalStateException("JsonFormat printingEnumsAsInts has already been set.");
+      }
     }
     }
 
 
     /**
     /**
@@ -191,7 +219,8 @@ public class JsonFormat {
           false,
           false,
           fieldsToAlwaysOutput,
           fieldsToAlwaysOutput,
           preservingProtoFieldNames,
           preservingProtoFieldNames,
-          omittingInsignificantWhitespace);
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
     }
     }
 
 
     private void checkUnsetIncludingDefaultValueFields() {
     private void checkUnsetIncludingDefaultValueFields() {
@@ -213,7 +242,8 @@ public class JsonFormat {
           alwaysOutputDefaultValueFields,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           includingDefaultValueFields,
           true,
           true,
-          omittingInsignificantWhitespace);
+          omittingInsignificantWhitespace,
+          printingEnumsAsInts);
     }
     }
 
 
 
 
@@ -240,7 +270,8 @@ public class JsonFormat {
           alwaysOutputDefaultValueFields,
           alwaysOutputDefaultValueFields,
           includingDefaultValueFields,
           includingDefaultValueFields,
           preservingProtoFieldNames,
           preservingProtoFieldNames,
-          true);
+          true,
+          printingEnumsAsInts);
     }
     }
 
 
     /**
     /**
@@ -259,7 +290,8 @@ public class JsonFormat {
               includingDefaultValueFields,
               includingDefaultValueFields,
               preservingProtoFieldNames,
               preservingProtoFieldNames,
               output,
               output,
-              omittingInsignificantWhitespace)
+              omittingInsignificantWhitespace,
+              printingEnumsAsInts)
           .print(message);
           .print(message);
     }
     }
 
 
@@ -416,7 +448,7 @@ public class JsonFormat {
        */
        */
       public Builder add(Iterable<Descriptor> messageTypes) {
       public Builder add(Iterable<Descriptor> messageTypes) {
         if (types == null) {
         if (types == null) {
-          throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builder can only be used once.");
         }
         }
         for (Descriptor type : messageTypes) {
         for (Descriptor type : messageTypes) {
           addFile(type.getFile());
           addFile(type.getFile());
@@ -570,6 +602,7 @@ public class JsonFormat {
     private final boolean alwaysOutputDefaultValueFields;
     private final boolean alwaysOutputDefaultValueFields;
     private final Set<FieldDescriptor> includingDefaultValueFields;
     private final Set<FieldDescriptor> includingDefaultValueFields;
     private final boolean preservingProtoFieldNames;
     private final boolean preservingProtoFieldNames;
+    private final boolean printingEnumsAsInts;
     private final TextGenerator generator;
     private final TextGenerator generator;
     // We use Gson to help handle string escapes.
     // We use Gson to help handle string escapes.
     private final Gson gson;
     private final Gson gson;
@@ -586,11 +619,13 @@ public class JsonFormat {
         Set<FieldDescriptor> includingDefaultValueFields,
         Set<FieldDescriptor> includingDefaultValueFields,
         boolean preservingProtoFieldNames,
         boolean preservingProtoFieldNames,
         Appendable jsonOutput,
         Appendable jsonOutput,
-        boolean omittingInsignificantWhitespace) {
+        boolean omittingInsignificantWhitespace,
+        boolean printingEnumsAsInts) {
       this.registry = registry;
       this.registry = registry;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
+      this.printingEnumsAsInts = printingEnumsAsInts;
       this.gson = GsonHolder.DEFAULT_GSON;
       this.gson = GsonHolder.DEFAULT_GSON;
       // json format related properties, determined by printerType
       // json format related properties, determined by printerType
       if (omittingInsignificantWhitespace) {
       if (omittingInsignificantWhitespace) {
@@ -1069,7 +1104,7 @@ public class JsonFormat {
               generator.print("\"");
               generator.print("\"");
             }
             }
           } else {
           } else {
-            if (((EnumValueDescriptor) value).getIndex() == -1) {
+            if (printingEnumsAsInts || ((EnumValueDescriptor) value).getIndex() == -1) {
               generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
               generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
             } else {
             } else {
               generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");
               generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");

+ 9 - 2
java/util/src/main/java/com/google/protobuf/util/Timestamps.java

@@ -74,6 +74,11 @@ public final class Timestamps {
   public static final Timestamp MAX_VALUE =
   public static final Timestamp MAX_VALUE =
       Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MAX).setNanos(999999999).build();
       Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MAX).setNanos(999999999).build();
 
 
+  /**
+   * A constant holding the {@link Timestamp} of epoch time, {@code 1970-01-01T00:00:00.000000000Z}.
+   */
+  public static final Timestamp EPOCH = Timestamp.newBuilder().setSeconds(0).setNanos(0).build();
+
   private static final ThreadLocal<SimpleDateFormat> timestampFormat =
   private static final ThreadLocal<SimpleDateFormat> timestampFormat =
       new ThreadLocal<SimpleDateFormat>() {
       new ThreadLocal<SimpleDateFormat>() {
         @Override
         @Override
@@ -358,10 +363,12 @@ public final class Timestamps {
   static Timestamp normalizedTimestamp(long seconds, int nanos) {
   static Timestamp normalizedTimestamp(long seconds, int nanos) {
     if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
     if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
       seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
       seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
-      nanos %= NANOS_PER_SECOND;
+      nanos = (int) (nanos % NANOS_PER_SECOND);
     }
     }
     if (nanos < 0) {
     if (nanos < 0) {
-      nanos += NANOS_PER_SECOND; // no overflow since nanos is negative (and we're adding)
+      nanos =
+          (int)
+              (nanos + NANOS_PER_SECOND); // no overflow since nanos is negative (and we're adding)
       seconds = checkedSubtract(seconds, 1);
       seconds = checkedSubtract(seconds, 1);
     }
     }
     Timestamp timestamp = Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
     Timestamp timestamp = Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();

+ 15 - 0
java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java

@@ -1174,6 +1174,14 @@ public class JsonFormatTest extends TestCase {
     JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
     JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
   }
   }
 
 
+  public void testParserIntegerEnumValue() throws Exception {
+    TestAllTypes.Builder actualBuilder = TestAllTypes.newBuilder();
+    mergeFromJson("{\n" + "  \"optionalNestedEnum\": 2\n" + "}", actualBuilder);
+
+    TestAllTypes expected = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAZ).build();
+    assertEquals(expected, actualBuilder.build());
+  }
+
   public void testCustomJsonName() throws Exception {
   public void testCustomJsonName() throws Exception {
     TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
     TestCustomJsonName message = TestCustomJsonName.newBuilder().setValue(12345).build();
     assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
     assertEquals("{\n" + "  \"@value\": 12345\n" + "}", JsonFormat.printer().print(message));
@@ -1441,6 +1449,13 @@ public class JsonFormatTest extends TestCase {
     assertEquals(54321, builder.getOptionalInt32());
     assertEquals(54321, builder.getOptionalInt32());
   }
   }
 
 
+  public void testPrintingEnumsAsInts() throws Exception {
+    TestAllTypes message = TestAllTypes.newBuilder().setOptionalNestedEnum(NestedEnum.BAR).build();
+    assertEquals(
+        "{\n" + "  \"optionalNestedEnum\": 1\n" + "}",
+        JsonFormat.printer().printingEnumsAsInts().print(message));
+  }
+
   public void testOmittingInsignificantWhiteSpace() throws Exception {
   public void testOmittingInsignificantWhiteSpace() throws Exception {
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
     TestAllTypes message = TestAllTypes.newBuilder().setOptionalInt32(12345).build();
     assertEquals(
     assertEquals(

+ 1 - 1
js/binary/arith.js

@@ -221,7 +221,7 @@ jspb.arith.UInt64.prototype.mul = function(a) {
  * Divide a 64-bit number by a 32-bit number to produce a
  * Divide a 64-bit number by a 32-bit number to produce a
  * 64-bit quotient and a 32-bit remainder.
  * 64-bit quotient and a 32-bit remainder.
  * @param {number} _divisor
  * @param {number} _divisor
- * @return {Array.<jspb.arith.UInt64>} array of [quotient, remainder],
+ * @return {Array<jspb.arith.UInt64>} array of [quotient, remainder],
  * unless divisor is 0, in which case an empty array is returned.
  * unless divisor is 0, in which case an empty array is returned.
  */
  */
 jspb.arith.UInt64.prototype.div = function(_divisor) {
 jspb.arith.UInt64.prototype.div = function(_divisor) {

+ 5 - 5
js/binary/decoder.js

@@ -58,7 +58,7 @@ goog.require('jspb.utils');
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  *     opt_next The decoder method to use for next().
  *     opt_next The decoder method to use for next().
- * @param {?Array.<number|boolean|string>=} opt_elements
+ * @param {?Array<number|boolean|string>=} opt_elements
  * @constructor
  * @constructor
  * @struct
  * @struct
  */
  */
@@ -92,7 +92,7 @@ jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  *     opt_next The decoder method to use for next().
  *     opt_next The decoder method to use for next().
- * @param {?Array.<number|boolean|string>=} opt_elements
+ * @param {?Array<number|boolean|string>=} opt_elements
  * @private
  * @private
  */
  */
 jspb.BinaryIterator.prototype.init_ =
 jspb.BinaryIterator.prototype.init_ =
@@ -112,7 +112,7 @@ jspb.BinaryIterator.prototype.init_ =
 
 
 /**
 /**
  * Global pool of BinaryIterator instances.
  * Global pool of BinaryIterator instances.
- * @private {!Array.<!jspb.BinaryIterator>}
+ * @private {!Array<!jspb.BinaryIterator>}
  */
  */
 jspb.BinaryIterator.instanceCache_ = [];
 jspb.BinaryIterator.instanceCache_ = [];
 
 
@@ -123,7 +123,7 @@ jspb.BinaryIterator.instanceCache_ = [];
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?jspb.BinaryDecoder=} opt_decoder
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
  *     opt_next The decoder method to use for next().
  *     opt_next The decoder method to use for next().
- * @param {?Array.<number|boolean|string>=} opt_elements
+ * @param {?Array<number|boolean|string>=} opt_elements
  * @return {!jspb.BinaryIterator}
  * @return {!jspb.BinaryIterator}
  */
  */
 jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
 jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
@@ -274,7 +274,7 @@ jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
 
 
 /**
 /**
  * Global pool of BinaryDecoder instances.
  * Global pool of BinaryDecoder instances.
- * @private {!Array.<!jspb.BinaryDecoder>}
+ * @private {!Array<!jspb.BinaryDecoder>}
  */
  */
 jspb.BinaryDecoder.instanceCache_ = [];
 jspb.BinaryDecoder.instanceCache_ = [];
 
 

+ 2 - 2
js/binary/encoder.js

@@ -51,7 +51,7 @@ goog.require('jspb.utils');
  * @struct
  * @struct
  */
  */
 jspb.BinaryEncoder = function() {
 jspb.BinaryEncoder = function() {
-  /** @private {!Array.<number>} */
+  /** @private {!Array<number>} */
   this.buffer_ = [];
   this.buffer_ = [];
 };
 };
 
 
@@ -65,7 +65,7 @@ jspb.BinaryEncoder.prototype.length = function() {
 
 
 
 
 /**
 /**
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryEncoder.prototype.end = function() {
 jspb.BinaryEncoder.prototype.end = function() {
   var buffer = this.buffer_;
   var buffer = this.buffer_;

+ 25 - 25
js/binary/reader.js

@@ -97,7 +97,7 @@ jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
 
 
   /**
   /**
    * User-defined reader callbacks.
    * User-defined reader callbacks.
-   * @private {Object.<string, function(!jspb.BinaryReader):*>}
+   * @private {Object<string, function(!jspb.BinaryReader):*>}
    */
    */
   this.readCallbacks_ = null;
   this.readCallbacks_ = null;
 };
 };
@@ -105,7 +105,7 @@ jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
 
 
 /**
 /**
  * Global pool of BinaryReader instances.
  * Global pool of BinaryReader instances.
- * @private {!Array.<!jspb.BinaryReader>}
+ * @private {!Array<!jspb.BinaryReader>}
  */
  */
 jspb.BinaryReader.instanceCache_ = [];
 jspb.BinaryReader.instanceCache_ = [];
 
 
@@ -992,7 +992,7 @@ jspb.BinaryReader.prototype.readPackedField_ = function(decodeMethod) {
 /**
 /**
  * Reads a packed int32 field, which consists of a length header and a list of
  * Reads a packed int32 field, which consists of a length header and a list of
  * signed varints.
  * signed varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedInt32 = function() {
 jspb.BinaryReader.prototype.readPackedInt32 = function() {
   return this.readPackedField_(this.decoder_.readSignedVarint32);
   return this.readPackedField_(this.decoder_.readSignedVarint32);
@@ -1002,7 +1002,7 @@ jspb.BinaryReader.prototype.readPackedInt32 = function() {
 /**
 /**
  * Reads a packed int32 field, which consists of a length header and a list of
  * Reads a packed int32 field, which consists of a length header and a list of
  * signed varints. Returns a list of strings.
  * signed varints. Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedInt32String = function() {
 jspb.BinaryReader.prototype.readPackedInt32String = function() {
   return this.readPackedField_(this.decoder_.readSignedVarint32String);
   return this.readPackedField_(this.decoder_.readSignedVarint32String);
@@ -1012,7 +1012,7 @@ jspb.BinaryReader.prototype.readPackedInt32String = function() {
 /**
 /**
  * Reads a packed int64 field, which consists of a length header and a list of
  * Reads a packed int64 field, which consists of a length header and a list of
  * signed varints.
  * signed varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedInt64 = function() {
 jspb.BinaryReader.prototype.readPackedInt64 = function() {
   return this.readPackedField_(this.decoder_.readSignedVarint64);
   return this.readPackedField_(this.decoder_.readSignedVarint64);
@@ -1022,7 +1022,7 @@ jspb.BinaryReader.prototype.readPackedInt64 = function() {
 /**
 /**
  * Reads a packed int64 field, which consists of a length header and a list of
  * Reads a packed int64 field, which consists of a length header and a list of
  * signed varints. Returns a list of strings.
  * signed varints. Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedInt64String = function() {
 jspb.BinaryReader.prototype.readPackedInt64String = function() {
   return this.readPackedField_(this.decoder_.readSignedVarint64String);
   return this.readPackedField_(this.decoder_.readSignedVarint64String);
@@ -1032,7 +1032,7 @@ jspb.BinaryReader.prototype.readPackedInt64String = function() {
 /**
 /**
  * Reads a packed uint32 field, which consists of a length header and a list of
  * Reads a packed uint32 field, which consists of a length header and a list of
  * unsigned varints.
  * unsigned varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedUint32 = function() {
 jspb.BinaryReader.prototype.readPackedUint32 = function() {
   return this.readPackedField_(this.decoder_.readUnsignedVarint32);
   return this.readPackedField_(this.decoder_.readUnsignedVarint32);
@@ -1042,7 +1042,7 @@ jspb.BinaryReader.prototype.readPackedUint32 = function() {
 /**
 /**
  * Reads a packed uint32 field, which consists of a length header and a list of
  * Reads a packed uint32 field, which consists of a length header and a list of
  * unsigned varints. Returns a list of strings.
  * unsigned varints. Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedUint32String = function() {
 jspb.BinaryReader.prototype.readPackedUint32String = function() {
   return this.readPackedField_(this.decoder_.readUnsignedVarint32String);
   return this.readPackedField_(this.decoder_.readUnsignedVarint32String);
@@ -1052,7 +1052,7 @@ jspb.BinaryReader.prototype.readPackedUint32String = function() {
 /**
 /**
  * Reads a packed uint64 field, which consists of a length header and a list of
  * Reads a packed uint64 field, which consists of a length header and a list of
  * unsigned varints.
  * unsigned varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedUint64 = function() {
 jspb.BinaryReader.prototype.readPackedUint64 = function() {
   return this.readPackedField_(this.decoder_.readUnsignedVarint64);
   return this.readPackedField_(this.decoder_.readUnsignedVarint64);
@@ -1062,7 +1062,7 @@ jspb.BinaryReader.prototype.readPackedUint64 = function() {
 /**
 /**
  * Reads a packed uint64 field, which consists of a length header and a list of
  * Reads a packed uint64 field, which consists of a length header and a list of
  * unsigned varints. Returns a list of strings.
  * unsigned varints. Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedUint64String = function() {
 jspb.BinaryReader.prototype.readPackedUint64String = function() {
   return this.readPackedField_(this.decoder_.readUnsignedVarint64String);
   return this.readPackedField_(this.decoder_.readUnsignedVarint64String);
@@ -1072,7 +1072,7 @@ jspb.BinaryReader.prototype.readPackedUint64String = function() {
 /**
 /**
  * Reads a packed sint32 field, which consists of a length header and a list of
  * Reads a packed sint32 field, which consists of a length header and a list of
  * zigzag varints.
  * zigzag varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSint32 = function() {
 jspb.BinaryReader.prototype.readPackedSint32 = function() {
   return this.readPackedField_(this.decoder_.readZigzagVarint32);
   return this.readPackedField_(this.decoder_.readZigzagVarint32);
@@ -1082,7 +1082,7 @@ jspb.BinaryReader.prototype.readPackedSint32 = function() {
 /**
 /**
  * Reads a packed sint64 field, which consists of a length header and a list of
  * Reads a packed sint64 field, which consists of a length header and a list of
  * zigzag varints.
  * zigzag varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSint64 = function() {
 jspb.BinaryReader.prototype.readPackedSint64 = function() {
   return this.readPackedField_(this.decoder_.readZigzagVarint64);
   return this.readPackedField_(this.decoder_.readZigzagVarint64);
@@ -1092,7 +1092,7 @@ jspb.BinaryReader.prototype.readPackedSint64 = function() {
 /**
 /**
  * Reads a packed sint64 field, which consists of a length header and a list of
  * Reads a packed sint64 field, which consists of a length header and a list of
  * zigzag varints.  Returns a list of strings.
  * zigzag varints.  Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSint64String = function() {
 jspb.BinaryReader.prototype.readPackedSint64String = function() {
   return this.readPackedField_(this.decoder_.readZigzagVarint64String);
   return this.readPackedField_(this.decoder_.readZigzagVarint64String);
@@ -1102,7 +1102,7 @@ jspb.BinaryReader.prototype.readPackedSint64String = function() {
 /**
 /**
  * Reads a packed fixed32 field, which consists of a length header and a list
  * Reads a packed fixed32 field, which consists of a length header and a list
  * of unsigned 32-bit ints.
  * of unsigned 32-bit ints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedFixed32 = function() {
 jspb.BinaryReader.prototype.readPackedFixed32 = function() {
   return this.readPackedField_(this.decoder_.readUint32);
   return this.readPackedField_(this.decoder_.readUint32);
@@ -1112,7 +1112,7 @@ jspb.BinaryReader.prototype.readPackedFixed32 = function() {
 /**
 /**
  * Reads a packed fixed64 field, which consists of a length header and a list
  * Reads a packed fixed64 field, which consists of a length header and a list
  * of unsigned 64-bit ints.
  * of unsigned 64-bit ints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedFixed64 = function() {
 jspb.BinaryReader.prototype.readPackedFixed64 = function() {
   return this.readPackedField_(this.decoder_.readUint64);
   return this.readPackedField_(this.decoder_.readUint64);
@@ -1122,7 +1122,7 @@ jspb.BinaryReader.prototype.readPackedFixed64 = function() {
 /**
 /**
  * Reads a packed fixed64 field, which consists of a length header and a list
  * Reads a packed fixed64 field, which consists of a length header and a list
  * of unsigned 64-bit ints.  Returns a list of strings.
  * of unsigned 64-bit ints.  Returns a list of strings.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedFixed64String = function() {
 jspb.BinaryReader.prototype.readPackedFixed64String = function() {
   return this.readPackedField_(this.decoder_.readUint64String);
   return this.readPackedField_(this.decoder_.readUint64String);
@@ -1132,7 +1132,7 @@ jspb.BinaryReader.prototype.readPackedFixed64String = function() {
 /**
 /**
  * Reads a packed sfixed32 field, which consists of a length header and a list
  * Reads a packed sfixed32 field, which consists of a length header and a list
  * of 32-bit ints.
  * of 32-bit ints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
 jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
   return this.readPackedField_(this.decoder_.readInt32);
   return this.readPackedField_(this.decoder_.readInt32);
@@ -1142,7 +1142,7 @@ jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
 /**
 /**
  * Reads a packed sfixed64 field, which consists of a length header and a list
  * Reads a packed sfixed64 field, which consists of a length header and a list
  * of 64-bit ints.
  * of 64-bit ints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
 jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
   return this.readPackedField_(this.decoder_.readInt64);
   return this.readPackedField_(this.decoder_.readInt64);
@@ -1152,7 +1152,7 @@ jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
 /**
 /**
  * Reads a packed sfixed64 field, which consists of a length header and a list
  * Reads a packed sfixed64 field, which consists of a length header and a list
  * of 64-bit ints.  Returns a list of strings.
  * of 64-bit ints.  Returns a list of strings.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedSfixed64String = function() {
 jspb.BinaryReader.prototype.readPackedSfixed64String = function() {
   return this.readPackedField_(this.decoder_.readInt64String);
   return this.readPackedField_(this.decoder_.readInt64String);
@@ -1162,7 +1162,7 @@ jspb.BinaryReader.prototype.readPackedSfixed64String = function() {
 /**
 /**
  * Reads a packed float field, which consists of a length header and a list of
  * Reads a packed float field, which consists of a length header and a list of
  * floats.
  * floats.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedFloat = function() {
 jspb.BinaryReader.prototype.readPackedFloat = function() {
   return this.readPackedField_(this.decoder_.readFloat);
   return this.readPackedField_(this.decoder_.readFloat);
@@ -1172,7 +1172,7 @@ jspb.BinaryReader.prototype.readPackedFloat = function() {
 /**
 /**
  * Reads a packed double field, which consists of a length header and a list of
  * Reads a packed double field, which consists of a length header and a list of
  * doubles.
  * doubles.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedDouble = function() {
 jspb.BinaryReader.prototype.readPackedDouble = function() {
   return this.readPackedField_(this.decoder_.readDouble);
   return this.readPackedField_(this.decoder_.readDouble);
@@ -1182,7 +1182,7 @@ jspb.BinaryReader.prototype.readPackedDouble = function() {
 /**
 /**
  * Reads a packed bool field, which consists of a length header and a list of
  * Reads a packed bool field, which consists of a length header and a list of
  * unsigned varints.
  * unsigned varints.
- * @return {!Array.<boolean>}
+ * @return {!Array<boolean>}
  */
  */
 jspb.BinaryReader.prototype.readPackedBool = function() {
 jspb.BinaryReader.prototype.readPackedBool = function() {
   return this.readPackedField_(this.decoder_.readBool);
   return this.readPackedField_(this.decoder_.readBool);
@@ -1192,7 +1192,7 @@ jspb.BinaryReader.prototype.readPackedBool = function() {
 /**
 /**
  * Reads a packed enum field, which consists of a length header and a list of
  * Reads a packed enum field, which consists of a length header and a list of
  * unsigned varints.
  * unsigned varints.
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  */
  */
 jspb.BinaryReader.prototype.readPackedEnum = function() {
 jspb.BinaryReader.prototype.readPackedEnum = function() {
   return this.readPackedField_(this.decoder_.readEnum);
   return this.readPackedField_(this.decoder_.readEnum);
@@ -1202,7 +1202,7 @@ jspb.BinaryReader.prototype.readPackedEnum = function() {
 /**
 /**
  * Reads a packed varint hash64 field, which consists of a length header and a
  * Reads a packed varint hash64 field, which consists of a length header and a
  * list of varint hash64s.
  * list of varint hash64s.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
 jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
   return this.readPackedField_(this.decoder_.readVarintHash64);
   return this.readPackedField_(this.decoder_.readVarintHash64);
@@ -1212,7 +1212,7 @@ jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
 /**
 /**
  * Reads a packed fixed hash64 field, which consists of a length header and a
  * Reads a packed fixed hash64 field, which consists of a length header and a
  * list of fixed hash64s.
  * list of fixed hash64s.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
 jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
   return this.readPackedField_(this.decoder_.readFixedHash64);
   return this.readPackedField_(this.decoder_.readFixedHash64);

+ 4 - 4
js/binary/utils.js

@@ -431,7 +431,7 @@ jspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
 
 
 /**
 /**
  * Individual digits for number->string conversion.
  * Individual digits for number->string conversion.
- * @const {!Array.<string>}
+ * @const {!Array<string>}
  */
  */
 jspb.utils.DIGITS = [
 jspb.utils.DIGITS = [
   '0', '1', '2', '3', '4', '5', '6', '7',
   '0', '1', '2', '3', '4', '5', '6', '7',
@@ -554,10 +554,10 @@ jspb.utils.hash64ToDecimalString = function(hash, signed) {
 /**
 /**
  * Converts an array of 8-character hash strings into their decimal
  * Converts an array of 8-character hash strings into their decimal
  * representations.
  * representations.
- * @param {!Array.<string>} hashes The array of hash strings to convert.
+ * @param {!Array<string>} hashes The array of hash strings to convert.
  * @param {boolean} signed True if we should treat the hash string as encoding
  * @param {boolean} signed True if we should treat the hash string as encoding
  *     a signed integer.
  *     a signed integer.
- * @return {!Array.<string>}
+ * @return {!Array<string>}
  */
  */
 jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) {
 jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) {
   var result = new Array(hashes.length);
   var result = new Array(hashes.length);
@@ -972,7 +972,7 @@ jspb.utils.byteSourceToUint8Array = function(data) {
   }
   }
 
 
   if (data.constructor === Array) {
   if (data.constructor === Array) {
-    data = /** @type {!Array.<number>} */(data);
+    data = /** @type {!Array<number>} */(data);
     return /** @type {!Uint8Array} */(new Uint8Array(data));
     return /** @type {!Uint8Array} */(new Uint8Array(data));
   }
   }
 
 

+ 1 - 1
js/binary/utils_test.js

@@ -657,7 +657,7 @@ describe('binaryUtilsTest', function() {
     // Converting Uint8Arrays into Uint8Arrays should be a no-op.
     // Converting Uint8Arrays into Uint8Arrays should be a no-op.
     assertEquals(sourceBytes, convert(sourceBytes));
     assertEquals(sourceBytes, convert(sourceBytes));
 
 
-    // Converting Array.<numbers> into Uint8Arrays should work.
+    // Converting Array<numbers> into Uint8Arrays should work.
     check(convert(sourceData));
     check(convert(sourceData));
 
 
     // Converting ArrayBuffers into Uint8Arrays should work.
     // Converting ArrayBuffers into Uint8Arrays should work.

+ 53 - 53
js/binary/writer.js

@@ -102,7 +102,7 @@ jspb.BinaryWriter = function() {
    * A stack of bookmarks containing the parent blocks for each message started
    * A stack of bookmarks containing the parent blocks for each message started
    * via beginSubMessage(), needed as bookkeeping for endSubMessage().
    * via beginSubMessage(), needed as bookkeeping for endSubMessage().
    * TODO(aappleby): Deprecated, users should be calling writeMessage().
    * TODO(aappleby): Deprecated, users should be calling writeMessage().
-   * @private {!Array.<!Array.<number>>}
+   * @private {!Array<!Array<number>>}
    */
    */
   this.bookmarks_ = [];
   this.bookmarks_ = [];
 };
 };
@@ -126,7 +126,7 @@ jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
  * Begins a new message by writing the field header and returning a bookmark
  * Begins a new message by writing the field header and returning a bookmark
  * which we will use to patch in the message length to in endDelimited_ below.
  * which we will use to patch in the message length to in endDelimited_ below.
  * @param {number} field
  * @param {number} field
- * @return {!Array.<number>}
+ * @return {!Array<number>}
  * @private
  * @private
  */
  */
 jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
 jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
@@ -143,7 +143,7 @@ jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
  * Ends a message by encoding the _change_ in length of the buffer to the
  * Ends a message by encoding the _change_ in length of the buffer to the
  * parent block and adds the number of bytes needed to encode that length to
  * parent block and adds the number of bytes needed to encode that length to
  * the total byte length.
  * the total byte length.
- * @param {!Array.<number>} bookmark
+ * @param {!Array<number>} bookmark
  * @private
  * @private
  */
  */
 jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
 jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
@@ -855,7 +855,7 @@ jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated 32-bit int field.
  * Writes an array of numbers to the buffer as a repeated 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -869,7 +869,7 @@ jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * 32-bit int field.
  * 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
+ * @param {?Array<string>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -882,7 +882,7 @@ jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated 64-bit int field.
  * Writes an array of numbers to the buffer as a repeated 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -896,7 +896,7 @@ jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * 64-bit int field.
  * 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
+ * @param {?Array<string>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -910,7 +910,7 @@ jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
  * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
  * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
  *     field.
  *     field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -924,7 +924,7 @@ jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * unsigned 32-bit int field.
  * unsigned 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
+ * @param {?Array<string>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -938,7 +938,7 @@ jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
  * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
  * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
  *     field.
  *     field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -952,7 +952,7 @@ jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * Writes an array of numbers formatted as strings to the buffer as a repeated
  * unsigned 64-bit int field.
  * unsigned 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
+ * @param {?Array<string>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -965,7 +965,7 @@ jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
 /**
 /**
  * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
  * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -978,7 +978,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
 /**
 /**
  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -991,7 +991,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
 /**
 /**
  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of ints to write.
+ * @param {?Array<string>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1005,7 +1005,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
  * Writes an array of numbers to the buffer as a repeated fixed32 field. This
  * Writes an array of numbers to the buffer as a repeated fixed32 field. This
  * works for both signed and unsigned fixed32s.
  * works for both signed and unsigned fixed32s.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1019,7 +1019,7 @@ jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
  * Writes an array of numbers to the buffer as a repeated fixed64 field. This
  * Writes an array of numbers to the buffer as a repeated fixed64 field. This
  * works for both signed and unsigned fixed64s.
  * works for both signed and unsigned fixed64s.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1033,7 +1033,7 @@ jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
  * Writes an array of numbers to the buffer as a repeated fixed64 field. This
  * Writes an array of numbers to the buffer as a repeated fixed64 field. This
  * works for both signed and unsigned fixed64s.
  * works for both signed and unsigned fixed64s.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of decimal strings to write.
+ * @param {?Array<string>} value The array of decimal strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
 jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
     field, value) {
     field, value) {
@@ -1047,7 +1047,7 @@ jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated sfixed32 field.
  * Writes an array of numbers to the buffer as a repeated sfixed32 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1060,7 +1060,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated sfixed64 field.
  * Writes an array of numbers to the buffer as a repeated sfixed64 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1074,7 +1074,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
  * Writes an array of decimal strings to the buffer as a repeated sfixed64
  * Writes an array of decimal strings to the buffer as a repeated sfixed64
  * field.
  * field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of decimal strings to write.
+ * @param {?Array<string>} value The array of decimal strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1087,7 +1087,7 @@ jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value)
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated float field.
  * Writes an array of numbers to the buffer as a repeated float field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1100,7 +1100,7 @@ jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a repeated double field.
  * Writes an array of numbers to the buffer as a repeated double field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1113,7 +1113,7 @@ jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
 /**
 /**
  * Writes an array of booleans to the buffer as a repeated bool field.
  * Writes an array of booleans to the buffer as a repeated bool field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<boolean>} value The array of ints to write.
+ * @param {?Array<boolean>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1126,7 +1126,7 @@ jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
 /**
 /**
  * Writes an array of enums to the buffer as a repeated enum field.
  * Writes an array of enums to the buffer as a repeated enum field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1139,7 +1139,7 @@ jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
 /**
 /**
  * Writes an array of strings to the buffer as a repeated string field.
  * Writes an array of strings to the buffer as a repeated string field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of strings to write.
+ * @param {?Array<string>} value The array of strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
   if (value == null) return;
   if (value == null) return;
@@ -1152,7 +1152,7 @@ jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
 /**
 /**
  * Writes an array of arbitrary byte fields to the buffer.
  * Writes an array of arbitrary byte fields to the buffer.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<!jspb.ByteSource>} value The arrays of arrays of bytes to
+ * @param {?Array<!jspb.ByteSource>} value The arrays of arrays of bytes to
  *     write.
  *     write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
 jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
@@ -1167,7 +1167,7 @@ jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
  * Writes an array of messages to the buffer.
  * Writes an array of messages to the buffer.
  * @template MessageType
  * @template MessageType
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<MessageType>} value The array of messages to
+ * @param {?Array<MessageType>} value The array of messages to
  *    write.
  *    write.
  * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
  * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
  *     Will be invoked with the value to write and the writer to write it with.
  *     Will be invoked with the value to write and the writer to write it with.
@@ -1187,7 +1187,7 @@ jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
  * Writes an array of group messages to the buffer.
  * Writes an array of group messages to the buffer.
  * @template MessageType
  * @template MessageType
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<MessageType>} value The array of messages to
+ * @param {?Array<MessageType>} value The array of messages to
  *    write.
  *    write.
  * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
  * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
  *     Will be invoked with the value to write and the writer to write it with.
  *     Will be invoked with the value to write and the writer to write it with.
@@ -1207,7 +1207,7 @@ jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * the buffer.
  * the buffer.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Array<string>} value The array of hashes to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
 jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
     function(field, value) {
     function(field, value) {
@@ -1222,7 +1222,7 @@ jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
  * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
  * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
  * each) to the buffer.
  * each) to the buffer.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Array<string>} value The array of hashes to write.
  */
  */
 jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
 jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
     function(field, value) {
     function(field, value) {
@@ -1236,7 +1236,7 @@ jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
 /**
 /**
  * Writes an array of numbers to the buffer as a packed 32-bit int field.
  * Writes an array of numbers to the buffer as a packed 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1252,7 +1252,7 @@ jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
  * Writes an array of numbers represented as strings to the buffer as a packed
  * Writes an array of numbers represented as strings to the buffer as a packed
  * 32-bit int field.
  * 32-bit int field.
  * @param {number} field
  * @param {number} field
- * @param {?Array.<string>} value
+ * @param {?Array<string>} value
  */
  */
 jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1267,7 +1267,7 @@ jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed 64-bit int field.
  * Writes an array of numbers to the buffer as a packed 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1283,7 +1283,7 @@ jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
  * Writes an array of numbers represented as strings to the buffer as a packed
  * Writes an array of numbers represented as strings to the buffer as a packed
  * 64-bit int field.
  * 64-bit int field.
  * @param {number} field
  * @param {number} field
- * @param {?Array.<string>} value
+ * @param {?Array<string>} value
  */
  */
 jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1299,7 +1299,7 @@ jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
 /**
 /**
  * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
  * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1315,7 +1315,7 @@ jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
  * Writes an array of numbers represented as strings to the buffer as a packed
  * Writes an array of numbers represented as strings to the buffer as a packed
  * unsigned 32-bit int field.
  * unsigned 32-bit int field.
  * @param {number} field
  * @param {number} field
- * @param {?Array.<string>} value
+ * @param {?Array<string>} value
  */
  */
 jspb.BinaryWriter.prototype.writePackedUint32String =
 jspb.BinaryWriter.prototype.writePackedUint32String =
     function(field, value) {
     function(field, value) {
@@ -1331,7 +1331,7 @@ jspb.BinaryWriter.prototype.writePackedUint32String =
 /**
 /**
  * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
  * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1347,7 +1347,7 @@ jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
  * Writes an array of numbers represented as strings to the buffer as a packed
  * Writes an array of numbers represented as strings to the buffer as a packed
  * unsigned 64-bit int field.
  * unsigned 64-bit int field.
  * @param {number} field
  * @param {number} field
- * @param {?Array.<string>} value
+ * @param {?Array<string>} value
  */
  */
 jspb.BinaryWriter.prototype.writePackedUint64String =
 jspb.BinaryWriter.prototype.writePackedUint64String =
     function(field, value) {
     function(field, value) {
@@ -1364,7 +1364,7 @@ jspb.BinaryWriter.prototype.writePackedUint64String =
 /**
 /**
  * Writes an array numbers to the buffer as a packed signed 32-bit int field.
  * Writes an array numbers to the buffer as a packed signed 32-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1379,7 +1379,7 @@ jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed signed 64-bit int field.
  * Writes an array of numbers to the buffer as a packed signed 64-bit int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1395,7 +1395,7 @@ jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
  * Writes an array of decimal strings to the buffer as a packed signed 64-bit
  * Writes an array of decimal strings to the buffer as a packed signed 64-bit
  * int field.
  * int field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of decimal strings to write.
+ * @param {?Array<string>} value The array of decimal strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1411,7 +1411,7 @@ jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed fixed32 field.
  * Writes an array of numbers to the buffer as a packed fixed32 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1426,7 +1426,7 @@ jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed fixed64 field.
  * Writes an array of numbers to the buffer as a packed fixed64 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1442,7 +1442,7 @@ jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
  * Writes an array of numbers represented as strings to the buffer as a packed
  * Writes an array of numbers represented as strings to the buffer as a packed
  * fixed64 field.
  * fixed64 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of strings to write.
+ * @param {?Array<string>} value The array of strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1458,7 +1458,7 @@ jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed sfixed32 field.
  * Writes an array of numbers to the buffer as a packed sfixed32 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1473,7 +1473,7 @@ jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed sfixed64 field.
  * Writes an array of numbers to the buffer as a packed sfixed64 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1488,7 +1488,7 @@ jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed sfixed64 field.
  * Writes an array of numbers to the buffer as a packed sfixed64 field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of decimal strings to write.
+ * @param {?Array<string>} value The array of decimal strings to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1503,7 +1503,7 @@ jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed float field.
  * Writes an array of numbers to the buffer as a packed float field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1518,7 +1518,7 @@ jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
 /**
 /**
  * Writes an array of numbers to the buffer as a packed double field.
  * Writes an array of numbers to the buffer as a packed double field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1533,7 +1533,7 @@ jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
 /**
 /**
  * Writes an array of booleans to the buffer as a packed bool field.
  * Writes an array of booleans to the buffer as a packed bool field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<boolean>} value The array of ints to write.
+ * @param {?Array<boolean>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1548,7 +1548,7 @@ jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
 /**
 /**
  * Writes an array of enums to the buffer as a packed enum field.
  * Writes an array of enums to the buffer as a packed enum field.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<number>} value The array of ints to write.
+ * @param {?Array<number>} value The array of ints to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1564,7 +1564,7 @@ jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * the buffer.
  * the buffer.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Array<string>} value The array of hashes to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;
@@ -1580,7 +1580,7 @@ jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
  * the buffer.
  * the buffer.
  * @param {number} field The field number.
  * @param {number} field The field number.
- * @param {?Array.<string>} value The array of hashes to write.
+ * @param {?Array<string>} value The array of hashes to write.
  */
  */
 jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
 jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
   if (value == null || !value.length) return;
   if (value == null || !value.length) return;

+ 8 - 1
js/debug.js

@@ -74,15 +74,22 @@ jspb.debug.dump = function(message) {
  */
  */
 jspb.debug.dump_ = function(thing) {
 jspb.debug.dump_ = function(thing) {
   var type = goog.typeOf(thing);
   var type = goog.typeOf(thing);
+  var message = thing;  // Copy because we don't want type inference on thing.
   if (type == 'number' || type == 'string' || type == 'boolean' ||
   if (type == 'number' || type == 'string' || type == 'boolean' ||
       type == 'null' || type == 'undefined') {
       type == 'null' || type == 'undefined') {
     return thing;
     return thing;
   }
   }
+  if (window.Uint8Array) {
+    // Will fail on IE9, where Uint8Array doesn't exist.
+    if (message instanceof Uint8Array) {
+      return thing;
+    }
+  }
+
   if (type == 'array') {
   if (type == 'array') {
     goog.asserts.assertArray(thing);
     goog.asserts.assertArray(thing);
     return goog.array.map(thing, jspb.debug.dump_);
     return goog.array.map(thing, jspb.debug.dump_);
   }
   }
-  var message = thing;  // Copy because we don't want type inference on thing.
   goog.asserts.assert(message instanceof jspb.Message,
   goog.asserts.assert(message instanceof jspb.Message,
       'Only messages expected: ' + thing);
       'Only messages expected: ' + thing);
   var ctor = message.constructor;
   var ctor = message.constructor;

+ 11 - 0
js/debug_test.js

@@ -41,6 +41,8 @@ goog.require('proto.jspb.test.IsExtension');
 goog.require('proto.jspb.test.Simple1');
 goog.require('proto.jspb.test.Simple1');
 
 
 
 
+// CommonJS-LoadFromFile: testbinary_pb
+goog.require('proto.jspb.test.TestAllTypes');
 
 
 describe('debugTest', function() {
 describe('debugTest', function() {
   it('testSimple1', function() {
   it('testSimple1', function() {
@@ -74,6 +76,15 @@ describe('debugTest', function() {
     }, jspb.debug.dump(message));
     }, jspb.debug.dump(message));
   });
   });
 
 
+  it('testBytes', function() {
+    if (COMPILED || !window['Uint8Array']) {
+      return;
+    }
+    var message = new proto.jspb.test.TestAllTypes();
+    var bytes = new Uint8Array(4);
+    message.setOptionalBytes(bytes);
+    assertEquals(jspb.debug.dump(message)['optionalBytes'], bytes);
+  });
 
 
   it('testExtensions', function() {
   it('testExtensions', function() {
     if (COMPILED) {
     if (COMPILED) {

+ 53 - 11
js/message.js

@@ -205,6 +205,16 @@ goog.define('jspb.Message.GENERATE_TO_STRING', true);
 goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
 goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
 
 
 
 
+// TODO(jakubvrana): Turn this off by default.
+/**
+ * @define {boolean} Disabling the serialization of empty trailing fields
+ *     reduces the size of serialized protos. The price is an extra iteration of
+ *     the proto before serialization. This is enabled by default to be
+ *     backwards compatible. Projects are advised to turn this flag always off.
+ */
+goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
+
+
 /**
 /**
  * @define {boolean} Turning on this flag does NOT change the behavior of JSPB
  * @define {boolean} Turning on this flag does NOT change the behavior of JSPB
  *     and only affects private internal state. It may, however, break some
  *     and only affects private internal state. It may, however, break some
@@ -212,8 +222,8 @@ goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
  *     mutates its internal state.
  *     mutates its internal state.
  *     Projects are advised to turn this flag always on.
  *     Projects are advised to turn this flag always on.
  */
  */
-goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', COMPILED);
-// TODO(b/19419436) Turn this on by default.
+goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', true);
+// TODO(b/19419436): Delete this flag.
 
 
 
 
 /**
 /**
@@ -277,6 +287,13 @@ jspb.Message.prototype.messageId_;
 jspb.Message.prototype.convertedFloatingPointFields_;
 jspb.Message.prototype.convertedFloatingPointFields_;
 
 
 
 
+/**
+ * Repeated fields numbers.
+ * @protected {?Array<number>|undefined}
+ */
+jspb.Message.prototype.repeatedFields;
+
+
 /**
 /**
  * The xid of this proto type (The same for all instances of a proto). Provides
  * The xid of this proto type (The same for all instances of a proto). Provides
  * a way to identify a proto by stable obfuscated name.
  * a way to identify a proto by stable obfuscated name.
@@ -323,6 +340,18 @@ jspb.Message.getIndex_ = function(msg, fieldNumber) {
 };
 };
 
 
 
 
+/**
+ * Returns the tag number based on the index in msg.array.
+ * @param {!jspb.Message} msg Message for which we're calculating an index.
+ * @param {number} index The tag number.
+ * @return {number} The field number.
+ * @private
+ */
+jspb.Message.getFieldNumber_ = function(msg, index) {
+  return index - msg.arrayIndexOffset_;
+};
+
+
 /**
 /**
  * Initializes a JsPb Message.
  * Initializes a JsPb Message.
  * @param {!jspb.Message} msg The JsPb proto to modify.
  * @param {!jspb.Message} msg The JsPb proto to modify.
@@ -353,6 +382,13 @@ jspb.Message.initialize = function(
   jspb.Message.initPivotAndExtensionObject_(msg, suggestedPivot);
   jspb.Message.initPivotAndExtensionObject_(msg, suggestedPivot);
   msg.convertedFloatingPointFields_ = {};
   msg.convertedFloatingPointFields_ = {};
 
 
+  if (!jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS) {
+    // TODO(jakubvrana): This is same for all instances, move to prototype.
+    // TODO(jakubvrana): There are indexOf calls on this in serializtion,
+    // consider switching to a set.
+    msg.repeatedFields = repeatedFields;
+  }
+
   if (repeatedFields) {
   if (repeatedFields) {
     for (var i = 0; i < repeatedFields.length; i++) {
     for (var i = 0; i < repeatedFields.length; i++) {
       var fieldNumber = repeatedFields[i];
       var fieldNumber = repeatedFields[i];
@@ -376,8 +412,9 @@ jspb.Message.initialize = function(
   if (opt_oneofFields && opt_oneofFields.length) {
   if (opt_oneofFields && opt_oneofFields.length) {
     // Compute the oneof case for each union. This ensures only one value is
     // Compute the oneof case for each union. This ensures only one value is
     // set in the union.
     // set in the union.
-    goog.array.forEach(
-        opt_oneofFields, goog.partial(jspb.Message.computeOneofCase, msg));
+    for (var i = 0; i < opt_oneofFields.length; i++) {
+      jspb.Message.computeOneofCase(msg, opt_oneofFields[i]);
+    }
   }
   }
 };
 };
 
 
@@ -428,7 +465,7 @@ jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
     // in Safari on iOS 8. See the description of CL/86511464 for details.
     // in Safari on iOS 8. See the description of CL/86511464 for details.
     if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
     if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) &&
         !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
         !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
-      msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
+      msg.pivot_ = jspb.Message.getFieldNumber_(msg, foundIndex);
       msg.extensionObject_ = obj;
       msg.extensionObject_ = obj;
       return;
       return;
     }
     }
@@ -1043,14 +1080,15 @@ jspb.Message.computeOneofCase = function(msg, oneof) {
   var oneofField;
   var oneofField;
   var oneofValue;
   var oneofValue;
 
 
-  goog.array.forEach(oneof, function(fieldNumber) {
+  for (var i = 0; i < oneof.length; i++) {
+    var fieldNumber = oneof[i];
     var value = jspb.Message.getField(msg, fieldNumber);
     var value = jspb.Message.getField(msg, fieldNumber);
-    if (goog.isDefAndNotNull(value)) {
+    if (value != null) {
       oneofField = fieldNumber;
       oneofField = fieldNumber;
       oneofValue = value;
       oneofValue = value;
       jspb.Message.setField(msg, fieldNumber, undefined);
       jspb.Message.setField(msg, fieldNumber, undefined);
     }
     }
-  });
+  }
 
 
   if (oneofField) {
   if (oneofField) {
     // NB: We know the value is unique, so we can call jspb.Message.setField
     // NB: We know the value is unique, so we can call jspb.Message.setField
@@ -1241,7 +1279,7 @@ jspb.Message.addToRepeatedWrapperField = function(
  *     dead code removal.
  *     dead code removal.
  * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
  * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
  *     for transitional soy proto support: http://goto/soy-param-migration
  *     for transitional soy proto support: http://goto/soy-param-migration
- * @return {!Object.<string, Object>} A map of proto or Soy objects.
+ * @return {!Object<string, Object>} A map of proto or Soy objects.
  * @template T
  * @template T
  */
  */
 jspb.Message.toMap = function(
 jspb.Message.toMap = function(
@@ -1318,7 +1356,7 @@ jspb.Message.prototype.toString = function() {
 
 
 /**
 /**
  * Gets the value of the extension field from the extended object.
  * Gets the value of the extension field from the extended object.
- * @param {jspb.ExtensionFieldInfo.<T>} fieldInfo Specifies the field to get.
+ * @param {jspb.ExtensionFieldInfo<T>} fieldInfo Specifies the field to get.
  * @return {T} The value of the field.
  * @return {T} The value of the field.
  * @template T
  * @template T
  */
  */
@@ -1705,7 +1743,11 @@ jspb.Message.registry_ = {};
  * non-MessageSet. We special case MessageSet so that we do not need
  * non-MessageSet. We special case MessageSet so that we do not need
  * to goog.require MessageSet from classes that extends MessageSet.
  * to goog.require MessageSet from classes that extends MessageSet.
  *
  *
- * @type {!Object.<number, jspb.ExtensionFieldInfo>}
+ * @type {!Object<number, jspb.ExtensionFieldInfo>}
  */
  */
 jspb.Message.messageSetExtensions = {};
 jspb.Message.messageSetExtensions = {};
+
+/**
+ * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}
+ */
 jspb.Message.messageSetExtensionsBinary = {};
 jspb.Message.messageSetExtensionsBinary = {};

+ 20 - 0
js/message_test.js

@@ -34,6 +34,7 @@ goog.setTestOnly();
 
 
 goog.require('goog.json');
 goog.require('goog.json');
 goog.require('goog.string');
 goog.require('goog.string');
+goog.require('goog.testing.PropertyReplacer');
 goog.require('goog.testing.asserts');
 goog.require('goog.testing.asserts');
 goog.require('goog.userAgent');
 goog.require('goog.userAgent');
 
 
@@ -85,6 +86,16 @@ goog.require('proto.jspb.test.TestExtensionsMessage');
 
 
 
 
 describe('Message test suite', function() {
 describe('Message test suite', function() {
+  var stubs = new goog.testing.PropertyReplacer();
+
+  beforeEach(function() {
+    stubs.set(jspb.Message, 'SERIALIZE_EMPTY_TRAILING_FIELDS', false);
+  });
+
+  afterEach(function() {
+    stubs.reset();
+  });
+
   it('testEmptyProto', function() {
   it('testEmptyProto', function() {
     var empty1 = new proto.jspb.test.Empty([]);
     var empty1 = new proto.jspb.test.Empty([]);
     var empty2 = new proto.jspb.test.Empty([]);
     var empty2 = new proto.jspb.test.Empty([]);
@@ -1041,4 +1052,13 @@ describe('Message test suite', function() {
     assertNan(message.getDefaultDoubleField());
     assertNan(message.getDefaultDoubleField());
   });
   });
 
 
+  it('testSerializePreservesEmptyNestedField', function() {
+    var message = new proto.jspb.test.OptionalFields();
+    message.setANestedMessage(new proto.jspb.test.OptionalFields.Nested());
+    message.addARepeatedMessage(new proto.jspb.test.OptionalFields.Nested());
+    message = proto.jspb.test.OptionalFields.deserialize(message.serialize());
+    assertNotNullNorUndefined(message.getANestedMessage());
+    assertEquals(1, message.getARepeatedMessageList().length);
+  });
+
 });
 });

+ 13 - 8
objectivec/google/protobuf/Any.pbobjc.h

@@ -135,17 +135,18 @@ typedef GPB_ENUM(GPBAny_FieldNumber) {
 @interface GPBAny : GPBMessage
 @interface GPBAny : GPBMessage
 
 
 /**
 /**
- * A URL/resource name whose content describes the type of the
- * serialized protocol buffer message.
+ * A URL/resource name that uniquely identifies the type of the serialized
+ * protocol buffer message. The last segment of the URL's path must represent
+ * the fully qualified name of the type (as in
+ * `path/google.protobuf.Duration`). The name should be in a canonical form
+ * (e.g., leading "." is not accepted).
  *
  *
- * For URLs which use the scheme `http`, `https`, or no scheme, the
- * following restrictions and interpretations apply:
+ * In practice, teams usually precompile into the binary all types that they
+ * expect it to use in the context of Any. However, for URLs which use the
+ * scheme `http`, `https`, or no scheme, one can optionally set up a type
+ * server that maps type URLs to message definitions as follows:
  *
  *
  * * If no scheme is provided, `https` is assumed.
  * * If no scheme is provided, `https` is assumed.
- * * The last segment of the URL's path must represent the fully
- *   qualified name of the type (as in `path/google.protobuf.Duration`).
- *   The name should be in a canonical form (e.g., leading "." is
- *   not accepted).
  * * An HTTP GET on the URL must yield a [google.protobuf.Type][]
  * * An HTTP GET on the URL must yield a [google.protobuf.Type][]
  *   value in binary format, or produce an error.
  *   value in binary format, or produce an error.
  * * Applications are allowed to cache lookup results based on the
  * * Applications are allowed to cache lookup results based on the
@@ -154,6 +155,10 @@ typedef GPB_ENUM(GPBAny_FieldNumber) {
  *   on changes to types. (Use versioned type names to manage
  *   on changes to types. (Use versioned type names to manage
  *   breaking changes.)
  *   breaking changes.)
  *
  *
+ * Note: this functionality is not currently available in the official
+ * protobuf release, and it is not used for type URLs beginning with
+ * type.googleapis.com.
+ *
  * Schemes other than `http`, `https` (or the empty scheme) might be
  * Schemes other than `http`, `https` (or the empty scheme) might be
  * used with implementation specific semantics.
  * used with implementation specific semantics.
  **/
  **/

+ 2 - 2
objectivec/google/protobuf/Timestamp.pbobjc.h

@@ -126,8 +126,8 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
  * to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
  * to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
  * with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
  * with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
  * can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
  * can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
- * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--)
- * to obtain a formatter capable of generating timestamps in this format.
+ * http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime--
+ * ) to obtain a formatter capable of generating timestamps in this format.
  **/
  **/
 @interface GPBTimestamp : GPBMessage
 @interface GPBTimestamp : GPBMessage
 
 

+ 2 - 2
python/google/protobuf/descriptor.py

@@ -41,8 +41,8 @@ from google.protobuf.internal import api_implementation
 _USE_C_DESCRIPTORS = False
 _USE_C_DESCRIPTORS = False
 if api_implementation.Type() == 'cpp':
 if api_implementation.Type() == 'cpp':
   # Used by MakeDescriptor in cpp mode
   # Used by MakeDescriptor in cpp mode
+  import binascii
   import os
   import os
-  import uuid
   from google.protobuf.pyext import _message
   from google.protobuf.pyext import _message
   _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False)
   _USE_C_DESCRIPTORS = getattr(_message, '_USE_C_DESCRIPTORS', False)
 
 
@@ -952,7 +952,7 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
     # imported ones. We need to specify a file name so the descriptor pool
     # imported ones. We need to specify a file name so the descriptor pool
     # accepts our FileDescriptorProto, but it is not important what that file
     # accepts our FileDescriptorProto, but it is not important what that file
     # name is actually set to.
     # name is actually set to.
-    proto_name = str(uuid.uuid4())
+    proto_name = binascii.hexlify(os.urandom(16)).decode('ascii')
 
 
     if package:
     if package:
       file_descriptor_proto.name = os.path.join(package.replace('.', '/'),
       file_descriptor_proto.name = os.path.join(package.replace('.', '/'),

+ 18 - 8
python/google/protobuf/descriptor_database.py

@@ -32,6 +32,8 @@
 
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 
+import warnings
+
 
 
 class Error(Exception):
 class Error(Exception):
   pass
   pass
@@ -64,21 +66,20 @@ class DescriptorDatabase(object):
     elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
     elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
       raise DescriptorDatabaseConflictingDefinitionError(
       raise DescriptorDatabaseConflictingDefinitionError(
           '%s already added, but with different descriptor.' % proto_name)
           '%s already added, but with different descriptor.' % proto_name)
+    else:
+      return
 
 
     # Add all the top-level descriptors to the index.
     # Add all the top-level descriptors to the index.
     package = file_desc_proto.package
     package = file_desc_proto.package
     for message in file_desc_proto.message_type:
     for message in file_desc_proto.message_type:
-      self._file_desc_protos_by_symbol.update(
-          (name, file_desc_proto) for name in _ExtractSymbols(message, package))
+      for name in _ExtractSymbols(message, package):
+        self._AddSymbol(name, file_desc_proto)
     for enum in file_desc_proto.enum_type:
     for enum in file_desc_proto.enum_type:
-      self._file_desc_protos_by_symbol[
-          '.'.join((package, enum.name))] = file_desc_proto
+      self._AddSymbol(('.'.join((package, enum.name))), file_desc_proto)
     for extension in file_desc_proto.extension:
     for extension in file_desc_proto.extension:
-      self._file_desc_protos_by_symbol[
-          '.'.join((package, extension.name))] = file_desc_proto
+      self._AddSymbol(('.'.join((package, extension.name))), file_desc_proto)
     for service in file_desc_proto.service:
     for service in file_desc_proto.service:
-      self._file_desc_protos_by_symbol[
-          '.'.join((package, service.name))] = file_desc_proto
+      self._AddSymbol(('.'.join((package, service.name))), file_desc_proto)
 
 
   def FindFileByName(self, name):
   def FindFileByName(self, name):
     """Finds the file descriptor proto by file name.
     """Finds the file descriptor proto by file name.
@@ -132,6 +133,15 @@ class DescriptorDatabase(object):
       top_level, _, _ = symbol.rpartition('.')
       top_level, _, _ = symbol.rpartition('.')
       return self._file_desc_protos_by_symbol[top_level]
       return self._file_desc_protos_by_symbol[top_level]
 
 
+  def _AddSymbol(self, name, file_desc_proto):
+    if name in self._file_desc_protos_by_symbol:
+      warn_msg = ('Conflict register for file "' + file_desc_proto.name +
+                  '": ' + name +
+                  ' is already defined in file "' +
+                  self._file_desc_protos_by_symbol[name].name + '"')
+      warnings.warn(warn_msg, RuntimeWarning)
+    self._file_desc_protos_by_symbol[name] = file_desc_proto
+
 
 
 def _ExtractSymbols(desc_proto, package):
 def _ExtractSymbols(desc_proto, package):
   """Pulls out all the symbols from a descriptor proto.
   """Pulls out all the symbols from a descriptor proto.

+ 42 - 1
python/google/protobuf/descriptor_pool.py

@@ -58,6 +58,7 @@ directly instead of this class.
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 
 import collections
 import collections
+import warnings
 
 
 from google.protobuf import descriptor
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
 from google.protobuf import descriptor_database
@@ -127,12 +128,38 @@ class DescriptorPool(object):
     self._service_descriptors = {}
     self._service_descriptors = {}
     self._file_descriptors = {}
     self._file_descriptors = {}
     self._toplevel_extensions = {}
     self._toplevel_extensions = {}
+    # TODO(jieluo): Remove _file_desc_by_toplevel_extension after
+    # maybe year 2020 for compatibility issue (with 3.4.1 only).
+    self._file_desc_by_toplevel_extension = {}
     # We store extensions in two two-level mappings: The first key is the
     # We store extensions in two two-level mappings: The first key is the
     # descriptor of the message being extended, the second key is the extension
     # descriptor of the message being extended, the second key is the extension
     # full name or its tag number.
     # full name or its tag number.
     self._extensions_by_name = collections.defaultdict(dict)
     self._extensions_by_name = collections.defaultdict(dict)
     self._extensions_by_number = collections.defaultdict(dict)
     self._extensions_by_number = collections.defaultdict(dict)
 
 
+  def _CheckConflictRegister(self, desc):
+    """Check if the descriptor name conflicts with another of the same name.
+
+    Args:
+      desc: Descriptor of a message, enum, service or extension.
+    """
+    desc_name = desc.full_name
+    for register, descriptor_type in [
+        (self._descriptors, descriptor.Descriptor),
+        (self._enum_descriptors, descriptor.EnumDescriptor),
+        (self._service_descriptors, descriptor.ServiceDescriptor),
+        (self._toplevel_extensions, descriptor.FieldDescriptor)]:
+      if desc_name in register:
+        file_name = register[desc_name].file.name
+        if not isinstance(desc, descriptor_type) or (
+            file_name != desc.file.name):
+          warn_msg = ('Conflict register for file "' + desc.file.name +
+                      '": ' + desc_name +
+                      ' is already defined in file "' +
+                      file_name + '"')
+          warnings.warn(warn_msg, RuntimeWarning)
+        return
+
   def Add(self, file_desc_proto):
   def Add(self, file_desc_proto):
     """Adds the FileDescriptorProto and its types to this pool.
     """Adds the FileDescriptorProto and its types to this pool.
 
 
@@ -169,6 +196,8 @@ class DescriptorPool(object):
     if not isinstance(desc, descriptor.Descriptor):
     if not isinstance(desc, descriptor.Descriptor):
       raise TypeError('Expected instance of descriptor.Descriptor.')
       raise TypeError('Expected instance of descriptor.Descriptor.')
 
 
+    self._CheckConflictRegister(desc)
+
     self._descriptors[desc.full_name] = desc
     self._descriptors[desc.full_name] = desc
     self._AddFileDescriptor(desc.file)
     self._AddFileDescriptor(desc.file)
 
 
@@ -184,6 +213,7 @@ class DescriptorPool(object):
     if not isinstance(enum_desc, descriptor.EnumDescriptor):
     if not isinstance(enum_desc, descriptor.EnumDescriptor):
       raise TypeError('Expected instance of descriptor.EnumDescriptor.')
       raise TypeError('Expected instance of descriptor.EnumDescriptor.')
 
 
+    self._CheckConflictRegister(enum_desc)
     self._enum_descriptors[enum_desc.full_name] = enum_desc
     self._enum_descriptors[enum_desc.full_name] = enum_desc
     self._AddFileDescriptor(enum_desc.file)
     self._AddFileDescriptor(enum_desc.file)
 
 
@@ -197,6 +227,7 @@ class DescriptorPool(object):
     if not isinstance(service_desc, descriptor.ServiceDescriptor):
     if not isinstance(service_desc, descriptor.ServiceDescriptor):
       raise TypeError('Expected instance of descriptor.ServiceDescriptor.')
       raise TypeError('Expected instance of descriptor.ServiceDescriptor.')
 
 
+    self._CheckConflictRegister(service_desc)
     self._service_descriptors[service_desc.full_name] = service_desc
     self._service_descriptors[service_desc.full_name] = service_desc
 
 
   def AddExtensionDescriptor(self, extension):
   def AddExtensionDescriptor(self, extension):
@@ -216,6 +247,7 @@ class DescriptorPool(object):
       raise TypeError('Expected an extension descriptor.')
       raise TypeError('Expected an extension descriptor.')
 
 
     if extension.extension_scope is None:
     if extension.extension_scope is None:
+      self._CheckConflictRegister(extension)
       self._toplevel_extensions[extension.full_name] = extension
       self._toplevel_extensions[extension.full_name] = extension
 
 
     try:
     try:
@@ -252,6 +284,12 @@ class DescriptorPool(object):
     """
     """
 
 
     self._AddFileDescriptor(file_desc)
     self._AddFileDescriptor(file_desc)
+    # TODO(jieluo): This is a temporary solution for FieldDescriptor.file.
+    # FieldDescriptor.file is added in code gen. Remove this solution after
+    # maybe 2020 for compatibility reason (with 3.4.1 only).
+    for extension in file_desc.extensions_by_name.values():
+      self._file_desc_by_toplevel_extension[
+          extension.full_name] = file_desc
 
 
   def _AddFileDescriptor(self, file_desc):
   def _AddFileDescriptor(self, file_desc):
     """Adds a FileDescriptor to the pool, non-recursively.
     """Adds a FileDescriptor to the pool, non-recursively.
@@ -331,7 +369,7 @@ class DescriptorPool(object):
       pass
       pass
 
 
     try:
     try:
-      return self._toplevel_extensions[symbol].file
+      return self._file_desc_by_toplevel_extension[symbol]
     except KeyError:
     except KeyError:
       pass
       pass
 
 
@@ -680,6 +718,7 @@ class DescriptorPool(object):
         fields[field_index].containing_oneof = oneofs[oneof_index]
         fields[field_index].containing_oneof = oneofs[oneof_index]
 
 
     scope[_PrefixWithDot(desc_name)] = desc
     scope[_PrefixWithDot(desc_name)] = desc
+    self._CheckConflictRegister(desc)
     self._descriptors[desc_name] = desc
     self._descriptors[desc_name] = desc
     return desc
     return desc
 
 
@@ -718,6 +757,7 @@ class DescriptorPool(object):
                                      containing_type=containing_type,
                                      containing_type=containing_type,
                                      options=_OptionsOrNone(enum_proto))
                                      options=_OptionsOrNone(enum_proto))
     scope['.%s' % enum_name] = desc
     scope['.%s' % enum_name] = desc
+    self._CheckConflictRegister(desc)
     self._enum_descriptors[enum_name] = desc
     self._enum_descriptors[enum_name] = desc
     return desc
     return desc
 
 
@@ -914,6 +954,7 @@ class DescriptorPool(object):
                                         methods=methods,
                                         methods=methods,
                                         options=_OptionsOrNone(service_proto),
                                         options=_OptionsOrNone(service_proto),
                                         file=file_desc)
                                         file=file_desc)
+    self._CheckConflictRegister(desc)
     self._service_descriptors[service_name] = desc
     self._service_descriptors[service_name] = desc
     return desc
     return desc
 
 

+ 21 - 0
python/google/protobuf/internal/descriptor_database_test.py

@@ -38,6 +38,7 @@ try:
   import unittest2 as unittest  #PY26
   import unittest2 as unittest  #PY26
 except ImportError:
 except ImportError:
   import unittest
   import unittest
+import warnings
 
 
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf import descriptor_pb2
@@ -98,6 +99,26 @@ class DescriptorDatabaseTest(unittest.TestCase):
                       db.FindFileContainingSymbol,
                       db.FindFileContainingSymbol,
                       'protobuf_unittest.NoneMessage')
                       'protobuf_unittest.NoneMessage')
 
 
+  def testConflictRegister(self):
+    db = descriptor_database.DescriptorDatabase()
+    unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    db.Add(unittest_fd)
+    conflict_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    conflict_fd.name = 'other_file'
+    with warnings.catch_warnings(record=True) as w:
+      # Cause all warnings to always be triggered.
+      warnings.simplefilter('always')
+      db.Add(conflict_fd)
+      self.assertTrue(len(w))
+      self.assertIs(w[0].category, RuntimeWarning)
+      self.assertIn('Conflict register for file "other_file": ',
+                    str(w[0].message))
+      self.assertIn('already defined in file '
+                    '"google/protobuf/unittest.proto"',
+                    str(w[0].message))
+
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
   unittest.main()
   unittest.main()

+ 56 - 0
python/google/protobuf/internal/descriptor_pool_test.py

@@ -34,8 +34,10 @@
 
 
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 
+import copy
 import os
 import os
 import sys
 import sys
+import warnings
 
 
 try:
 try:
   import unittest2 as unittest  #PY26
   import unittest2 as unittest  #PY26
@@ -119,6 +121,14 @@ class DescriptorPoolTestBase(object):
     self.assertEqual('google/protobuf/unittest.proto',
     self.assertEqual('google/protobuf/unittest.proto',
                      file_desc5.name)
                      file_desc5.name)
 
 
+    # Tests the generated pool.
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'google.protobuf.python.internal.Factory2Message.one_more_field')
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'google.protobuf.python.internal.another_field')
+    assert descriptor_pool.Default().FindFileContainingSymbol(
+        'protobuf_unittest.TestService')
+
   def testFindFileContainingSymbolFailure(self):
   def testFindFileContainingSymbolFailure(self):
     with self.assertRaises(KeyError):
     with self.assertRaises(KeyError):
       self.pool.FindFileContainingSymbol('Does not exist')
       self.pool.FindFileContainingSymbol('Does not exist')
@@ -492,6 +502,52 @@ class DescriptorPoolTestBase(object):
     TEST1_FILE.CheckFile(self, self.pool)
     TEST1_FILE.CheckFile(self, self.pool)
     TEST2_FILE.CheckFile(self, self.pool)
     TEST2_FILE.CheckFile(self, self.pool)
 
 
+  def testConflictRegister(self):
+    if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+      if api_implementation.Type() == 'cpp':
+        # Cpp extension cannot call Add on a DescriptorPool
+        # that uses a DescriptorDatabase.
+        # TODO(jieluo): Fix python and cpp extension diff.
+        return
+    unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+        unittest_pb2.DESCRIPTOR.serialized_pb)
+    conflict_fd = copy.deepcopy(unittest_fd)
+    conflict_fd.name = 'other_file'
+    if api_implementation.Type() == 'cpp':
+      try:
+        self.pool.Add(unittest_fd)
+        self.pool.Add(conflict_fd)
+      except TypeError:
+        pass
+    else:
+      with warnings.catch_warnings(record=True) as w:
+        # Cause all warnings to always be triggered.
+        warnings.simplefilter('always')
+        pool = copy.deepcopy(self.pool)
+        # No warnings to add the same descriptors.
+        file_descriptor = unittest_pb2.DESCRIPTOR
+        pool.AddDescriptor(
+            file_descriptor.message_types_by_name['TestAllTypes'])
+        pool.AddEnumDescriptor(
+            file_descriptor.enum_types_by_name['ForeignEnum'])
+        pool.AddServiceDescriptor(
+            file_descriptor.services_by_name['TestService'])
+        pool.AddExtensionDescriptor(
+            file_descriptor.extensions_by_name['optional_int32_extension'])
+        self.assertEqual(len(w), 0)
+        # Check warnings for conflict descriptors with the same name.
+        pool.Add(unittest_fd)
+        pool.Add(conflict_fd)
+        pool.FindFileByName(unittest_fd.name)
+        pool.FindFileByName(conflict_fd.name)
+        self.assertTrue(len(w))
+        self.assertIs(w[0].category, RuntimeWarning)
+        self.assertIn('Conflict register for file "other_file": ',
+                      str(w[0].message))
+        self.assertIn('already defined in file '
+                      '"google/protobuf/unittest.proto"',
+                      str(w[0].message))
+
 
 
 class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
 class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
 
 

+ 2 - 1
python/google/protobuf/internal/encoder.py

@@ -418,7 +418,8 @@ def _VarintBytes(value):
 def TagBytes(field_number, wire_type):
 def TagBytes(field_number, wire_type):
   """Encode the given tag and return the bytes.  Only called at startup."""
   """Encode the given tag and return the bytes.  Only called at startup."""
 
 
-  return six.binary_type( _VarintBytes(wire_format.PackTag(field_number, wire_type)) )
+  return six.binary_type(
+      _VarintBytes(wire_format.PackTag(field_number, wire_type)))
 
 
 # --------------------------------------------------------------------
 # --------------------------------------------------------------------
 # As with sizers (see above), we have a number of common encoder
 # As with sizers (see above), we have a number of common encoder

+ 5 - 2
python/google/protobuf/internal/text_format_test.py

@@ -828,6 +828,10 @@ class Proto2Tests(TextFormatBase):
             '    }\n'
             '    }\n'
             '  }\n'
             '  }\n'
             '  [unknown_extension]: 5\n'
             '  [unknown_extension]: 5\n'
+            '  [unknown_extension_with_number_field] {\n'
+            '    1: "some_field"\n'
+            '    2: -0.451\n'
+            '  }\n'
             '}\n')
             '}\n')
     text_format.Parse(text, message, allow_unknown_extension=True)
     text_format.Parse(text, message, allow_unknown_extension=True)
     golden = 'message_set {\n}\n'
     golden = 'message_set {\n}\n'
@@ -894,7 +898,6 @@ class Proto2Tests(TextFormatBase):
     message = unittest_mset_pb2.TestMessageSetContainer()
     message = unittest_mset_pb2.TestMessageSetContainer()
     malformed = ('message_set {\n'
     malformed = ('message_set {\n'
                  '  unknown_field: true\n'
                  '  unknown_field: true\n'
-                 '  \n'  # Missing '>' here.
                  '}\n')
                  '}\n')
     six.assertRaisesRegex(self,
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           text_format.ParseError,
@@ -906,7 +909,7 @@ class Proto2Tests(TextFormatBase):
                           message,
                           message,
                           allow_unknown_extension=True)
                           allow_unknown_extension=True)
 
 
-    # Parse known extension correcty.
+    # Parse known extension correctly.
     message = unittest_mset_pb2.TestMessageSetContainer()
     message = unittest_mset_pb2.TestMessageSetContainer()
     text = ('message_set {\n'
     text = ('message_set {\n'
             '  [protobuf_unittest.TestMessageSetExtension1] {\n'
             '  [protobuf_unittest.TestMessageSetExtension1] {\n'

+ 266 - 264
python/google/protobuf/pyext/descriptor_containers.cc

@@ -957,55 +957,55 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->field_count();
   return GetDescriptor(self)->field_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindFieldByName(name);
   return GetDescriptor(self)->FindFieldByName(name);
 }
 }
 
 
-static ItemDescriptor GetByCamelcaseName(PyContainer* self,
+static const void* GetByCamelcaseName(PyContainer* self,
                                          const string& name) {
                                          const string& name) {
   return GetDescriptor(self)->FindFieldByCamelcaseName(name);
   return GetDescriptor(self)->FindFieldByCamelcaseName(name);
 }
 }
 
 
-static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+static const void* GetByNumber(PyContainer* self, int number) {
   return GetDescriptor(self)->FindFieldByNumber(number);
   return GetDescriptor(self)->FindFieldByNumber(number);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->field(index);
   return GetDescriptor(self)->field(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static const string& GetItemCamelcaseName(ItemDescriptor item) {
-  return item->camelcase_name();
+static const string& GetItemCamelcaseName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->camelcase_name();
 }
 }
 
 
-static int GetItemNumber(ItemDescriptor item) {
-  return item->number();
+static int GetItemNumber(const void* item) {
+  return static_cast<ItemDescriptor>(item)->number();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageFields",
   "MessageFields",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)GetByCamelcaseName,
-  (GetByNumberMethod)GetByNumber,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
-  (GetItemNumberMethod)GetItemNumber,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  GetByCamelcaseName,
+  GetByNumber,
+  NewObjectFromItem,
+  GetItemName,
+  GetItemCamelcaseName,
+  GetItemNumber,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace fields
 }  // namespace fields
@@ -1035,38 +1035,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->nested_type_count();
   return GetDescriptor(self)->nested_type_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindNestedTypeByName(name);
   return GetDescriptor(self)->FindNestedTypeByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->nested_type(index);
   return GetDescriptor(self)->nested_type(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageNestedTypes",
   "MessageNestedTypes",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace nested_types
 }  // namespace nested_types
@@ -1087,38 +1087,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->enum_type_count();
   return GetDescriptor(self)->enum_type_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindEnumTypeByName(name);
   return GetDescriptor(self)->FindEnumTypeByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->enum_type(index);
   return GetDescriptor(self)->enum_type(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageNestedEnums",
   "MessageNestedEnums",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace enums
 }  // namespace enums
@@ -1150,11 +1150,11 @@ static int Count(PyContainer* self) {
   return count;
   return count;
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindEnumValueByName(name);
   return GetDescriptor(self)->FindEnumValueByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   // This is not optimal, but the number of enums *types* in a given message
   // This is not optimal, but the number of enums *types* in a given message
   // is small.  This function is only used when iterating over the mapping.
   // is small.  This function is only used when iterating over the mapping.
   const EnumDescriptor* enum_type = NULL;
   const EnumDescriptor* enum_type = NULL;
@@ -1173,26 +1173,27 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) {
   return enum_type->value(index);
   return enum_type->value(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumValueDescriptor_FromDescriptor(
+      static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageEnumValues",
   "MessageEnumValues",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)NULL,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  NULL,
 };
 };
 
 
 }  // namespace enumvalues
 }  // namespace enumvalues
@@ -1209,38 +1210,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->extension_count();
   return GetDescriptor(self)->extension_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindExtensionByName(name);
   return GetDescriptor(self)->FindExtensionByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->extension(index);
   return GetDescriptor(self)->extension(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageExtensions",
   "MessageExtensions",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace extensions
 }  // namespace extensions
@@ -1261,38 +1262,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->oneof_decl_count();
   return GetDescriptor(self)->oneof_decl_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindOneofByName(name);
   return GetDescriptor(self)->FindOneofByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->oneof_decl(index);
   return GetDescriptor(self)->oneof_decl(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyOneofDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyOneofDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "MessageOneofs",
   "MessageOneofs",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace oneofs
 }  // namespace oneofs
@@ -1323,46 +1324,47 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->value_count();
   return GetDescriptor(self)->value_count();
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->value(index);
   return GetDescriptor(self)->value(index);
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindValueByName(name);
   return GetDescriptor(self)->FindValueByName(name);
 }
 }
 
 
-static ItemDescriptor GetByNumber(PyContainer* self, int number) {
+static const void* GetByNumber(PyContainer* self, int number) {
   return GetDescriptor(self)->FindValueByNumber(number);
   return GetDescriptor(self)->FindValueByNumber(number);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumValueDescriptor_FromDescriptor(
+      static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemNumber(ItemDescriptor item) {
-  return item->number();
+static int GetItemNumber(const void* item) {
+  return static_cast<ItemDescriptor>(item)->number();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "EnumValues",
   "EnumValues",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)GetByNumber,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)GetItemNumber,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  GetByNumber,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  GetItemNumber,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace enumvalues
 }  // namespace enumvalues
@@ -1397,30 +1399,30 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->field_count();
   return GetDescriptor(self)->field_count();
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->field(index);
   return GetDescriptor(self)->field(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index_in_oneof();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index_in_oneof();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "OneofFields",
   "OneofFields",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)NULL,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)NULL,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  NULL,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  NULL,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace fields
 }  // namespace fields
@@ -1447,38 +1449,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->method_count();
   return GetDescriptor(self)->method_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindMethodByName(name);
   return GetDescriptor(self)->FindMethodByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->method(index);
   return GetDescriptor(self)->method(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMethodDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMethodDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "ServiceMethods",
   "ServiceMethods",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace methods
 }  // namespace methods
@@ -1509,38 +1511,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->message_type_count();
   return GetDescriptor(self)->message_type_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindMessageTypeByName(name);
   return GetDescriptor(self)->FindMessageTypeByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->message_type(index);
   return GetDescriptor(self)->message_type(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyMessageDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FileMessages",
   "FileMessages",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace messages
 }  // namespace messages
@@ -1557,38 +1559,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->enum_type_count();
   return GetDescriptor(self)->enum_type_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindEnumTypeByName(name);
   return GetDescriptor(self)->FindEnumTypeByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->enum_type(index);
   return GetDescriptor(self)->enum_type(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyEnumDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FileEnums",
   "FileEnums",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace enums
 }  // namespace enums
@@ -1605,38 +1607,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->extension_count();
   return GetDescriptor(self)->extension_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindExtensionByName(name);
   return GetDescriptor(self)->FindExtensionByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->extension(index);
   return GetDescriptor(self)->extension(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFieldDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FileExtensions",
   "FileExtensions",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace extensions
 }  // namespace extensions
@@ -1653,38 +1655,38 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->service_count();
   return GetDescriptor(self)->service_count();
 }
 }
 
 
-static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+static const void* GetByName(PyContainer* self, const string& name) {
   return GetDescriptor(self)->FindServiceByName(name);
   return GetDescriptor(self)->FindServiceByName(name);
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->service(index);
   return GetDescriptor(self)->service(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyServiceDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyServiceDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
-static const string& GetItemName(ItemDescriptor item) {
-  return item->name();
+static const string& GetItemName(const void* item) {
+  return static_cast<ItemDescriptor>(item)->name();
 }
 }
 
 
-static int GetItemIndex(ItemDescriptor item) {
-  return item->index();
+static int GetItemIndex(const void* item) {
+  return static_cast<ItemDescriptor>(item)->index();
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FileServices",
   "FileServices",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)GetByName,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)GetItemName,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)GetItemIndex,
+  Count,
+  GetByIndex,
+  GetByName,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  GetItemName,
+  NULL,
+  NULL,
+  GetItemIndex,
 };
 };
 
 
 }  // namespace services
 }  // namespace services
@@ -1701,26 +1703,26 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->dependency_count();
   return GetDescriptor(self)->dependency_count();
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->dependency(index);
   return GetDescriptor(self)->dependency(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FileDependencies",
   "FileDependencies",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)NULL,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)NULL,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)NULL,
+  Count,
+  GetByIndex,
+  NULL,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
 };
 };
 
 
 }  // namespace dependencies
 }  // namespace dependencies
@@ -1737,26 +1739,26 @@ static int Count(PyContainer* self) {
   return GetDescriptor(self)->public_dependency_count();
   return GetDescriptor(self)->public_dependency_count();
 }
 }
 
 
-static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+static const void* GetByIndex(PyContainer* self, int index) {
   return GetDescriptor(self)->public_dependency(index);
   return GetDescriptor(self)->public_dependency(index);
 }
 }
 
 
-static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_FromDescriptor(item);
+static PyObject* NewObjectFromItem(const void* item) {
+  return PyFileDescriptor_FromDescriptor(static_cast<ItemDescriptor>(item));
 }
 }
 
 
 static DescriptorContainerDef ContainerDef = {
 static DescriptorContainerDef ContainerDef = {
   "FilePublicDependencies",
   "FilePublicDependencies",
-  (CountMethod)Count,
-  (GetByIndexMethod)GetByIndex,
-  (GetByNameMethod)NULL,
-  (GetByCamelcaseNameMethod)NULL,
-  (GetByNumberMethod)NULL,
-  (NewObjectFromItemMethod)NewObjectFromItem,
-  (GetItemNameMethod)NULL,
-  (GetItemCamelcaseNameMethod)NULL,
-  (GetItemNumberMethod)NULL,
-  (GetItemIndexMethod)NULL,
+  Count,
+  GetByIndex,
+  NULL,
+  NULL,
+  NULL,
+  NewObjectFromItem,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
 };
 };
 
 
 }  // namespace public_dependencies
 }  // namespace public_dependencies

+ 43 - 47
python/google/protobuf/pyext/message.cc

@@ -605,18 +605,16 @@ void OutOfRangeError(PyObject* arg) {
 
 
 template<class RangeType, class ValueType>
 template<class RangeType, class ValueType>
 bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
 bool VerifyIntegerCastAndRange(PyObject* arg, ValueType value) {
-  if
-    GOOGLE_PREDICT_FALSE(value == -1 && PyErr_Occurred()) {
-      if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
-        // Replace it with the same ValueError as pure python protos instead of
-        // the default one.
-        PyErr_Clear();
-        OutOfRangeError(arg);
-      }  // Otherwise propagate existing error.
-      return false;
+  if (GOOGLE_PREDICT_FALSE(value == -1 && PyErr_Occurred())) {
+    if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
+      // Replace it with the same ValueError as pure python protos instead of
+      // the default one.
+      PyErr_Clear();
+      OutOfRangeError(arg);
+    }  // Otherwise propagate existing error.
+    return false;
     }
     }
-  if
-    GOOGLE_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value)) {
+    if (GOOGLE_PREDICT_FALSE(!IsValidNumericCast<RangeType>(value))) {
       OutOfRangeError(arg);
       OutOfRangeError(arg);
       return false;
       return false;
     }
     }
@@ -628,26 +626,22 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
   // The fast path.
   // The fast path.
 #if PY_MAJOR_VERSION < 3
 #if PY_MAJOR_VERSION < 3
   // For the typical case, offer a fast path.
   // For the typical case, offer a fast path.
-  if
-    GOOGLE_PREDICT_TRUE(PyInt_Check(arg)) {
-      long int_result = PyInt_AsLong(arg);
-      if
-        GOOGLE_PREDICT_TRUE(IsValidNumericCast<T>(int_result)) {
-          *value = static_cast<T>(int_result);
-          return true;
-        }
-      else {
-        OutOfRangeError(arg);
-        return false;
-      }
+  if (GOOGLE_PREDICT_TRUE(PyInt_Check(arg))) {
+    long int_result = PyInt_AsLong(arg);
+    if (GOOGLE_PREDICT_TRUE(IsValidNumericCast<T>(int_result))) {
+      *value = static_cast<T>(int_result);
+      return true;
+    } else {
+      OutOfRangeError(arg);
+      return false;
+    }
     }
     }
 #endif
 #endif
   // This effectively defines an integer as "an object that can be cast as
   // This effectively defines an integer as "an object that can be cast as
   // an integer and can be used as an ordinal number".
   // an integer and can be used as an ordinal number".
   // This definition includes everything that implements numbers.Integral
   // This definition includes everything that implements numbers.Integral
   // and shouldn't cast the net too wide.
   // and shouldn't cast the net too wide.
-  if
-    GOOGLE_PREDICT_FALSE(!PyIndex_Check(arg)) {
+    if (GOOGLE_PREDICT_FALSE(!PyIndex_Check(arg))) {
       FormatTypeError(arg, "int, long");
       FormatTypeError(arg, "int, long");
       return false;
       return false;
     }
     }
@@ -664,10 +658,9 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
       // Unlike PyLong_AsLongLong, PyLong_AsUnsignedLongLong is very
       // Unlike PyLong_AsLongLong, PyLong_AsUnsignedLongLong is very
       // picky about the exact type.
       // picky about the exact type.
       PyObject* casted = PyNumber_Long(arg);
       PyObject* casted = PyNumber_Long(arg);
-      if
-        GOOGLE_PREDICT_FALSE(casted == NULL) {
-          // Propagate existing error.
-          return false;
+      if (GOOGLE_PREDICT_FALSE(casted == NULL)) {
+        // Propagate existing error.
+        return false;
         }
         }
       ulong_result = PyLong_AsUnsignedLongLong(casted);
       ulong_result = PyLong_AsUnsignedLongLong(casted);
       Py_DECREF(casted);
       Py_DECREF(casted);
@@ -690,10 +683,9 @@ bool CheckAndGetInteger(PyObject* arg, T* value) {
       // Valid subclasses of numbers.Integral should have a __long__() method
       // Valid subclasses of numbers.Integral should have a __long__() method
       // so fall back to that.
       // so fall back to that.
       PyObject* casted = PyNumber_Long(arg);
       PyObject* casted = PyNumber_Long(arg);
-      if
-        GOOGLE_PREDICT_FALSE(casted == NULL) {
-          // Propagate existing error.
-          return false;
+      if (GOOGLE_PREDICT_FALSE(casted == NULL)) {
+        // Propagate existing error.
+        return false;
         }
         }
       long_result = PyLong_AsLongLong(casted);
       long_result = PyLong_AsLongLong(casted);
       Py_DECREF(casted);
       Py_DECREF(casted);
@@ -717,10 +709,9 @@ template bool CheckAndGetInteger<uint64>(PyObject*, uint64*);
 
 
 bool CheckAndGetDouble(PyObject* arg, double* value) {
 bool CheckAndGetDouble(PyObject* arg, double* value) {
   *value = PyFloat_AsDouble(arg);
   *value = PyFloat_AsDouble(arg);
-  if
-    GOOGLE_PREDICT_FALSE(*value == -1 && PyErr_Occurred()) {
-      FormatTypeError(arg, "int, long, float");
-      return false;
+  if (GOOGLE_PREDICT_FALSE(*value == -1 && PyErr_Occurred())) {
+    FormatTypeError(arg, "int, long, float");
+    return false;
     }
     }
   return true;
   return true;
 }
 }
@@ -1187,7 +1178,7 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
       continue;
       continue;
     }
     }
     if (descriptor->is_map()) {
     if (descriptor->is_map()) {
-      ScopedPyObjectPtr map(GetAttr(self, name));
+      ScopedPyObjectPtr map(GetAttr(reinterpret_cast<PyObject*>(self), name));
       const FieldDescriptor* value_descriptor =
       const FieldDescriptor* value_descriptor =
           descriptor->message_type()->FindFieldByName("value");
           descriptor->message_type()->FindFieldByName("value");
       if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -1215,7 +1206,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
         }
         }
       }
       }
     } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
-      ScopedPyObjectPtr container(GetAttr(self, name));
+      ScopedPyObjectPtr container(
+          GetAttr(reinterpret_cast<PyObject*>(self), name));
       if (container == NULL) {
       if (container == NULL) {
         return -1;
         return -1;
       }
       }
@@ -1282,7 +1274,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
         }
         }
       }
       }
     } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      ScopedPyObjectPtr message(GetAttr(self, name));
+      ScopedPyObjectPtr message(
+          GetAttr(reinterpret_cast<PyObject*>(self), name));
       if (message == NULL) {
       if (message == NULL) {
         return -1;
         return -1;
       }
       }
@@ -1307,8 +1300,8 @@ int InitAttributes(CMessage* self, PyObject* args, PyObject* kwargs) {
           return -1;
           return -1;
         }
         }
       }
       }
-      if (SetAttr(self, name, (new_val.get() == NULL) ? value : new_val.get()) <
-          0) {
+      if (SetAttr(reinterpret_cast<PyObject*>(self), name,
+                  (new_val.get() == NULL) ? value : new_val.get()) < 0) {
         return -1;
         return -1;
       }
       }
     }
     }
@@ -2211,7 +2204,8 @@ static PyObject* ListFields(CMessage* self) {
         return NULL;
         return NULL;
       }
       }
 
 
-      PyObject* field_value = GetAttr(self, py_field_name.get());
+      PyObject* field_value =
+          GetAttr(reinterpret_cast<PyObject*>(self), py_field_name.get());
       if (field_value == NULL) {
       if (field_value == NULL) {
         PyErr_SetObject(PyExc_ValueError, py_field_name.get());
         PyErr_SetObject(PyExc_ValueError, py_field_name.get());
         return NULL;
         return NULL;
@@ -2707,7 +2701,8 @@ static bool SetCompositeField(
   return PyDict_SetItem(self->composite_fields, name, value) == 0;
   return PyDict_SetItem(self->composite_fields, name, value) == 0;
 }
 }
 
 
-PyObject* GetAttr(CMessage* self, PyObject* name) {
+PyObject* GetAttr(PyObject* pself, PyObject* name) {
+  CMessage* self = reinterpret_cast<CMessage*>(pself);
   PyObject* value = self->composite_fields ?
   PyObject* value = self->composite_fields ?
       PyDict_GetItem(self->composite_fields, name) : NULL;
       PyDict_GetItem(self->composite_fields, name) : NULL;
   if (value != NULL) {
   if (value != NULL) {
@@ -2785,7 +2780,8 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
   return InternalGetScalar(self->message, field_descriptor);
   return InternalGetScalar(self->message, field_descriptor);
 }
 }
 
 
-int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
+int SetAttr(PyObject* pself, PyObject* name, PyObject* value) {
+  CMessage* self = reinterpret_cast<CMessage*>(pself);
   if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) {
   if (self->composite_fields && PyDict_Contains(self->composite_fields, name)) {
     PyErr_SetString(PyExc_TypeError, "Can't set composite field");
     PyErr_SetString(PyExc_TypeError, "Can't set composite field");
     return -1;
     return -1;
@@ -2837,8 +2833,8 @@ PyTypeObject CMessage_Type = {
   PyObject_HashNotImplemented,         //  tp_hash
   PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_call
   (reprfunc)cmessage::ToStr,           //  tp_str
   (reprfunc)cmessage::ToStr,           //  tp_str
-  (getattrofunc)cmessage::GetAttr,     //  tp_getattro
-  (setattrofunc)cmessage::SetAttr,     //  tp_setattro
+  cmessage::GetAttr,                   //  tp_getattro
+  cmessage::SetAttr,                   //  tp_setattro
   0,                                   //  tp_as_buffer
   0,                                   //  tp_as_buffer
   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  //  tp_flags
   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  //  tp_flags
   "A ProtocolMessage",                 //  tp_doc
   "A ProtocolMessage",                 //  tp_doc

+ 6 - 6
python/google/protobuf/pyext/message.h

@@ -240,15 +240,15 @@ PyObject* MergeFrom(CMessage* self, PyObject* arg);
 // has been registered with the same field number on this class.
 // has been registered with the same field number on this class.
 PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle);
 PyObject* RegisterExtension(PyObject* cls, PyObject* extension_handle);
 
 
-// Retrieves an attribute named 'name' from CMessage 'self'. Returns
-// the attribute value on success, or NULL on failure.
+// Retrieves an attribute named 'name' from 'self', which is interpreted as a
+// CMessage. Returns the attribute value on success, or null on failure.
 //
 //
 // Returns a new reference.
 // Returns a new reference.
-PyObject* GetAttr(CMessage* self, PyObject* name);
+PyObject* GetAttr(PyObject* self, PyObject* name);
 
 
-// Set the value of the attribute named 'name', for CMessage 'self',
-// to the value 'value'. Returns -1 on failure.
-int SetAttr(CMessage* self, PyObject* name, PyObject* value);
+// Set the value of the attribute named 'name', for 'self', which is interpreted
+// as a CMessage, to the value 'value'. Returns -1 on failure.
+int SetAttr(PyObject* self, PyObject* name, PyObject* value);
 
 
 PyObject* FindInitializationErrors(CMessage* self);
 PyObject* FindInitializationErrors(CMessage* self);
 
 

+ 1 - 1
python/google/protobuf/text_format.py

@@ -938,7 +938,7 @@ def _SkipField(tokenizer):
       tokenizer.ConsumeIdentifier()
       tokenizer.ConsumeIdentifier()
     tokenizer.Consume(']')
     tokenizer.Consume(']')
   else:
   else:
-    tokenizer.ConsumeIdentifier()
+    tokenizer.ConsumeIdentifierOrNumber()
 
 
   _SkipFieldContents(tokenizer)
   _SkipFieldContents(tokenizer)
 
 

+ 2 - 0
src/Makefile.am

@@ -119,6 +119,7 @@ nobase_include_HEADERS =                                         \
   google/protobuf/generated_message_table_driven.h               \
   google/protobuf/generated_message_table_driven.h               \
   google/protobuf/generated_message_util.h                       \
   google/protobuf/generated_message_util.h                       \
   google/protobuf/has_bits.h                                     \
   google/protobuf/has_bits.h                                     \
+  google/protobuf/implicit_weak_message.h                        \
   google/protobuf/map_entry.h                                    \
   google/protobuf/map_entry.h                                    \
   google/protobuf/map_entry_lite.h                               \
   google/protobuf/map_entry_lite.h                               \
   google/protobuf/map_field.h                                    \
   google/protobuf/map_field.h                                    \
@@ -223,6 +224,7 @@ libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/generated_message_util.cc                    \
   google/protobuf/generated_message_util.cc                    \
   google/protobuf/generated_message_table_driven_lite.h        \
   google/protobuf/generated_message_table_driven_lite.h        \
   google/protobuf/generated_message_table_driven_lite.cc       \
   google/protobuf/generated_message_table_driven_lite.cc       \
+  google/protobuf/implicit_weak_message.cc                     \
   google/protobuf/message_lite.cc                              \
   google/protobuf/message_lite.cc                              \
   google/protobuf/repeated_field.cc                            \
   google/protobuf/repeated_field.cc                            \
   google/protobuf/wire_format_lite.cc                          \
   google/protobuf/wire_format_lite.cc                          \

+ 7 - 7
src/google/protobuf/any.pb.cc

@@ -196,13 +196,6 @@ const Any& Any::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Any* Any::New(::google::protobuf::Arena* arena) const {
-  Any* n = new Any;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void Any::Clear() {
 void Any::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Any)
@@ -436,5 +429,12 @@ void Any::InternalSwap(Any* other) {
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Any* Arena::Create< ::google::protobuf::Any >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::Any >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 11 - 2
src/google/protobuf/any.pb.h

@@ -58,6 +58,11 @@ LIBPROTOBUF_EXPORT extern AnyDefaultTypeInternal _Any_default_instance_;
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Any* Arena::Create< ::google::protobuf::Any>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -115,9 +120,13 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_in
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Any* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Any* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Any>(NULL);
+  }
 
 
-  Any* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Any* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Any>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Any& from);
   void CopyFrom(const Any& from);

+ 13 - 8
src/google/protobuf/any.proto

@@ -120,17 +120,18 @@ option objc_class_prefix = "GPB";
 //     }
 //     }
 //
 //
 message Any {
 message Any {
-  // A URL/resource name whose content describes the type of the
-  // serialized protocol buffer message.
+  // A URL/resource name that uniquely identifies the type of the serialized
+  // protocol buffer message. The last segment of the URL's path must represent
+  // the fully qualified name of the type (as in
+  // `path/google.protobuf.Duration`). The name should be in a canonical form
+  // (e.g., leading "." is not accepted).
   //
   //
-  // For URLs which use the scheme `http`, `https`, or no scheme, the
-  // following restrictions and interpretations apply:
+  // In practice, teams usually precompile into the binary all types that they
+  // expect it to use in the context of Any. However, for URLs which use the
+  // scheme `http`, `https`, or no scheme, one can optionally set up a type
+  // server that maps type URLs to message definitions as follows:
   //
   //
   // * If no scheme is provided, `https` is assumed.
   // * If no scheme is provided, `https` is assumed.
-  // * The last segment of the URL's path must represent the fully
-  //   qualified name of the type (as in `path/google.protobuf.Duration`).
-  //   The name should be in a canonical form (e.g., leading "." is
-  //   not accepted).
   // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
   // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
   //   value in binary format, or produce an error.
   //   value in binary format, or produce an error.
   // * Applications are allowed to cache lookup results based on the
   // * Applications are allowed to cache lookup results based on the
@@ -139,6 +140,10 @@ message Any {
   //   on changes to types. (Use versioned type names to manage
   //   on changes to types. (Use versioned type names to manage
   //   breaking changes.)
   //   breaking changes.)
   //
   //
+  // Note: this functionality is not currently available in the official
+  // protobuf release, and it is not used for type URLs beginning with
+  // type.googleapis.com.
+  //
   // Schemes other than `http`, `https` (or the empty scheme) might be
   // Schemes other than `http`, `https` (or the empty scheme) might be
   // used with implementation specific semantics.
   // used with implementation specific semantics.
   //
   //

+ 40 - 36
src/google/protobuf/api.pb.cc

@@ -311,13 +311,6 @@ const Api& Api::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Api* Api::New(::google::protobuf::Arena* arena) const {
-  Api* n = new Api;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void Api::Clear() {
 void Api::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Api)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Api)
@@ -368,7 +361,8 @@ bool Api::MergePartialFromCodedStream(
       case 2: {
       case 2: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_methods()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_methods()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -379,7 +373,8 @@ bool Api::MergePartialFromCodedStream(
       case 3: {
       case 3: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(26u /* 26 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(26u /* 26 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_options()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_options()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -418,7 +413,8 @@ bool Api::MergePartialFromCodedStream(
       case 6: {
       case 6: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(50u /* 50 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(50u /* 50 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_mixins()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_mixins()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -480,14 +476,18 @@ void Api::SerializeWithCachedSizes(
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->methods_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->methods_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      2, this->methods(static_cast<int>(i)), output);
+      2,
+      this->methods(static_cast<int>(i)),
+      output);
   }
   }
 
 
   // repeated .google.protobuf.Option options = 3;
   // repeated .google.protobuf.Option options = 3;
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, this->options(static_cast<int>(i)), output);
+      3,
+      this->options(static_cast<int>(i)),
+      output);
   }
   }
 
 
   // string version = 4;
   // string version = 4;
@@ -503,14 +503,16 @@ void Api::SerializeWithCachedSizes(
   // .google.protobuf.SourceContext source_context = 5;
   // .google.protobuf.SourceContext source_context = 5;
   if (this->has_source_context()) {
   if (this->has_source_context()) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      5, *this->source_context_, output);
+      5, *source_context_, output);
   }
   }
 
 
   // repeated .google.protobuf.Mixin mixins = 6;
   // repeated .google.protobuf.Mixin mixins = 6;
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->mixins_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->mixins_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6, this->mixins(static_cast<int>(i)), output);
+      6,
+      this->mixins(static_cast<int>(i)),
+      output);
   }
   }
 
 
   // .google.protobuf.Syntax syntax = 7;
   // .google.protobuf.Syntax syntax = 7;
@@ -575,7 +577,7 @@ void Api::SerializeWithCachedSizes(
   if (this->has_source_context()) {
   if (this->has_source_context()) {
     target = ::google::protobuf::internal::WireFormatLite::
     target = ::google::protobuf::internal::WireFormatLite::
       InternalWriteMessageToArray(
       InternalWriteMessageToArray(
-        5, *this->source_context_, deterministic, target);
+        5, *source_context_, deterministic, target);
   }
   }
 
 
   // repeated .google.protobuf.Mixin mixins = 6;
   // repeated .google.protobuf.Mixin mixins = 6;
@@ -660,7 +662,7 @@ size_t Api::ByteSizeLong() const {
   if (this->has_source_context()) {
   if (this->has_source_context()) {
     total_size += 1 +
     total_size += 1 +
       ::google::protobuf::internal::WireFormatLite::MessageSize(
       ::google::protobuf::internal::WireFormatLite::MessageSize(
-        *this->source_context_);
+        *source_context_);
   }
   }
 
 
   // .google.protobuf.Syntax syntax = 7;
   // .google.protobuf.Syntax syntax = 7;
@@ -741,9 +743,9 @@ void Api::Swap(Api* other) {
 }
 }
 void Api::InternalSwap(Api* other) {
 void Api::InternalSwap(Api* other) {
   using std::swap;
   using std::swap;
-  methods_.InternalSwap(&other->methods_);
-  options_.InternalSwap(&other->options_);
-  mixins_.InternalSwap(&other->mixins_);
+  CastToBase(&methods_)->InternalSwap(CastToBase(&other->methods_));
+  CastToBase(&options_)->InternalSwap(CastToBase(&other->options_));
+  CastToBase(&mixins_)->InternalSwap(CastToBase(&other->mixins_));
   name_.Swap(&other->name_);
   name_.Swap(&other->name_);
   version_.Swap(&other->version_);
   version_.Swap(&other->version_);
   swap(source_context_, other->source_context_);
   swap(source_context_, other->source_context_);
@@ -843,13 +845,6 @@ const Method& Method::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Method* Method::New(::google::protobuf::Arena* arena) const {
-  Method* n = new Method;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void Method::Clear() {
 void Method::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Method)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Method)
@@ -957,7 +952,8 @@ bool Method::MergePartialFromCodedStream(
       case 6: {
       case 6: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(50u /* 50 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(50u /* 50 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_options()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_options()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -1049,7 +1045,9 @@ void Method::SerializeWithCachedSizes(
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->options_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      6, this->options(static_cast<int>(i)), output);
+      6,
+      this->options(static_cast<int>(i)),
+      output);
   }
   }
 
 
   // .google.protobuf.Syntax syntax = 7;
   // .google.protobuf.Syntax syntax = 7;
@@ -1271,7 +1269,7 @@ void Method::Swap(Method* other) {
 }
 }
 void Method::InternalSwap(Method* other) {
 void Method::InternalSwap(Method* other) {
   using std::swap;
   using std::swap;
-  options_.InternalSwap(&other->options_);
+  CastToBase(&options_)->InternalSwap(CastToBase(&other->options_));
   name_.Swap(&other->name_);
   name_.Swap(&other->name_);
   request_type_url_.Swap(&other->request_type_url_);
   request_type_url_.Swap(&other->request_type_url_);
   response_type_url_.Swap(&other->response_type_url_);
   response_type_url_.Swap(&other->response_type_url_);
@@ -1352,13 +1350,6 @@ const Mixin& Mixin::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Mixin* Mixin::New(::google::protobuf::Arena* arena) const {
-  Mixin* n = new Mixin;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void Mixin::Clear() {
 void Mixin::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin)
@@ -1604,5 +1595,18 @@ void Mixin::InternalSwap(Mixin* other) {
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Api* Arena::Create< ::google::protobuf::Api >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::Api >(arena);
+}
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Method* Arena::Create< ::google::protobuf::Method >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::Method >(arena);
+}
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Mixin* Arena::Create< ::google::protobuf::Mixin >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::Mixin >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 67 - 47
src/google/protobuf/api.pb.h

@@ -71,6 +71,13 @@ LIBPROTOBUF_EXPORT extern MixinDefaultTypeInternal _Mixin_default_instance_;
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Api* Arena::Create< ::google::protobuf::Api>(Arena*);
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Method* Arena::Create< ::google::protobuf::Method>(Arena*);
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Mixin* Arena::Create< ::google::protobuf::Mixin>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -118,9 +125,13 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Api* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Api* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Api>(NULL);
+  }
 
 
-  Api* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Api* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Api>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Api& from);
   void CopyFrom(const Api& from);
@@ -160,11 +171,11 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   int methods_size() const;
   int methods_size() const;
   void clear_methods();
   void clear_methods();
   static const int kMethodsFieldNumber = 2;
   static const int kMethodsFieldNumber = 2;
-  const ::google::protobuf::Method& methods(int index) const;
   ::google::protobuf::Method* mutable_methods(int index);
   ::google::protobuf::Method* mutable_methods(int index);
-  ::google::protobuf::Method* add_methods();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
       mutable_methods();
       mutable_methods();
+  const ::google::protobuf::Method& methods(int index) const;
+  ::google::protobuf::Method* add_methods();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
       methods() const;
       methods() const;
 
 
@@ -172,11 +183,11 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   int options_size() const;
   int options_size() const;
   void clear_options();
   void clear_options();
   static const int kOptionsFieldNumber = 3;
   static const int kOptionsFieldNumber = 3;
-  const ::google::protobuf::Option& options(int index) const;
   ::google::protobuf::Option* mutable_options(int index);
   ::google::protobuf::Option* mutable_options(int index);
-  ::google::protobuf::Option* add_options();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
       mutable_options();
       mutable_options();
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* add_options();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
       options() const;
       options() const;
 
 
@@ -184,11 +195,11 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_in
   int mixins_size() const;
   int mixins_size() const;
   void clear_mixins();
   void clear_mixins();
   static const int kMixinsFieldNumber = 6;
   static const int kMixinsFieldNumber = 6;
-  const ::google::protobuf::Mixin& mixins(int index) const;
   ::google::protobuf::Mixin* mutable_mixins(int index);
   ::google::protobuf::Mixin* mutable_mixins(int index);
-  ::google::protobuf::Mixin* add_mixins();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
       mutable_mixins();
       mutable_mixins();
+  const ::google::protobuf::Mixin& mixins(int index) const;
+  ::google::protobuf::Mixin* add_mixins();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
       mixins() const;
       mixins() const;
 
 
@@ -296,9 +307,13 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Method* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Method* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Method>(NULL);
+  }
 
 
-  Method* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Method* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Method>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Method& from);
   void CopyFrom(const Method& from);
@@ -338,11 +353,11 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc
   int options_size() const;
   int options_size() const;
   void clear_options();
   void clear_options();
   static const int kOptionsFieldNumber = 6;
   static const int kOptionsFieldNumber = 6;
-  const ::google::protobuf::Option& options(int index) const;
   ::google::protobuf::Option* mutable_options(int index);
   ::google::protobuf::Option* mutable_options(int index);
-  ::google::protobuf::Option* add_options();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
       mutable_options();
       mutable_options();
+  const ::google::protobuf::Option& options(int index) const;
+  ::google::protobuf::Option* add_options();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
       options() const;
       options() const;
 
 
@@ -467,9 +482,13 @@ class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Mixin* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Mixin* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Mixin>(NULL);
+  }
 
 
-  Mixin* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Mixin* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Mixin>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Mixin& from);
   void CopyFrom(const Mixin& from);
@@ -614,23 +633,23 @@ inline int Api::methods_size() const {
 inline void Api::clear_methods() {
 inline void Api::clear_methods() {
   methods_.Clear();
   methods_.Clear();
 }
 }
-inline const ::google::protobuf::Method& Api::methods(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
-  return methods_.Get(index);
-}
 inline ::google::protobuf::Method* Api::mutable_methods(int index) {
 inline ::google::protobuf::Method* Api::mutable_methods(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods)
   return methods_.Mutable(index);
   return methods_.Mutable(index);
 }
 }
-inline ::google::protobuf::Method* Api::add_methods() {
-  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
-  return methods_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >*
 Api::mutable_methods() {
 Api::mutable_methods() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods)
   return &methods_;
   return &methods_;
 }
 }
+inline const ::google::protobuf::Method& Api::methods(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.methods)
+  return methods_.Get(index);
+}
+inline ::google::protobuf::Method* Api::add_methods() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.methods)
+  return methods_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >&
 Api::methods() const {
 Api::methods() const {
   // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
   // @@protoc_insertion_point(field_list:google.protobuf.Api.methods)
@@ -641,23 +660,23 @@ Api::methods() const {
 inline int Api::options_size() const {
 inline int Api::options_size() const {
   return options_.size();
   return options_.size();
 }
 }
-inline const ::google::protobuf::Option& Api::options(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
-  return options_.Get(index);
-}
 inline ::google::protobuf::Option* Api::mutable_options(int index) {
 inline ::google::protobuf::Option* Api::mutable_options(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options)
   return options_.Mutable(index);
   return options_.Mutable(index);
 }
 }
-inline ::google::protobuf::Option* Api::add_options() {
-  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
-  return options_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
 Api::mutable_options() {
 Api::mutable_options() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options)
   return &options_;
   return &options_;
 }
 }
+inline const ::google::protobuf::Option& Api::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Api::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.options)
+  return options_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
 Api::options() const {
 Api::options() const {
   // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
   // @@protoc_insertion_point(field_list:google.protobuf.Api.options)
@@ -737,7 +756,8 @@ inline ::google::protobuf::SourceContext* Api::release_source_context() {
 inline ::google::protobuf::SourceContext* Api::mutable_source_context() {
 inline ::google::protobuf::SourceContext* Api::mutable_source_context() {
   
   
   if (source_context_ == NULL) {
   if (source_context_ == NULL) {
-    source_context_ = new ::google::protobuf::SourceContext;
+    source_context_ = ::google::protobuf::Arena::Create< ::google::protobuf::SourceContext >(
+        GetArenaNoVirtual());
   }
   }
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context)
   return source_context_;
   return source_context_;
@@ -768,23 +788,23 @@ inline int Api::mixins_size() const {
 inline void Api::clear_mixins() {
 inline void Api::clear_mixins() {
   mixins_.Clear();
   mixins_.Clear();
 }
 }
-inline const ::google::protobuf::Mixin& Api::mixins(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
-  return mixins_.Get(index);
-}
 inline ::google::protobuf::Mixin* Api::mutable_mixins(int index) {
 inline ::google::protobuf::Mixin* Api::mutable_mixins(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
   // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins)
   return mixins_.Mutable(index);
   return mixins_.Mutable(index);
 }
 }
-inline ::google::protobuf::Mixin* Api::add_mixins() {
-  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
-  return mixins_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >*
 Api::mutable_mixins() {
 Api::mutable_mixins() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins)
   return &mixins_;
   return &mixins_;
 }
 }
+inline const ::google::protobuf::Mixin& Api::mixins(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins)
+  return mixins_.Get(index);
+}
+inline ::google::protobuf::Mixin* Api::add_mixins() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins)
+  return mixins_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >&
 Api::mixins() const {
 Api::mixins() const {
   // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
   // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins)
@@ -1000,23 +1020,23 @@ inline void Method::set_response_streaming(bool value) {
 inline int Method::options_size() const {
 inline int Method::options_size() const {
   return options_.size();
   return options_.size();
 }
 }
-inline const ::google::protobuf::Option& Method::options(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
-  return options_.Get(index);
-}
 inline ::google::protobuf::Option* Method::mutable_options(int index) {
 inline ::google::protobuf::Option* Method::mutable_options(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
   // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options)
   return options_.Mutable(index);
   return options_.Mutable(index);
 }
 }
-inline ::google::protobuf::Option* Method::add_options() {
-  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
-  return options_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >*
 Method::mutable_options() {
 Method::mutable_options() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options)
   return &options_;
   return &options_;
 }
 }
+inline const ::google::protobuf::Option& Method::options(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.Method.options)
+  return options_.Get(index);
+}
+inline ::google::protobuf::Option* Method::add_options() {
+  // @@protoc_insertion_point(field_add:google.protobuf.Method.options)
+  return options_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >&
 Method::options() const {
 Method::options() const {
   // @@protoc_insertion_point(field_list:google.protobuf.Method.options)
   // @@protoc_insertion_point(field_list:google.protobuf.Method.options)

+ 203 - 168
src/google/protobuf/arena.cc

@@ -73,14 +73,15 @@ void ArenaImpl::Init() {
     // Thread which calls Init() owns the first block. This allows the
     // Thread which calls Init() owns the first block. This allows the
     // single-threaded case to allocate on the first block without having to
     // single-threaded case to allocate on the first block without having to
     // perform atomic operations.
     // perform atomic operations.
-    InitBlock(initial_block_, &thread_cache(), options_.initial_block_size);
-    ThreadInfo* info = NewThreadInfo(initial_block_);
-    info->next = NULL;
+    new (initial_block_) Block(options_.initial_block_size, NULL);
+    SerialArena* serial =
+        SerialArena::New(initial_block_, &thread_cache(), this);
+    serial->set_next(NULL);
     google::protobuf::internal::NoBarrier_Store(&threads_,
     google::protobuf::internal::NoBarrier_Store(&threads_,
-                                  reinterpret_cast<google::protobuf::internal::AtomicWord>(info));
+                                  reinterpret_cast<google::protobuf::internal::AtomicWord>(serial));
     google::protobuf::internal::NoBarrier_Store(&space_allocated_,
     google::protobuf::internal::NoBarrier_Store(&space_allocated_,
                                   options_.initial_block_size);
                                   options_.initial_block_size);
-    CacheBlock(initial_block_);
+    CacheSerialArena(serial);
   } else {
   } else {
     google::protobuf::internal::NoBarrier_Store(&space_allocated_, 0);
     google::protobuf::internal::NoBarrier_Store(&space_allocated_, 0);
   }
   }
@@ -103,145 +104,134 @@ uint64 ArenaImpl::Reset() {
   return space_allocated;
   return space_allocated;
 }
 }
 
 
-ArenaImpl::Block* ArenaImpl::NewBlock(void* me, Block* my_last_block,
-                                      size_t min_bytes) {
+ArenaImpl::Block* ArenaImpl::NewBlock(Block* last_block, size_t min_bytes) {
   size_t size;
   size_t size;
-  if (my_last_block != NULL) {
+  if (last_block) {
     // Double the current block size, up to a limit.
     // Double the current block size, up to a limit.
-    size = std::min(2 * my_last_block->size, options_.max_block_size);
+    size = std::min(2 * last_block->size(), options_.max_block_size);
   } else {
   } else {
     size = options_.start_block_size;
     size = options_.start_block_size;
   }
   }
-  // Verify that min_bytes + kHeaderSize won't overflow.
-  GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kHeaderSize);
-  size = std::max(size, kHeaderSize + min_bytes);
+  // Verify that min_bytes + kBlockHeaderSize won't overflow.
+  GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kBlockHeaderSize);
+  size = std::max(size, kBlockHeaderSize + min_bytes);
 
 
-  Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
-  InitBlock(b, me, size);
+  void* mem = options_.block_alloc(size);
+  Block* b = new (mem) Block(size, last_block);
   google::protobuf::internal::NoBarrier_AtomicIncrement(&space_allocated_, size);
   google::protobuf::internal::NoBarrier_AtomicIncrement(&space_allocated_, size);
   return b;
   return b;
 }
 }
 
 
-void ArenaImpl::InitBlock(Block* b, void *me, size_t size) {
-  b->pos = kHeaderSize;
-  b->size = size;
-  b->owner = me;
-  b->next = NULL;
-#ifdef ADDRESS_SANITIZER
-  // Poison the rest of the block for ASAN. It was unpoisoned by the underlying
-  // malloc but it's not yet usable until we return it as part of an allocation.
-  ASAN_POISON_MEMORY_REGION(
-      reinterpret_cast<char*>(b) + b->pos, b->size - b->pos);
-#endif  // ADDRESS_SANITIZER
-}
+ArenaImpl::Block::Block(size_t size, Block* next)
+    : next_(next), pos_(kBlockHeaderSize), size_(size) {}
 
 
-ArenaImpl::CleanupChunk* ArenaImpl::ExpandCleanupList(CleanupChunk* cleanup,
-                                                      Block* b) {
-  size_t size = cleanup ? cleanup->size * 2 : kMinCleanupListElements;
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+void ArenaImpl::SerialArena::AddCleanupFallback(void* elem,
+                                                void (*cleanup)(void*)) {
+  size_t size = cleanup_ ? cleanup_->size * 2 : kMinCleanupListElements;
   size = std::min(size, kMaxCleanupListElements);
   size = std::min(size, kMaxCleanupListElements);
   size_t bytes = internal::AlignUpTo8(CleanupChunk::SizeOf(size));
   size_t bytes = internal::AlignUpTo8(CleanupChunk::SizeOf(size));
-  if (b->avail() < bytes) {
-    b = GetBlock(bytes);
-  }
-  CleanupChunk* list =
-      reinterpret_cast<CleanupChunk*>(AllocFromBlock(b, bytes));
-  list->next = b->thread_info->cleanup;
+  CleanupChunk* list = reinterpret_cast<CleanupChunk*>(AllocateAligned(bytes));
+  list->next = cleanup_;
   list->size = size;
   list->size = size;
-  list->len = 0;
-  b->thread_info->cleanup = list;
-  return list;
+
+  cleanup_ = list;
+  cleanup_ptr_ = &list->nodes[0];
+  cleanup_limit_ = &list->nodes[size];
+
+  AddCleanup(elem, cleanup);
 }
 }
 
 
-inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
-void ArenaImpl::AddCleanupInBlock(
-    Block* b, void* elem, void (*func)(void*)) {
-  CleanupChunk* cleanup = b->thread_info->cleanup;
-  if (cleanup == NULL || cleanup->len == cleanup->size) {
-    cleanup = ExpandCleanupList(cleanup, b);
+void* ArenaImpl::AllocateAligned(size_t n) {
+  SerialArena* arena;
+  if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+    return arena->AllocateAligned(n);
+  } else {
+    return AllocateAlignedFallback(n);
   }
   }
+}
 
 
-  CleanupNode* node = &cleanup->nodes[cleanup->len++];
-
-  node->elem = elem;
-  node->cleanup = func;
+void* ArenaImpl::AllocateAlignedAndAddCleanup(size_t n,
+                                              void (*cleanup)(void*)) {
+  SerialArena* arena;
+  if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+    return arena->AllocateAlignedAndAddCleanup(n, cleanup);
+  } else {
+    return AllocateAlignedAndAddCleanupFallback(n, cleanup);
+  }
 }
 }
 
 
 void ArenaImpl::AddCleanup(void* elem, void (*cleanup)(void*)) {
 void ArenaImpl::AddCleanup(void* elem, void (*cleanup)(void*)) {
-  return AddCleanupInBlock(GetBlock(0), elem, cleanup);
+  SerialArena* arena;
+  if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+    arena->AddCleanup(elem, cleanup);
+  } else {
+    return AddCleanupFallback(elem, cleanup);
+  }
 }
 }
 
 
-void* ArenaImpl::AllocateAligned(size_t n) {
-  GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
-
-  return AllocFromBlock(GetBlock(n), n);
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+void* ArenaImpl::AllocateAlignedFallback(size_t n) {
+  return GetSerialArena()->AllocateAligned(n);
 }
 }
 
 
-void* ArenaImpl::AllocateAlignedAndAddCleanup(size_t n,
-                                              void (*cleanup)(void*)) {
-  GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+void* ArenaImpl::AllocateAlignedAndAddCleanupFallback(size_t n,
+                                                      void (*cleanup)(void*)) {
+  return GetSerialArena()->AllocateAlignedAndAddCleanup(n, cleanup);
+}
 
 
-  Block* b = GetBlock(n);
-  void* mem = AllocFromBlock(b, n);
-  AddCleanupInBlock(b, mem, cleanup);
-  return mem;
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+void ArenaImpl::AddCleanupFallback(void* elem, void (*cleanup)(void*)) {
+  GetSerialArena()->AddCleanup(elem, cleanup);
 }
 }
 
 
 inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
 inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
-ArenaImpl::Block* ArenaImpl::GetBlock(size_t n) {
-  Block* my_block = NULL;
-
+bool ArenaImpl::GetSerialArenaFast(ArenaImpl::SerialArena** arena) {
   // If this thread already owns a block in this arena then try to use that.
   // If this thread already owns a block in this arena then try to use that.
   // This fast path optimizes the case where multiple threads allocate from the
   // This fast path optimizes the case where multiple threads allocate from the
   // same arena.
   // same arena.
   ThreadCache* tc = &thread_cache();
   ThreadCache* tc = &thread_cache();
-  if (tc->last_lifecycle_id_seen == lifecycle_id_) {
-    my_block = tc->last_block_used_;
-    if (my_block->avail() >= n) {
-      return my_block;
-    }
+  if (GOOGLE_PREDICT_TRUE(tc->last_lifecycle_id_seen == lifecycle_id_)) {
+    *arena = tc->last_serial_arena;
+    return true;
   }
   }
 
 
-  // Check whether we own the last accessed block on this arena.
-  // This fast path optimizes the case where a single thread uses multiple
-  // arenas.
-  Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
-  if (b != NULL && b->owner == tc) {
-    my_block = b;
-    if (my_block->avail() >= n) {
-      return my_block;
-    }
+  // Check whether we own the last accessed SerialArena on this arena.  This
+  // fast path optimizes the case where a single thread uses multiple arenas.
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&hint_));
+  if (GOOGLE_PREDICT_TRUE(serial != NULL && serial->owner() == tc)) {
+    *arena = serial;
+    return true;
   }
   }
-  return GetBlockSlow(tc, my_block, n);
+
+  return false;
 }
 }
 
 
-inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
-void* ArenaImpl::AllocFromBlock(Block* b, size_t n) {
-  GOOGLE_DCHECK_EQ(internal::AlignUpTo8(b->pos), b->pos);  // Must be already aligned.
-  GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
-  GOOGLE_DCHECK_GE(b->avail(), n);
-  size_t p = b->pos;
-  b->pos = p + n;
+ArenaImpl::SerialArena* ArenaImpl::GetSerialArena() {
+  SerialArena* arena;
+  if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) {
+    return arena;
+  } else {
+    return GetSerialArenaFallback(&thread_cache());
+  }
+}
+
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+void* ArenaImpl::SerialArena::AllocateAlignedFallback(size_t n) {
+  // Sync back to current's pos.
+  head_->set_pos(head_->size() - (limit_ - ptr_));
+
+  head_ = arena_->NewBlock(head_, n);
+  ptr_ = head_->Pointer(head_->pos());
+  limit_ = head_->Pointer(head_->size());
+
 #ifdef ADDRESS_SANITIZER
 #ifdef ADDRESS_SANITIZER
-  ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n);
+  ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
 #endif  // ADDRESS_SANITIZER
 #endif  // ADDRESS_SANITIZER
-  return reinterpret_cast<char*>(b) + p;
-}
 
 
-ArenaImpl::Block* ArenaImpl::GetBlockSlow(void* me, Block* my_full_block,
-                                          size_t n) {
-  ThreadInfo* info =
-      my_full_block ? my_full_block->thread_info : GetThreadInfo(me, n);
-  GOOGLE_DCHECK(info != NULL);
-  Block* b = info->head;
-  if (b->avail() < n) {
-    Block* new_b = NewBlock(me, b, n);
-    new_b->thread_info = info;
-    new_b->next = b;
-    info->head = new_b;
-    b = new_b;
-  }
-  CacheBlock(b);
-  return b;
+  return AllocateAligned(n);
 }
 }
 
 
 uint64 ArenaImpl::SpaceAllocated() const {
 uint64 ArenaImpl::SpaceAllocated() const {
@@ -249,18 +239,24 @@ uint64 ArenaImpl::SpaceAllocated() const {
 }
 }
 
 
 uint64 ArenaImpl::SpaceUsed() const {
 uint64 ArenaImpl::SpaceUsed() const {
-  ThreadInfo* info =
-      reinterpret_cast<ThreadInfo*>(google::protobuf::internal::Acquire_Load(&threads_));
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&threads_));
   uint64 space_used = 0;
   uint64 space_used = 0;
-
-  for ( ; info; info = info->next) {
-    // Remove the overhead of the ThreadInfo itself.
-    space_used -= sizeof(ThreadInfo);
-    for (Block* b = info->head; b; b = b->next) {
-      space_used += (b->pos - kHeaderSize);
-    }
+  for ( ; serial; serial = serial->next()) {
+    space_used += serial->SpaceUsed();
   }
   }
+  return space_used;
+}
 
 
+uint64 ArenaImpl::SerialArena::SpaceUsed() const {
+  // Get current block's size from ptr_ (since we can't trust head_->pos().
+  uint64 space_used = ptr_ - head_->Pointer(kBlockHeaderSize);
+  // Get subsequent block size from b->pos().
+  for (Block* b = head_->next(); b; b = b->next()) {
+    space_used += (b->pos() - kBlockHeaderSize);
+  }
+  // Remove the overhead of the SerialArena itself.
+  space_used -= kSerialArenaSize;
   return space_used;
   return space_used;
 }
 }
 
 
@@ -268,30 +264,45 @@ uint64 ArenaImpl::FreeBlocks() {
   uint64 space_allocated = 0;
   uint64 space_allocated = 0;
   // By omitting an Acquire barrier we ensure that any user code that doesn't
   // By omitting an Acquire barrier we ensure that any user code that doesn't
   // properly synchronize Reset() or the destructor will throw a TSAN warning.
   // properly synchronize Reset() or the destructor will throw a TSAN warning.
-  ThreadInfo* info =
-      reinterpret_cast<ThreadInfo*>(google::protobuf::internal::NoBarrier_Load(&threads_));
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(google::protobuf::internal::NoBarrier_Load(&threads_));
+
+  while (serial) {
+    // This is inside a block we are freeing, so we need to read it now.
+    SerialArena* next = serial->next();
+    space_allocated += ArenaImpl::SerialArena::Free(serial, initial_block_,
+                                                    options_.block_dealloc);
+    // serial is dead now.
+    serial = next;
+  }
 
 
-  while (info) {
+  return space_allocated;
+}
+
+uint64 ArenaImpl::SerialArena::Free(ArenaImpl::SerialArena* serial,
+                                    Block* initial_block,
+                                    void (*block_dealloc)(void*, size_t)) {
+  uint64 space_allocated = 0;
+
+  // We have to be careful in this function, since we will be freeing the Block
+  // that contains this SerialArena.  Be careful about accessing |serial|.
+
+  for (Block* b = serial->head_; b; ) {
     // This is inside the block we are freeing, so we need to read it now.
     // This is inside the block we are freeing, so we need to read it now.
-    ThreadInfo* next_info = info->next;
-    for (Block* b = info->head; b; ) {
-      // This is inside the block we are freeing, so we need to read it now.
-      Block* next_block = b->next;
-      space_allocated += (b->size);
+    Block* next_block = b->next();
+    space_allocated += (b->size());
 
 
 #ifdef ADDRESS_SANITIZER
 #ifdef ADDRESS_SANITIZER
-      // This memory was provided by the underlying allocator as unpoisoned, so
-      // return it in an unpoisoned state.
-      ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b), b->size);
+    // This memory was provided by the underlying allocator as unpoisoned, so
+    // return it in an unpoisoned state.
+    ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size());
 #endif  // ADDRESS_SANITIZER
 #endif  // ADDRESS_SANITIZER
 
 
-      if (b != initial_block_) {
-        options_.block_dealloc(b, b->size);
-      }
-
-      b = next_block;
+    if (b != initial_block) {
+      block_dealloc(b, b->size());
     }
     }
-    info = next_info;
+
+    b = next_block;
   }
   }
 
 
   return space_allocated;
   return space_allocated;
@@ -300,63 +311,87 @@ uint64 ArenaImpl::FreeBlocks() {
 void ArenaImpl::CleanupList() {
 void ArenaImpl::CleanupList() {
   // By omitting an Acquire barrier we ensure that any user code that doesn't
   // By omitting an Acquire barrier we ensure that any user code that doesn't
   // properly synchronize Reset() or the destructor will throw a TSAN warning.
   // properly synchronize Reset() or the destructor will throw a TSAN warning.
-  ThreadInfo* info =
-      reinterpret_cast<ThreadInfo*>(google::protobuf::internal::NoBarrier_Load(&threads_));
-
-  for ( ; info; info = info->next) {
-    CleanupChunk* list = info->cleanup;
-    while (list) {
-      size_t n = list->len;
-      CleanupNode* node = &list->nodes[list->len - 1];
-      for (size_t i = 0; i < n; i++, node--) {
-        node->cleanup(node->elem);
-      }
-      list = list->next;
-    }
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(google::protobuf::internal::NoBarrier_Load(&threads_));
+
+  for ( ; serial; serial = serial->next()) {
+    serial->CleanupList();
   }
   }
 }
 }
 
 
-ArenaImpl::ThreadInfo* ArenaImpl::NewThreadInfo(Block* b) {
-  GOOGLE_DCHECK(FindThreadInfo(b->owner) == NULL);
-  ThreadInfo* info =
-      reinterpret_cast<ThreadInfo*>(AllocFromBlock(b, sizeof(ThreadInfo)));
-  b->thread_info = info;
-  info->owner = b->owner;
-  info->head = b;
-  info->cleanup = NULL;
-  return info;
+void ArenaImpl::SerialArena::CleanupList() {
+  if (cleanup_ != NULL) {
+    CleanupListFallback();
+  }
 }
 }
 
 
-ArenaImpl::ThreadInfo* ArenaImpl::FindThreadInfo(void* me) {
-  ThreadInfo* info =
-      reinterpret_cast<ThreadInfo*>(google::protobuf::internal::Acquire_Load(&threads_));
-  for ( ; info; info = info->next) {
-    if (info->owner == me) {
-      return info;
+void ArenaImpl::SerialArena::CleanupListFallback() {
+  // Cleanup newest chunk: ptrs give us length.
+  size_t n = cleanup_ptr_ - &cleanup_->nodes[0];
+  CleanupNode* node = cleanup_ptr_;
+  for (size_t i = 0; i < n; i++) {
+    --node;
+    node->cleanup(node->elem);
+  }
+
+  // Cleanup older chunks, which are known to be full.
+  CleanupChunk* list = cleanup_->next;
+  while (list) {
+    size_t n = list->size;
+    CleanupNode* node = &list->nodes[list->size];
+    for (size_t i = 0; i < n; i++) {
+      --node;
+      node->cleanup(node->elem);
     }
     }
+    list = list->next;
   }
   }
+}
 
 
-  return NULL;
+ArenaImpl::SerialArena* ArenaImpl::SerialArena::New(Block* b, void* owner,
+                                                    ArenaImpl* arena) {
+  GOOGLE_DCHECK_EQ(b->pos(), kBlockHeaderSize);  // Should be a fresh block
+  GOOGLE_DCHECK_LE(kBlockHeaderSize + kSerialArenaSize, b->size());
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(b->Pointer(kBlockHeaderSize));
+  b->set_pos(kBlockHeaderSize + kSerialArenaSize);
+  serial->arena_ = arena;
+  serial->owner_ = owner;
+  serial->head_ = b;
+  serial->ptr_ = b->Pointer(b->pos());
+  serial->limit_ = b->Pointer(b->size());
+  serial->cleanup_ = NULL;
+  serial->cleanup_ptr_ = NULL;
+  serial->cleanup_limit_ = NULL;
+  return serial;
 }
 }
 
 
-ArenaImpl::ThreadInfo* ArenaImpl::GetThreadInfo(void* me, size_t n) {
-  ThreadInfo* info = FindThreadInfo(me);
+GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE
+ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) {
+  // Look for this SerialArena in our linked list.
+  SerialArena* serial =
+      reinterpret_cast<SerialArena*>(google::protobuf::internal::Acquire_Load(&threads_));
+  for ( ; serial; serial = serial->next()) {
+    if (serial->owner() == me) {
+      break;
+    }
+  }
 
 
-  if (!info) {
-    // This thread doesn't have any ThreadInfo, which also means it doesn't have
-    // any blocks yet.  So we'll allocate its first block now.
-    Block* b = NewBlock(me, NULL, sizeof(ThreadInfo) + n);
-    info = NewThreadInfo(b);
+  if (!serial) {
+    // This thread doesn't have any SerialArena, which also means it doesn't
+    // have any blocks yet.  So we'll allocate its first block now.
+    Block* b = NewBlock(NULL, kSerialArenaSize);
+    serial = SerialArena::New(b, me, this);
 
 
     google::protobuf::internal::AtomicWord head;
     google::protobuf::internal::AtomicWord head;
     do {
     do {
       head = google::protobuf::internal::NoBarrier_Load(&threads_);
       head = google::protobuf::internal::NoBarrier_Load(&threads_);
-      info->next = reinterpret_cast<ThreadInfo*>(head);
+      serial->set_next(reinterpret_cast<SerialArena*>(head));
     } while (google::protobuf::internal::Release_CompareAndSwap(
     } while (google::protobuf::internal::Release_CompareAndSwap(
-                 &threads_, head, reinterpret_cast<google::protobuf::internal::AtomicWord>(info)) != head);
+                 &threads_, head, reinterpret_cast<google::protobuf::internal::AtomicWord>(serial)) != head);
   }
   }
 
 
-  return info;
+  CacheSerialArena(serial);
+  return serial;
 }
 }
 
 
 }  // namespace internal
 }  // namespace internal

+ 65 - 18
src/google/protobuf/arena.h

@@ -56,6 +56,21 @@ using type_info = ::type_info;
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+struct ArenaOptions;
+}  // namespace protobuf
+
+namespace quality_webanswers {
+
+void TempPrivateWorkAround(::google::protobuf::ArenaOptions* arena_options);
+
+}  // namespace quality_webanswers
+
+namespace protobuf {
+namespace arena_metrics {
+
+void EnableArenaMetrics(::google::protobuf::ArenaOptions* options);
+
+}  // namespace arena_metrics
 
 
 class Arena;       // defined below
 class Arena;       // defined below
 class Message;     // message.h
 class Message;     // message.h
@@ -117,6 +132,20 @@ struct ArenaOptions {
   // from the arena. By default, it contains a ptr to a wrapper function that
   // from the arena. By default, it contains a ptr to a wrapper function that
   // calls free.
   // calls free.
   void (*block_dealloc)(void*, size_t);
   void (*block_dealloc)(void*, size_t);
+
+  ArenaOptions()
+      : start_block_size(kDefaultStartBlockSize),
+        max_block_size(kDefaultMaxBlockSize),
+        initial_block(NULL),
+        initial_block_size(0),
+        block_alloc(&::operator new),
+        block_dealloc(&internal::arena_free),
+        on_arena_init(NULL),
+        on_arena_reset(NULL),
+        on_arena_destruction(NULL),
+        on_arena_allocation(NULL) {}
+
+ private:
   // Hooks for adding external functionality such as user-specific metrics
   // Hooks for adding external functionality such as user-specific metrics
   // collection, specific debugging abilities, etc.
   // collection, specific debugging abilities, etc.
   // Init hook may return a pointer to a cookie to be stored in the arena.
   // Init hook may return a pointer to a cookie to be stored in the arena.
@@ -138,23 +167,15 @@ struct ArenaOptions {
   void (*on_arena_allocation)(const std::type_info* allocated_type,
   void (*on_arena_allocation)(const std::type_info* allocated_type,
       uint64 alloc_size, void* cookie);
       uint64 alloc_size, void* cookie);
 
 
-  ArenaOptions()
-      : start_block_size(kDefaultStartBlockSize),
-        max_block_size(kDefaultMaxBlockSize),
-        initial_block(NULL),
-        initial_block_size(0),
-        block_alloc(&::operator new),
-        block_dealloc(&internal::arena_free),
-        on_arena_init(NULL),
-        on_arena_reset(NULL),
-        on_arena_destruction(NULL),
-        on_arena_allocation(NULL) {}
-
- private:
   // Constants define default starting block size and max block size for
   // Constants define default starting block size and max block size for
   // arena allocator behavior -- see descriptions above.
   // arena allocator behavior -- see descriptions above.
   static const size_t kDefaultStartBlockSize = 256;
   static const size_t kDefaultStartBlockSize = 256;
   static const size_t kDefaultMaxBlockSize   = 8192;
   static const size_t kDefaultMaxBlockSize   = 8192;
+
+  friend void ::google::protobuf::arena_metrics::EnableArenaMetrics(ArenaOptions*);
+  friend void quality_webanswers::TempPrivateWorkAround(ArenaOptions*);
+  friend class Arena;
+  friend class ArenaOptionsTestFriend;
 };
 };
 
 
 // Support for non-RTTI environments. (The metrics hooks API uses type
 // Support for non-RTTI environments. (The metrics hooks API uses type
@@ -229,14 +250,15 @@ class LIBPROTOBUF_EXPORT Arena {
   // WARNING: if you allocate multiple objects, it is difficult to guarantee
   // WARNING: if you allocate multiple objects, it is difficult to guarantee
   // that a series of allocations will fit in the initial block, especially if
   // that a series of allocations will fit in the initial block, especially if
   // Arena changes its alignment guarantees in the future!
   // Arena changes its alignment guarantees in the future!
-  static const size_t kBlockOverhead = internal::ArenaImpl::kHeaderSize;
+  static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
+                                       internal::ArenaImpl::kSerialArenaSize;
 
 
   // Default constructor with sensible default options, tuned for average
   // Default constructor with sensible default options, tuned for average
   // use-cases.
   // use-cases.
   Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
   Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
 
 
   ~Arena() {
   ~Arena() {
-    if (on_arena_reset_ != NULL || on_arena_destruction_ != NULL) {
+    if (hooks_cookie_) {
       CallDestructorHooks();
       CallDestructorHooks();
     }
     }
   }
   }
@@ -277,6 +299,7 @@ class LIBPROTOBUF_EXPORT Arena {
     }
     }
   }
   }
 #endif
 #endif
+
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   static T* CreateMessage(::google::protobuf::Arena* arena) {
   static T* CreateMessage(::google::protobuf::Arena* arena) {
 #if LANG_CXX11
 #if LANG_CXX11
@@ -355,6 +378,7 @@ class LIBPROTOBUF_EXPORT Arena {
     }
     }
   }
   }
 #endif
 #endif
+
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   static T* Create(::google::protobuf::Arena* arena) {
   static T* Create(::google::protobuf::Arena* arena) {
     if (arena == NULL) {
     if (arena == NULL) {
@@ -522,6 +546,7 @@ class LIBPROTOBUF_EXPORT Arena {
   //
   //
   // Combines SpaceAllocated and SpaceUsed. Returns a pair of
   // Combines SpaceAllocated and SpaceUsed. Returns a pair of
   // <space_allocated, space_used>.
   // <space_allocated, space_used>.
+  PROTOBUF_RUNTIME_DEPRECATED("Please use SpaceAllocated() and SpaceUsed()")
   std::pair<uint64, uint64> SpaceAllocatedAndUsed() const {
   std::pair<uint64, uint64> SpaceAllocatedAndUsed() const {
     return std::make_pair(SpaceAllocated(), SpaceUsed());
     return std::make_pair(SpaceAllocated(), SpaceUsed());
   }
   }
@@ -637,6 +662,29 @@ class LIBPROTOBUF_EXPORT Arena {
   struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
   struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
 
 
  private:
  private:
+  template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessageInternal(::google::protobuf::Arena* arena) {
+#if LANG_CXX11
+    static_assert(
+        InternalHelper<T>::is_arena_constructable::value,
+        "CreateMessage can only construct types that are ArenaConstructable");
+#endif
+    if (arena == NULL) {
+      return new T;
+    } else {
+      return arena->CreateMessageInternal<T>();
+    }
+  }
+
+  template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateInternal(::google::protobuf::Arena* arena) {
+    if (arena == NULL) {
+      return new T();
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value);
+    }
+  }
+
   void CallDestructorHooks();
   void CallDestructorHooks();
   void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
   void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
   inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
   inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
@@ -668,12 +716,12 @@ class LIBPROTOBUF_EXPORT Arena {
   // fields, since they are designed to work in all mode combinations.
   // fields, since they are designed to work in all mode combinations.
   template <typename Msg> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   template <typename Msg> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   static Msg* CreateMaybeMessage(Arena* arena, google::protobuf::internal::true_type) {
   static Msg* CreateMaybeMessage(Arena* arena, google::protobuf::internal::true_type) {
-    return CreateMessage<Msg>(arena);
+    return CreateMessageInternal<Msg>(arena);
   }
   }
 
 
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   static T* CreateMaybeMessage(Arena* arena, google::protobuf::internal::false_type) {
   static T* CreateMaybeMessage(Arena* arena, google::protobuf::internal::false_type) {
-    return Create<T>(arena);
+    return CreateInternal<T>(arena);
   }
   }
 
 
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
@@ -907,7 +955,6 @@ class LIBPROTOBUF_EXPORT Arena {
 
 
   internal::ArenaImpl impl_;
   internal::ArenaImpl impl_;
 
 
-  void* (*on_arena_init_)(Arena* arena);
   void (*on_arena_allocation_)(const std::type_info* allocated_type,
   void (*on_arena_allocation_)(const std::type_info* allocated_type,
                                uint64 alloc_size, void* cookie);
                                uint64 alloc_size, void* cookie);
   void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);
   void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);

+ 117 - 41
src/google/protobuf/arena_impl.h

@@ -40,10 +40,13 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/mutex.h>
-#include <google/protobuf/stubs/type_traits.h>
 
 
 #include <google/protobuf/stubs/port.h>
 #include <google/protobuf/stubs/port.h>
 
 
+#ifdef ADDRESS_SANITIZER
+#include <sanitizer/asan_interface.h>
+#endif  // ADDRESS_SANITIZER
+
 namespace google {
 namespace google {
 
 
 namespace protobuf {
 namespace protobuf {
@@ -112,6 +115,10 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
   void AddCleanup(void* elem, void (*cleanup)(void*));
   void AddCleanup(void* elem, void (*cleanup)(void*));
 
 
  private:
  private:
+  void* AllocateAlignedFallback(size_t n);
+  void* AllocateAlignedAndAddCleanupFallback(size_t n, void (*cleanup)(void*));
+  void AddCleanupFallback(void* elem, void (*cleanup)(void*));
+
   // Node contains the ptr of the object to be cleaned up and the associated
   // Node contains the ptr of the object to be cleaned up and the associated
   // cleanup function ptr.
   // cleanup function ptr.
   struct CleanupNode {
   struct CleanupNode {
@@ -124,34 +131,107 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
     static size_t SizeOf(size_t i) {
     static size_t SizeOf(size_t i) {
       return sizeof(CleanupChunk) + (sizeof(CleanupNode) * (i - 1));
       return sizeof(CleanupChunk) + (sizeof(CleanupNode) * (i - 1));
     }
     }
-    size_t len;            // Number of elements currently present.
     size_t size;           // Total elements in the list.
     size_t size;           // Total elements in the list.
     CleanupChunk* next;    // Next node in the list.
     CleanupChunk* next;    // Next node in the list.
     CleanupNode nodes[1];  // True length is |size|.
     CleanupNode nodes[1];  // True length is |size|.
   };
   };
 
 
-  struct Block;
+  class Block;
+
+  // A thread-unsafe Arena that can only be used within its owning thread.
+  class LIBPROTOBUF_EXPORT SerialArena {
+   public:
+    // The allocate/free methods here are a little strange, since SerialArena is
+    // allocated inside a Block which it also manages.  This is to avoid doing
+    // an extra allocation for the SerialArena itself.
+
+    // Creates a new SerialArena inside Block* and returns it.
+    static SerialArena* New(Block* b, void* owner, ArenaImpl* arena);
+
+    // Destroys this SerialArena, freeing all blocks with the given dealloc
+    // function, except any block equal to |initial_block|.
+    static uint64 Free(SerialArena* serial, Block* initial_block,
+                       void (*block_dealloc)(void*, size_t));
+
+    void CleanupList();
+    uint64 SpaceUsed() const;
+
+    void* AllocateAligned(size_t n) {
+      GOOGLE_DCHECK_EQ(internal::AlignUpTo8(n), n);  // Must be already aligned.
+      GOOGLE_DCHECK_GE(limit_, ptr_);
+      if (GOOGLE_PREDICT_FALSE(static_cast<size_t>(limit_ - ptr_) < n)) {
+        return AllocateAlignedFallback(n);
+      }
+      void* ret = ptr_;
+      ptr_ += n;
+#ifdef ADDRESS_SANITIZER
+      ASAN_UNPOISON_MEMORY_REGION(ret, n);
+#endif  // ADDRESS_SANITIZER
+      return ret;
+    }
+
+    void AddCleanup(void* elem, void (*cleanup)(void*)) {
+      if (GOOGLE_PREDICT_FALSE(cleanup_ptr_ == cleanup_limit_)) {
+        AddCleanupFallback(elem, cleanup);
+        return;
+      }
+      cleanup_ptr_->elem = elem;
+      cleanup_ptr_->cleanup = cleanup;
+      cleanup_ptr_++;
+    }
+
+    void* AllocateAlignedAndAddCleanup(size_t n, void (*cleanup)(void*)) {
+      void* ret = AllocateAligned(n);
+      AddCleanup(ret, cleanup);
+      return ret;
+    }
 
 
-  // Tracks per-thread info.  ThreadInfos are kept in a linked list.
-  struct ThreadInfo {
-    void *owner;             // &ThreadCache of this thread;
-    Block* head;             // Head of linked list of blocks.
-    CleanupChunk* cleanup;   // Head of cleanup list.
-    ThreadInfo* next;        // Next ThreadInfo in this linked list.
+    void* owner() const { return owner_; }
+    SerialArena* next() const { return next_; }
+    void set_next(SerialArena* next) { next_ = next; }
+
+   private:
+    void* AllocateAlignedFallback(size_t n);
+    void AddCleanupFallback(void* elem, void (*cleanup)(void*));
+    void CleanupListFallback();
+
+    ArenaImpl* arena_;        // Containing arena.
+    void* owner_;             // &ThreadCache of this thread;
+    Block* head_;             // Head of linked list of blocks.
+    CleanupChunk* cleanup_;   // Head of cleanup list.
+    SerialArena* next_;       // Next SerialArena in this linked list.
+
+    // Next pointer to allocate from.  Always 8-byte aligned.  Points inside
+    // head_ (and head_->pos will always be non-canonical).  We keep these
+    // here to reduce indirection.
+    char* ptr_;
+    char* limit_;
+
+    // Next CleanupList members to append to.  These point inside cleanup_.
+    CleanupNode* cleanup_ptr_;
+    CleanupNode* cleanup_limit_;
   };
   };
 
 
   // Blocks are variable length malloc-ed objects.  The following structure
   // Blocks are variable length malloc-ed objects.  The following structure
   // describes the common header for all blocks.
   // describes the common header for all blocks.
-  struct Block {
-    void* owner;              // &ThreadCache of thread that owns this block.
-    ThreadInfo* thread_info;  // ThreadInfo of thread that owns this block.
-    Block* next;              // Next block in arena (may have different owner)
-    // ((char*) &block) + pos is next available byte. It is always
-    // aligned at a multiple of 8 bytes.
-    size_t pos;
-    size_t size;  // total size of the block.
-    GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE
-    size_t avail() const { return size - pos; }
+  class LIBPROTOBUF_EXPORT Block {
+   public:
+    Block(size_t size, Block* next);
+
+    char* Pointer(size_t n) {
+      GOOGLE_DCHECK(n <= size_);
+      return reinterpret_cast<char*>(this) + n;
+    }
+
+    Block* next() const { return next_; }
+    size_t pos() const { return pos_; }
+    size_t size() const { return size_; }
+    void set_pos(size_t pos) { pos_ = pos; }
+
+   private:
+    Block* next_;   // Next block for this thread.
+    size_t pos_;
+    size_t size_;
     // data follows
     // data follows
   };
   };
 
 
@@ -160,13 +240,13 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
     // If we are using the ThreadLocalStorage class to store the ThreadCache,
     // If we are using the ThreadLocalStorage class to store the ThreadCache,
     // then the ThreadCache's default constructor has to be responsible for
     // then the ThreadCache's default constructor has to be responsible for
     // initializing it.
     // initializing it.
-    ThreadCache() : last_lifecycle_id_seen(-1), last_block_used_(NULL) {}
+    ThreadCache() : last_lifecycle_id_seen(-1), last_serial_arena(NULL) {}
 #endif
 #endif
 
 
     // The ThreadCache is considered valid as long as this matches the
     // The ThreadCache is considered valid as long as this matches the
     // lifecycle_id of the arena being used.
     // lifecycle_id of the arena being used.
     int64 last_lifecycle_id_seen;
     int64 last_lifecycle_id_seen;
-    Block* last_block_used_;
+    SerialArena* last_serial_arena;
   };
   };
   static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
   static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
@@ -188,38 +268,30 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
   // Free all blocks and return the total space used which is the sums of sizes
   // Free all blocks and return the total space used which is the sums of sizes
   // of the all the allocated blocks.
   // of the all the allocated blocks.
   uint64 FreeBlocks();
   uint64 FreeBlocks();
-
-  void AddCleanupInBlock(Block* b, void* elem, void (*func)(void*));
-  CleanupChunk* ExpandCleanupList(CleanupChunk* cleanup, Block* b);
   // Delete or Destruct all objects owned by the arena.
   // Delete or Destruct all objects owned by the arena.
   void CleanupList();
   void CleanupList();
 
 
-  inline void CacheBlock(Block* block) {
-    thread_cache().last_block_used_ = block;
+  inline void CacheSerialArena(SerialArena* serial) {
+    thread_cache().last_serial_arena = serial;
     thread_cache().last_lifecycle_id_seen = lifecycle_id_;
     thread_cache().last_lifecycle_id_seen = lifecycle_id_;
     // TODO(haberman): evaluate whether we would gain efficiency by getting rid
     // TODO(haberman): evaluate whether we would gain efficiency by getting rid
     // of hint_.  It's the only write we do to ArenaImpl in the allocation path,
     // of hint_.  It's the only write we do to ArenaImpl in the allocation path,
     // which will dirty the cache line.
     // which will dirty the cache line.
-    google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(block));
+    google::protobuf::internal::Release_Store(&hint_, reinterpret_cast<google::protobuf::internal::AtomicWord>(serial));
   }
   }
 
 
-  google::protobuf::internal::AtomicWord threads_;          // Pointer to a linked list of ThreadInfo.
+  google::protobuf::internal::AtomicWord threads_;          // Pointer to a linked list of SerialArena.
   google::protobuf::internal::AtomicWord hint_;             // Fast thread-local block access
   google::protobuf::internal::AtomicWord hint_;             // Fast thread-local block access
   google::protobuf::internal::AtomicWord space_allocated_;  // Sum of sizes of all allocated blocks.
   google::protobuf::internal::AtomicWord space_allocated_;  // Sum of sizes of all allocated blocks.
 
 
   Block *initial_block_;     // If non-NULL, points to the block that came from
   Block *initial_block_;     // If non-NULL, points to the block that came from
                              // user data.
                              // user data.
 
 
-  // Returns a block owned by this thread.
-  Block* GetBlock(size_t n);
-  Block* GetBlockSlow(void* me, Block* my_full_block, size_t n);
-  Block* NewBlock(void* me, Block* my_last_block, size_t min_bytes);
-  void InitBlock(Block* b, void *me, size_t size);
-  static void* AllocFromBlock(Block* b, size_t n);
-  ThreadInfo* NewThreadInfo(Block* b);
-  ThreadInfo* FindThreadInfo(void* me);
-  ThreadInfo* GetThreadInfo(void* me, size_t n);
+  Block* NewBlock(Block* last_block, size_t min_bytes);
 
 
+  SerialArena* GetSerialArena();
+  bool GetSerialArenaFast(SerialArena** arena);
+  SerialArena* GetSerialArenaFallback(void* me);
   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
 
 
   Options options_;
   Options options_;
@@ -227,11 +299,15 @@ class LIBPROTOBUF_EXPORT ArenaImpl {
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
 
 
  public:
  public:
-  // kHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8 to
-  // protect the invariant that pos is always at a multiple of 8.
-  static const size_t kHeaderSize = (sizeof(Block) + 7) & -8;
+  // kBlockHeaderSize is sizeof(Block), aligned up to the nearest multiple of 8
+  // to protect the invariant that pos is always at a multiple of 8.
+  static const size_t kBlockHeaderSize = (sizeof(Block) + 7) & -8;
+  static const size_t kSerialArenaSize = (sizeof(SerialArena) + 7) & -8;
 #if LANG_CXX11
 #if LANG_CXX11
-  static_assert(kHeaderSize % 8 == 0, "kHeaderSize must be a multiple of 8.");
+  static_assert(kBlockHeaderSize % 8 == 0,
+                "kBlockHeaderSize must be a multiple of 8.");
+  static_assert(kSerialArenaSize % 8 == 0,
+                "kSerialArenaSize must be a multiple of 8.");
 #endif
 #endif
 };
 };
 
 

+ 22 - 10
src/google/protobuf/arena_unittest.cc

@@ -67,7 +67,6 @@ using protobuf_unittest::TestOneof2;
 using protobuf_unittest::TestEmptyMessage;
 using protobuf_unittest::TestEmptyMessage;
 
 
 namespace protobuf {
 namespace protobuf {
-namespace {
 
 
 class Notifier {
 class Notifier {
  public:
  public:
@@ -270,7 +269,7 @@ TEST(ArenaTest, InitialBlockTooSmall) {
   // Construct a small (64 byte) initial block of memory to be used by the
   // Construct a small (64 byte) initial block of memory to be used by the
   // arena allocator; then, allocate an object which will not fit in the
   // arena allocator; then, allocate an object which will not fit in the
   // initial block.
   // initial block.
-  std::vector<char> arena_block(72);
+  std::vector<char> arena_block(96);
   ArenaOptions options;
   ArenaOptions options;
   options.initial_block = &arena_block[0];
   options.initial_block = &arena_block[0];
   options.initial_block_size = arena_block.size();
   options.initial_block_size = arena_block.size();
@@ -1299,12 +1298,12 @@ TEST(ArenaTest, SpaceAllocated_and_Used) {
   options.initial_block_size = 0;
   options.initial_block_size = 0;
   Arena arena_3(options);
   Arena arena_3(options);
   EXPECT_EQ(0, arena_3.SpaceUsed());
   EXPECT_EQ(0, arena_3.SpaceUsed());
-  ::google::protobuf::Arena::CreateArray<char>(&arena_3, 182);
+  ::google::protobuf::Arena::CreateArray<char>(&arena_3, 160);
   EXPECT_EQ(256, arena_3.SpaceAllocated());
   EXPECT_EQ(256, arena_3.SpaceAllocated());
-  EXPECT_EQ(Align8(182), arena_3.SpaceUsed());
+  EXPECT_EQ(Align8(160), arena_3.SpaceUsed());
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
   ::google::protobuf::Arena::CreateArray<char>(&arena_3, 70);
   EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
   EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
-  EXPECT_EQ(Align8(182) + Align8(70), arena_3.SpaceUsed());
+  EXPECT_EQ(Align8(160) + Align8(70), arena_3.SpaceUsed());
   EXPECT_EQ(256 + 512, arena_3.Reset());
   EXPECT_EQ(256 + 512, arena_3.Reset());
 }
 }
 
 
@@ -1347,6 +1346,13 @@ TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
   EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
   EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
 }
 }
 
 
+TEST(ArenaTest, AddCleanup) {
+  ::google::protobuf::Arena arena;
+  for (int i = 0; i < 100; i++) {
+    arena.Own(new int);
+  }
+}
+
 TEST(ArenaTest, UnsafeSetAllocatedOnArena) {
 TEST(ArenaTest, UnsafeSetAllocatedOnArena) {
   ::google::protobuf::Arena arena;
   ::google::protobuf::Arena arena;
   TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
   TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
@@ -1405,13 +1411,20 @@ uint32 ArenaHooksTestUtil::num_reset = 0;
 uint32 ArenaHooksTestUtil::num_destruct = 0;
 uint32 ArenaHooksTestUtil::num_destruct = 0;
 const int ArenaHooksTestUtil::kCookieValue;
 const int ArenaHooksTestUtil::kCookieValue;
 
 
+class ArenaOptionsTestFriend {
+ public:
+  static void Set(::google::protobuf::ArenaOptions* options) {
+    options->on_arena_init = ArenaHooksTestUtil::on_init;
+    options->on_arena_allocation = ArenaHooksTestUtil::on_allocation;
+    options->on_arena_reset = ArenaHooksTestUtil::on_reset;
+    options->on_arena_destruction = ArenaHooksTestUtil::on_destruction;
+  }
+};
+
 // Test the hooks are correctly called and that the cookie is passed.
 // Test the hooks are correctly called and that the cookie is passed.
 TEST(ArenaTest, ArenaHooksSanity) {
 TEST(ArenaTest, ArenaHooksSanity) {
   ::google::protobuf::ArenaOptions options;
   ::google::protobuf::ArenaOptions options;
-  options.on_arena_init = ArenaHooksTestUtil::on_init;
-  options.on_arena_allocation = ArenaHooksTestUtil::on_allocation;
-  options.on_arena_reset = ArenaHooksTestUtil::on_reset;
-  options.on_arena_destruction = ArenaHooksTestUtil::on_destruction;
+  ArenaOptionsTestFriend::Set(&options);
 
 
   // Scope for defining the arena
   // Scope for defining the arena
   {
   {
@@ -1433,6 +1446,5 @@ TEST(ArenaTest, ArenaHooksSanity) {
 }
 }
 
 
 
 
-}  // namespace
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google

+ 21 - 0
src/google/protobuf/arenastring.h

@@ -51,6 +51,18 @@ namespace google {
 namespace protobuf {
 namespace protobuf {
 namespace internal {
 namespace internal {
 
 
+template <typename T>
+class TaggedPtr {
+ public:
+  void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
+  T* Get() const { return reinterpret_cast<T*>(ptr_); }
+
+  bool IsNull() { return ptr_ == 0; }
+
+ private:
+  uintptr_t ptr_;
+};
+
 struct LIBPROTOBUF_EXPORT ArenaStringPtr {
 struct LIBPROTOBUF_EXPORT ArenaStringPtr {
   inline void Set(const ::std::string* default_value,
   inline void Set(const ::std::string* default_value,
                   const ::std::string& value, ::google::protobuf::Arena* arena) {
                   const ::std::string& value, ::google::protobuf::Arena* arena) {
@@ -294,6 +306,15 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
     return ptr_ == default_value;
     return ptr_ == default_value;
   }
   }
 
 
+  // Internal accessors!!!!
+  void UnsafeSetTaggedPointer(TaggedPtr< ::std::string> value) {
+    ptr_ = value.Get();
+  }
+  // Generated code only! An optimization, in certain cases the generated
+  // code is certain we can obtain a string with no default checks and
+  // tag tests.
+  ::std::string* UnsafeMutablePointer() { return ptr_; }
+
  private:
  private:
   ::std::string* ptr_;
   ::std::string* ptr_;
 
 

+ 4 - 22
src/google/protobuf/compiler/annotation_test_util.cc

@@ -76,10 +76,9 @@ void AddFile(const string& filename, const string& data) {
                              true));
                              true));
 }
 }
 
 
-bool CaptureMetadata(const string& filename, const string& plugin_specific_args,
-                     const string& meta_file_suffix, CommandLineInterface* cli,
-                     FileDescriptorProto* file,
-                     std::vector<ExpectedOutput>* outputs) {
+bool RunProtoCompiler(const string& filename,
+                      const string& plugin_specific_args,
+                      CommandLineInterface* cli, FileDescriptorProto* file) {
   cli->SetInputsAreProtoPathRelative(true);
   cli->SetInputsAreProtoPathRelative(true);
 
 
   DescriptorCapturingGenerator capturing_generator(file);
   DescriptorCapturingGenerator capturing_generator(file);
@@ -92,24 +91,7 @@ bool CaptureMetadata(const string& filename, const string& plugin_specific_args,
                         plugin_specific_args.c_str(), capture_out.c_str(),
                         plugin_specific_args.c_str(), capture_out.c_str(),
                         filename.c_str()};
                         filename.c_str()};
 
 
-  if (cli->Run(5, argv) != 0) {
-    return false;
-  }
-
-  if (outputs != NULL) {
-    for (std::vector<ExpectedOutput>::iterator i = outputs->begin();
-         i != outputs->end(); ++i) {
-      GOOGLE_CHECK_OK(File::GetContents(TestTempDir() + "/" + i->file_path,
-                                 &i->file_content, true));
-      if (!DecodeMetadata(
-              TestTempDir() + "/" + i->file_path + meta_file_suffix,
-              &i->file_info)) {
-        return false;
-      }
-    }
-  }
-
-  return true;
+  return cli->Run(5, argv) == 0;
 }
 }
 
 
 bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {
 bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {

+ 6 - 11
src/google/protobuf/compiler/annotation_test_util.h

@@ -59,25 +59,20 @@ struct ExpectedOutput {
 // directory.
 // directory.
 void AddFile(const string& filename, const string& data);
 void AddFile(const string& filename, const string& data);
 
 
-// Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
-// code from the previously added file with name `filename`.
+// Runs proto compiler. Captures proto file structrue in FileDescriptorProto.
+// Files will be generated in TestTempDir() folder. Callers of this
+// function must read generated files themselves.
 //
 //
 // filename: source .proto file used to generate code.
 // filename: source .proto file used to generate code.
 // plugin_specific_args: command line arguments specific to current generator.
 // plugin_specific_args: command line arguments specific to current generator.
 //     For Java, this value might be "--java_out=annotate_code:test_temp_dir"
 //     For Java, this value might be "--java_out=annotate_code:test_temp_dir"
-// meta_file_suffix: suffix of meta files that contain annotations. For Java
-//     it is ".pb.meta" because for file Foo.java meta file is Foo.java.pb.meta
 // cli: instance of command line interface to run generator. See Java's
 // cli: instance of command line interface to run generator. See Java's
 //     annotation_unittest.cc for an example of how to initialize it.
 //     annotation_unittest.cc for an example of how to initialize it.
 // file: output parameter, will be set to the descriptor of the proto file
 // file: output parameter, will be set to the descriptor of the proto file
 //     specified in filename.
 //     specified in filename.
-// outputs: output parameter. If not NULL, each ExpectedOutput in the vector
-//     should have its file_path set; CaptureMetadata will fill the rest of
-//     the fields appropriately.
-bool CaptureMetadata(const string& filename, const string& plugin_specific_args,
-                     const string& meta_file_suffix, CommandLineInterface* cli,
-                     FileDescriptorProto* file,
-                     std::vector<ExpectedOutput>* outputs);
+bool RunProtoCompiler(const string& filename,
+                      const string& plugin_specific_args,
+                      CommandLineInterface* cli, FileDescriptorProto* file);
 
 
 bool DecodeMetadata(const string& path, GeneratedCodeInfo* info);
 bool DecodeMetadata(const string& path, GeneratedCodeInfo* info);
 
 

+ 1 - 1
src/google/protobuf/compiler/code_generator.h

@@ -166,7 +166,7 @@ typedef GeneratorContext OutputDirectory;
 //   "foo=bar,baz,qux=corge"
 //   "foo=bar,baz,qux=corge"
 // parses to the pairs:
 // parses to the pairs:
 //   ("foo", "bar"), ("baz", ""), ("qux", "corge")
 //   ("foo", "bar"), ("baz", ""), ("qux", "corge")
-void ParseGeneratorParameter(
+LIBPROTOC_EXPORT void ParseGeneratorParameter(
     const string&, std::vector<std::pair<string, string> >*);
     const string&, std::vector<std::pair<string, string> >*);
 
 
 }  // namespace compiler
 }  // namespace compiler

+ 3 - 3
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -195,7 +195,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "inline $type$ $classname$::$name$() const {\n"
     "inline $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "  if (has_$name$()) {\n"
-    "    return static_cast< $type$ >($oneof_prefix$$name$_);\n"
+    "    return static_cast< $type$ >($field_member$);\n"
     "  }\n"
     "  }\n"
     "  return static_cast< $type$ >($default$);\n"
     "  return static_cast< $type$ >($default$);\n"
     "}\n"
     "}\n"
@@ -209,14 +209,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    clear_$oneof_name$();\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "    set_has_$name$();\n"
     "  }\n"
     "  }\n"
-    "  $oneof_prefix$$name$_ = value;\n"
+    "  $field_member$ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
     "}\n");
 }
 }
 
 
 void EnumOneofFieldGenerator::
 void EnumOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+  printer->Print(variables_, "$field_member$ = $default$;\n");
 }
 }
 
 
 void EnumOneofFieldGenerator::
 void EnumOneofFieldGenerator::

+ 2 - 15
src/google/protobuf/compiler/cpp/cpp_field.cc

@@ -67,12 +67,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
   (*variables)["number"] = SimpleItoa(descriptor->number());
   (*variables)["number"] = SimpleItoa(descriptor->number());
   (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
   (*variables)["classname"] = ClassName(FieldScope(descriptor), false);
   (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
   (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
-
-  // non_null_ptr_to_name is usable only if has_$name$ is true.  It yields a
-  // pointer that will not be NULL.  Subclasses of FieldGenerator may set
-  // (*variables)["non_null_ptr_to_name"] differently.
-  (*variables)["non_null_ptr_to_name"] =
-      StrCat("&this->", FieldName(descriptor), "()");
+  (*variables)["field_member"] = FieldName(descriptor) + "_";
 
 
   (*variables)["tag_size"] = SimpleItoa(
   (*variables)["tag_size"] = SimpleItoa(
     WireFormat::TagSize(descriptor->number(), descriptor->type()));
     WireFormat::TagSize(descriptor->number(), descriptor->type()));
@@ -81,8 +76,6 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
   (*variables)["deprecated_attr"] = descriptor->options().deprecated()
   (*variables)["deprecated_attr"] = descriptor->options().deprecated()
       ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
       ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : "";
 
 
-  (*variables)["cppget"] = "Get";
-
   if (HasFieldPresence(descriptor->file())) {
   if (HasFieldPresence(descriptor->file())) {
     (*variables)["set_hasbit"] =
     (*variables)["set_hasbit"] =
         "set_has_" + FieldName(descriptor) + "();";
         "set_has_" + FieldName(descriptor) + "();";
@@ -93,10 +86,6 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
     (*variables)["clear_hasbit"] = "";
     (*variables)["clear_hasbit"] = "";
   }
   }
 
 
-  // By default, empty string, so that generic code used for both oneofs and
-  // singular fields can be written.
-  (*variables)["oneof_prefix"] = "";
-
   // These variables are placeholders to pick out the beginning and ends of
   // These variables are placeholders to pick out the beginning and ends of
   // identifiers for annotations (when doing so with existing variables would
   // identifiers for annotations (when doing so with existing variables would
   // be ambiguous or impossible). They should never be set to anything but the
   // be ambiguous or impossible). They should never be set to anything but the
@@ -108,10 +97,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
 void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
 void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
                                   std::map<string, string>* variables) {
                                   std::map<string, string>* variables) {
   const string prefix = descriptor->containing_oneof()->name() + "_.";
   const string prefix = descriptor->containing_oneof()->name() + "_.";
-  (*variables)["oneof_prefix"] = prefix;
   (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
   (*variables)["oneof_name"] = descriptor->containing_oneof()->name();
-  (*variables)["non_null_ptr_to_name"] =
-      StrCat(prefix, (*variables)["name"], "_");
+  (*variables)["field_member"] = StrCat(prefix, (*variables)["name"], "_");
 }
 }
 
 
 FieldGenerator::~FieldGenerator() {}
 FieldGenerator::~FieldGenerator() {}

+ 4 - 0
src/google/protobuf/compiler/cpp/cpp_field.h

@@ -184,6 +184,10 @@ class FieldGenerator {
   // message's MergeFromCodedStream() method.
   // message's MergeFromCodedStream() method.
   virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
   virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
 
 
+  // Returns true if this field's "MergeFromCodedStream" code needs the arena
+  // to be defined as a variable.
+  virtual bool MergeFromCodedStreamNeedsArena() const { return false; }
+
   // Generate lines to decode this field from a packed value, which will be
   // Generate lines to decode this field from a packed value, which will be
   // placed inside the message's MergeFromCodedStream() method.
   // placed inside the message's MergeFromCodedStream() method.
   virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer)
   virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer)

+ 81 - 14
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -397,7 +397,7 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
 
 
     // Define default instances
     // Define default instances
     GenerateSourceDefaultInstance(idx, printer);
     GenerateSourceDefaultInstance(idx, printer);
-    if (UsingImplicitWeakFields(file_, options_)) {
+    if (options_.lite_implicit_weak_fields) {
       printer->Print("void $classname$_ReferenceStrong() {}\n", "classname",
       printer->Print("void $classname$_ReferenceStrong() {}\n", "classname",
                      message_generators_[idx]->classname_);
                      message_generators_[idx]->classname_);
     }
     }
@@ -416,6 +416,13 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
     GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer);
     GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer);
   }
   }
 
 
+
+  printer->Print(
+      "namespace google {\nnamespace protobuf {\n");
+  message_generators_[idx]->GenerateSourceInProto2Namespace(printer);
+  printer->Print(
+      "}  // namespace protobuf\n}  // namespace google\n");
+
   printer->Print(
   printer->Print(
       "\n"
       "\n"
       "// @@protoc_insertion_point(global_scope)\n");
       "// @@protoc_insertion_point(global_scope)\n");
@@ -467,7 +474,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     // Define default instances
     // Define default instances
     for (int i = 0; i < message_generators_.size(); i++) {
     for (int i = 0; i < message_generators_.size(); i++) {
       GenerateSourceDefaultInstance(i, printer);
       GenerateSourceDefaultInstance(i, printer);
-      if (UsingImplicitWeakFields(file_, options_)) {
+      if (options_.lite_implicit_weak_fields) {
         printer->Print("void $classname$_ReferenceStrong() {}\n", "classname",
         printer->Print("void $classname$_ReferenceStrong() {}\n", "classname",
                        message_generators_[i]->classname_);
                        message_generators_[i]->classname_);
       }
       }
@@ -525,6 +532,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
       "\n"
       "\n"
       "// @@protoc_insertion_point(namespace_scope)\n");
       "// @@protoc_insertion_point(namespace_scope)\n");
   }
   }
+
+  printer->Print(
+      "namespace google {\nnamespace protobuf {\n");
+  for (int i = 0; i < message_generators_.size(); i++) {
+    message_generators_[i]->GenerateSourceInProto2Namespace(printer);
+  }
+  printer->Print(
+      "}  // namespace protobuf\n}  // namespace google\n");
+
   printer->Print(
   printer->Print(
     "\n"
     "\n"
     "// @@protoc_insertion_point(global_scope)\n");
     "// @@protoc_insertion_point(global_scope)\n");
@@ -553,7 +569,42 @@ class FileGenerator::ForwardDeclarations {
   std::map<string, const Descriptor*>& classes() { return classes_; }
   std::map<string, const Descriptor*>& classes() { return classes_; }
   std::map<string, const EnumDescriptor*>& enums() { return enums_; }
   std::map<string, const EnumDescriptor*>& enums() { return enums_; }
 
 
-  void Print(io::Printer* printer, const Options& options) const {
+  void PrintForwardDeclarations(io::Printer* printer,
+                                const Options& options) const {
+    PrintNestedDeclarations(printer, options);
+    PrintTopLevelDeclarations(printer, options);
+  }
+
+
+ private:
+  void PrintNestedDeclarations(io::Printer* printer,
+                               const Options& options) const {
+    PrintDeclarationsInsideNamespace(printer, options);
+    for (std::map<string, ForwardDeclarations *>::const_iterator
+             it = namespaces_.begin(),
+             end = namespaces_.end();
+         it != end; ++it) {
+      printer->Print("namespace $nsname$ {\n",
+                     "nsname", it->first);
+      it->second->PrintNestedDeclarations(printer, options);
+      printer->Print("}  // namespace $nsname$\n",
+                     "nsname", it->first);
+    }
+  }
+
+  void PrintTopLevelDeclarations(io::Printer* printer,
+                                 const Options& options) const {
+    PrintDeclarationsOutsideNamespace(printer, options);
+    for (std::map<string, ForwardDeclarations *>::const_iterator
+             it = namespaces_.begin(),
+             end = namespaces_.end();
+         it != end; ++it) {
+      it->second->PrintTopLevelDeclarations(printer, options);
+    }
+  }
+
+  void PrintDeclarationsInsideNamespace(io::Printer* printer,
+                                        const Options& options) const {
     for (std::map<string, const EnumDescriptor *>::const_iterator
     for (std::map<string, const EnumDescriptor *>::const_iterator
              it = enums_.begin(),
              it = enums_.begin(),
              end = enums_.end();
              end = enums_.end();
@@ -584,20 +635,36 @@ class FileGenerator::ForwardDeclarations {
                        "classname", it->first);
                        "classname", it->first);
       }
       }
     }
     }
-    for (std::map<string, ForwardDeclarations *>::const_iterator
-             it = namespaces_.begin(),
-             end = namespaces_.end();
+  }
+
+  void PrintDeclarationsOutsideNamespace(io::Printer* printer,
+                                         const Options& options) const {
+    if (classes_.size() == 0) return;
+
+    printer->Print(
+        "namespace google {\nnamespace protobuf {\n");
+    for (std::map<string, const Descriptor*>::const_iterator
+             it = classes_.begin(),
+             end = classes_.end();
          it != end; ++it) {
          it != end; ++it) {
-      printer->Print("namespace $nsname$ {\n",
-                     "nsname", it->first);
-      it->second->Print(printer, options);
-      printer->Print("}  // namespace $nsname$\n",
-                     "nsname", it->first);
+      const Descriptor* d = it->second;
+      string extra_class_qualifier;
+      // "class" is to disambiguate in case there is also a function with this
+      // name.  There is code out there that does this!
+      printer->Print(
+          "template<> "
+          "$dllexport_decl$"
+          "$class$$classname$* Arena::$func$< $class$$classname$>(Arena*);\n",
+          "classname", QualifiedClassName(d),
+          "func", MessageCreateFunction(d),
+          "class", extra_class_qualifier,
+          "dllexport_decl",
+          options.dllexport_decl.empty() ? "" : options.dllexport_decl + " ");
     }
     }
+    printer->Print(
+        "}  // namespace protobuf\n}  // namespace google\n");
   }
   }
 
 
-
- private:
   std::map<string, ForwardDeclarations*> namespaces_;
   std::map<string, ForwardDeclarations*> namespaces_;
   std::map<string, const Descriptor*> classes_;
   std::map<string, const Descriptor*> classes_;
   std::map<string, const EnumDescriptor*> enums_;
   std::map<string, const EnumDescriptor*> enums_;
@@ -1053,7 +1120,7 @@ void FileGenerator::GenerateInitializationCode(io::Printer* printer) {
 void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
 void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
   ForwardDeclarations decls;
   ForwardDeclarations decls;
   FillForwardDeclarations(&decls);
   FillForwardDeclarations(&decls);
-  decls.Print(printer, options_);
+  decls.PrintForwardDeclarations(printer, options_);
 }
 }
 
 
 void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) {
 void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) {

+ 31 - 8
src/google/protobuf/compiler/cpp/cpp_generator.cc

@@ -41,12 +41,12 @@
 #endif
 #endif
 #include <utility>
 #include <utility>
 
 
+#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/compiler/cpp/cpp_file.h>
 #include <google/protobuf/compiler/cpp/cpp_file.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/stubs/strutil.h>
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
@@ -85,7 +85,6 @@ bool CppGenerator::Generate(const FileDescriptor* file,
   // __declspec(dllimport) depending on what is being compiled.
   // __declspec(dllimport) depending on what is being compiled.
   //
   //
   Options file_options;
   Options file_options;
-  bool split_source = false;
   for (int i = 0; i < options.size(); i++) {
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "dllexport_decl") {
     if (options[i].first == "dllexport_decl") {
       file_options.dllexport_decl = options[i].second;
       file_options.dllexport_decl = options[i].second;
@@ -101,18 +100,28 @@ bool CppGenerator::Generate(const FileDescriptor* file,
       file_options.enforce_lite = true;
       file_options.enforce_lite = true;
     } else if (options[i].first == "lite_implicit_weak_fields") {
     } else if (options[i].first == "lite_implicit_weak_fields") {
       file_options.lite_implicit_weak_fields = true;
       file_options.lite_implicit_weak_fields = true;
+      if (!options[i].second.empty()) {
+        file_options.num_cc_files = strto32(options[i].second.c_str(),
+                                            NULL, 10);
+      }
     } else if (options[i].first == "table_driven_parsing") {
     } else if (options[i].first == "table_driven_parsing") {
       file_options.table_driven_parsing = true;
       file_options.table_driven_parsing = true;
     } else if (options[i].first == "table_driven_serialization") {
     } else if (options[i].first == "table_driven_serialization") {
       file_options.table_driven_serialization = true;
       file_options.table_driven_serialization = true;
-    } else if (options[i].first == "split_source") {
-      split_source = true;
     } else {
     } else {
       *error = "Unknown generator option: " + options[i].first;
       *error = "Unknown generator option: " + options[i].first;
       return false;
       return false;
     }
     }
   }
   }
 
 
+  // The safe_boundary_check option controls behavior for Google-internal
+  // protobuf APIs.
+  if (file_options.safe_boundary_check) {
+    *error =
+        "The safe_boundary_check option is not supported outside of Google.";
+    return false;
+  }
+
   // -----------------------------------------------------------------
   // -----------------------------------------------------------------
 
 
 
 
@@ -159,8 +168,8 @@ bool CppGenerator::Generate(const FileDescriptor* file,
     }
     }
   }
   }
 
 
-  // Generate cc file.
-  if (split_source) {
+  // Generate cc file(s).
+  if (UsingImplicitWeakFields(file, file_options)) {
     {
     {
       // This is the global .cc file, containing enum/services/tables/reflection
       // This is the global .cc file, containing enum/services/tables/reflection
       google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
       google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
@@ -168,12 +177,26 @@ bool CppGenerator::Generate(const FileDescriptor* file,
       io::Printer printer(output.get(), '$');
       io::Printer printer(output.get(), '$');
       file_generator.GenerateGlobalSource(&printer);
       file_generator.GenerateGlobalSource(&printer);
     }
     }
-    for (int i = 0; i < file_generator.NumMessages(); i++) {
+
+    int num_cc_files = file_generator.NumMessages();
+
+    // If we're using implicit weak fields then we allow the user to optionally
+    // specify how many files to generate, not counting the global pb.cc file.
+    // If we have more files than messages, then some files will be generated as
+    // empty placeholders.
+    if (file_options.num_cc_files > 0) {
+      GOOGLE_CHECK_LE(file_generator.NumMessages(), file_options.num_cc_files)
+          << "There must be at least as many numbered .cc files as messages.";
+      num_cc_files = file_options.num_cc_files;
+    }
+    for (int i = 0; i < num_cc_files; i++) {
       // TODO(gerbens) Agree on naming scheme.
       // TODO(gerbens) Agree on naming scheme.
       google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
       google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
           generator_context->Open(basename + "." + SimpleItoa(i) + ".cc"));
           generator_context->Open(basename + "." + SimpleItoa(i) + ".cc"));
       io::Printer printer(output.get(), '$');
       io::Printer printer(output.get(), '$');
-      file_generator.GenerateSourceForMessage(i, &printer);
+      if (i < file_generator.NumMessages()) {
+        file_generator.GenerateSourceForMessage(i, &printer);
+      }
     }
     }
   } else {
   } else {
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(

+ 1 - 1
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -752,7 +752,7 @@ bool UsingImplicitWeakFields(const FileDescriptor* file,
 bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options) {
 bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options) {
   return UsingImplicitWeakFields(field->file(), options) &&
   return UsingImplicitWeakFields(field->file(), options) &&
          field->type() == FieldDescriptor::TYPE_MESSAGE &&
          field->type() == FieldDescriptor::TYPE_MESSAGE &&
-         !field->is_required() && !field->is_repeated() && !field->is_map() &&
+         !field->is_required() && !field->is_map() &&
          field->containing_oneof() == NULL;
          field->containing_oneof() == NULL;
 }
 }
 
 

+ 4 - 0
src/google/protobuf/compiler/cpp/cpp_helpers.h

@@ -310,6 +310,10 @@ inline bool IsCrossFileMessage(const FieldDescriptor* field) {
          field->message_type()->file() != field->file();
          field->message_type()->file() != field->file();
 }
 }
 
 
+inline string MessageCreateFunction(const Descriptor* d) {
+  return SupportsArenas(d) ? "CreateMessage" : "Create";
+}
+
 bool IsAnyMessage(const FileDescriptor* descriptor);
 bool IsAnyMessage(const FileDescriptor* descriptor);
 bool IsAnyMessage(const Descriptor* descriptor);
 bool IsAnyMessage(const Descriptor* descriptor);
 
 

+ 419 - 350
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -325,6 +325,109 @@ bool IsCrossFileMaybeMap(const FieldDescriptor* field) {
   return IsCrossFileMessage(field);
   return IsCrossFileMessage(field);
 }
 }
 
 
+bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
+  return v.front()->is_required();
+}
+
+// Allows chunking repeated fields together and non-repeated fields if the
+// fields share the same has_byte index.
+// TODO(seongkim): use lambda with capture instead of functor.
+class MatchRepeatedAndHasByte {
+ public:
+  MatchRepeatedAndHasByte(const std::vector<int>* has_bit_indices,
+                          bool has_field_presence)
+      : has_bit_indices_(*has_bit_indices),
+        has_field_presence_(has_field_presence) {}
+
+  // Returns true if the following conditions are met:
+  // --both fields are repeated fields
+  // --both fields are non-repeated fields with either has_field_presence is
+  //   false or have the same has_byte index.
+  bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+    return a->is_repeated() == b->is_repeated() &&
+           (!has_field_presence_ || a->is_repeated() ||
+            has_bit_indices_[a->index()] / 8 ==
+                has_bit_indices_[b->index()] / 8);
+  }
+
+ private:
+  const std::vector<int>& has_bit_indices_;
+  const bool has_field_presence_;
+};
+
+// Allows chunking required fields separately after chunking with
+// MatchRepeatedAndHasByte.
+class MatchRepeatedAndHasByteAndRequired : public MatchRepeatedAndHasByte {
+ public:
+  MatchRepeatedAndHasByteAndRequired(const std::vector<int>* has_bit_indices,
+                                     bool has_field_presence)
+      : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {}
+
+  bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+    return MatchRepeatedAndHasByte::operator()(a, b) &&
+           a->is_required() == b->is_required();
+  }
+};
+
+// Allows chunking zero-initializable fields separately after chunking with
+// MatchRepeatedAndHasByte.
+class MatchRepeatedAndHasByteAndZeroInits : public MatchRepeatedAndHasByte {
+ public:
+  MatchRepeatedAndHasByteAndZeroInits(const std::vector<int>* has_bit_indices,
+                                      bool has_field_presence)
+      : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {}
+
+  bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const {
+    return MatchRepeatedAndHasByte::operator()(a, b) &&
+           CanInitializeByZeroing(a) == CanInitializeByZeroing(b);
+  }
+};
+
+// Collects neighboring fields based on a given criteria (equivalent predicate).
+template <typename Predicate>
+std::vector<std::vector<const FieldDescriptor*> > CollectFields(
+    const std::vector<const FieldDescriptor*>& fields,
+    const Predicate& equivalent) {
+  std::vector<std::vector<const FieldDescriptor*> > chunks;
+  if (fields.empty()) {
+    return chunks;
+  }
+
+  const FieldDescriptor* last_field = fields.front();
+  std::vector<const FieldDescriptor*> chunk;
+  for (int i = 0; i < fields.size(); i++) {
+    if (!equivalent(last_field, fields[i]) && !chunk.empty()) {
+      chunks.push_back(chunk);
+      chunk.clear();
+    }
+    chunk.push_back(fields[i]);
+    last_field = fields[i];
+  }
+  if (!chunk.empty()) {
+    chunks.push_back(chunk);
+  }
+  return chunks;
+}
+
+// Returns a bit mask based on has_bit index of "fields" that are typically on
+// the same chunk. It is used in a group presence check where _has_bits_ is
+// masked to tell if any thing in "fields" is present.
+uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields,
+                    const std::vector<int>& has_bit_indices) {
+  GOOGLE_CHECK(!fields.empty());
+  int first_index_offset = has_bit_indices[fields.front()->index()] / 32;
+  uint32 chunk_mask = 0;
+  for (int i = 0; i < fields.size(); i++) {
+    const FieldDescriptor* field = fields[i];
+    // "index" defines where in the _has_bits_ the field appears.
+    int index = has_bit_indices[field->index()];
+    GOOGLE_CHECK_EQ(first_index_offset, index / 32);
+    chunk_mask |= static_cast<uint32>(1) << (index % 32);
+  }
+  GOOGLE_CHECK_NE(0, chunk_mask);
+  return chunk_mask;
+}
+
 }  // anonymous namespace
 }  // anonymous namespace
 
 
 // ===================================================================
 // ===================================================================
@@ -993,6 +1096,7 @@ GenerateClassDefinition(io::Printer* printer) {
 
 
   vars["new_final"] = " PROTOBUF_FINAL";
   vars["new_final"] = " PROTOBUF_FINAL";
 
 
+  vars["create_func"] = MessageCreateFunction(descriptor_);
   printer->Print(vars,
   printer->Print(vars,
     "void Swap($classname$* other);\n"
     "void Swap($classname$* other);\n"
     "friend void swap($classname$& a, $classname$& b) {\n"
     "friend void swap($classname$& a, $classname$& b) {\n"
@@ -1001,9 +1105,13 @@ GenerateClassDefinition(io::Printer* printer) {
     "\n"
     "\n"
     "// implements Message ----------------------------------------------\n"
     "// implements Message ----------------------------------------------\n"
     "\n"
     "\n"
-    "inline $classname$* New() const$new_final$ { return New(NULL); }\n"
+    "inline $classname$* New() const$new_final$ {\n"
+    "  return ::google::protobuf::Arena::$create_func$<$classname$>(NULL);\n"
+    "}\n"
     "\n"
     "\n"
-    "$classname$* New(::google::protobuf::Arena* arena) const$new_final$;\n");
+    "$classname$* New(::google::protobuf::Arena* arena) const$new_final$ {\n"
+    "  return ::google::protobuf::Arena::$create_func$<$classname$>(arena);\n"
+    "}\n");
 
 
   // For instances that derive from Message (rather than MessageLite), some
   // For instances that derive from Message (rather than MessageLite), some
   // methods are virtual and should be marked as final.
   // methods are virtual and should be marked as final.
@@ -2452,112 +2560,125 @@ GenerateStructors(io::Printer* printer) {
   }
   }
 
 
   // Generate the copy constructor.
   // Generate the copy constructor.
-  printer->Print(
-    "$classname$::$classname$(const $classname$& from)\n"
-    "  : $superclass$()",
-    "classname", classname_,
-    "superclass", superclass,
-    "full_name", descriptor_->full_name());
-  printer->Indent();
-  printer->Indent();
-  printer->Indent();
+  if (UsingImplicitWeakFields(descriptor_->file(), options_)) {
+    // If we are in lite mode and using implicit weak fields, we generate a
+    // one-liner copy constructor that delegates to MergeFrom. This saves some
+    // code size and also cuts down on the complexity of implicit weak fields.
+    // We might eventually want to do this for all lite protos.
+    printer->Print(
+      "$classname$::$classname$(const $classname$& from)\n"
+      "  : $classname$() {\n"
+      "  MergeFrom(from);\n"
+      "}\n",
+      "classname", classname_);
+  } else {
+    printer->Print(
+      "$classname$::$classname$(const $classname$& from)\n"
+      "  : $superclass$()",
+      "classname", classname_,
+      "superclass", superclass,
+      "full_name", descriptor_->full_name());
+    printer->Indent();
+    printer->Indent();
+    printer->Indent();
 
 
-  printer->Print(
-      ",\n_internal_metadata_(NULL)");
+    printer->Print(
+        ",\n_internal_metadata_(NULL)");
 
 
-  if (HasFieldPresence(descriptor_->file())) {
-      printer->Print(",\n_has_bits_(from._has_bits_)");
-  }
+    if (HasFieldPresence(descriptor_->file())) {
+        printer->Print(",\n_has_bits_(from._has_bits_)");
+    }
 
 
-  bool need_to_emit_cached_size = true;
-  const string cached_size_decl = ",\n_cached_size_(0)";
-  // We reproduce the logic used for laying out _cached_sized_ in the class
-  // definition, as to initialize it in-order.
-  if (HasFieldPresence(descriptor_->file()) &&
-      (HasBitsSize() % 8) != 0) {
-    printer->Print(cached_size_decl.c_str());
-    need_to_emit_cached_size = false;
-  }
+    bool need_to_emit_cached_size = true;
+    const string cached_size_decl = ",\n_cached_size_(0)";
+    // We reproduce the logic used for laying out _cached_sized_ in the class
+    // definition, as to initialize it in-order.
+    if (HasFieldPresence(descriptor_->file()) &&
+        (HasBitsSize() % 8) != 0) {
+      printer->Print(cached_size_decl.c_str());
+      need_to_emit_cached_size = false;
+    }
 
 
-  std::vector<bool> processed(optimized_order_.size(), false);
-  for (int i = 0; i < optimized_order_.size(); ++i) {
-    const FieldDescriptor* field = optimized_order_[i];
+    std::vector<bool> processed(optimized_order_.size(), false);
+    for (int i = 0; i < optimized_order_.size(); ++i) {
+      const FieldDescriptor* field = optimized_order_[i];
 
 
-    if (!(field->is_repeated() && !(field->is_map()))
-        ) {
-      continue;
-    }
+      if (!(field->is_repeated() && !(field->is_map()))
+          ) {
+        continue;
+      }
 
 
-    processed[i] = true;
-    printer->Print(",\n$name$_(from.$name$_)",
-                   "name", FieldName(field));
-  }
+      processed[i] = true;
+      printer->Print(",\n$name$_(from.$name$_)",
+                     "name", FieldName(field));
+    }
 
 
-  if (need_to_emit_cached_size) {
-    printer->Print(cached_size_decl.c_str());
-    need_to_emit_cached_size = false;
-  }
+    if (need_to_emit_cached_size) {
+      printer->Print(cached_size_decl.c_str());
+      need_to_emit_cached_size = false;
+    }
 
 
-  if (IsAnyMessage(descriptor_)) {
-    printer->Print(",\n_any_metadata_(&type_url_, &value_)");
-  }
-  if (num_weak_fields_ > 0) {
-    printer->Print(",\n_weak_field_map_(from._weak_field_map_)");
-  }
+    if (IsAnyMessage(descriptor_)) {
+      printer->Print(",\n_any_metadata_(&type_url_, &value_)");
+    }
+    if (num_weak_fields_ > 0) {
+      printer->Print(",\n_weak_field_map_(from._weak_field_map_)");
+    }
 
 
-  printer->Outdent();
-  printer->Outdent();
-  printer->Print(" {\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(" {\n");
 
 
-  printer->Print(
-      "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
+    printer->Print(
+        "_internal_metadata_.MergeFrom(from._internal_metadata_);\n");
 
 
-  if (descriptor_->extension_range_count() > 0) {
-    printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
-  }
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
+    }
 
 
-  GenerateConstructorBody(printer, processed, true);
+    GenerateConstructorBody(printer, processed, true);
 
 
-  // Copy oneof fields. Oneof field requires oneof case check.
-  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
-    printer->Print(
-        "clear_has_$oneofname$();\n"
-        "switch (from.$oneofname$_case()) {\n",
-        "oneofname", descriptor_->oneof_decl(i)->name());
-    printer->Indent();
-    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
-      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+    // Copy oneof fields. Oneof field requires oneof case check.
+    for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
       printer->Print(
       printer->Print(
-          "case k$field_name$: {\n",
-          "field_name", UnderscoresToCamelCase(field->name(), true));
+          "clear_has_$oneofname$();\n"
+          "switch (from.$oneofname$_case()) {\n",
+          "oneofname", descriptor_->oneof_decl(i)->name());
       printer->Indent();
       printer->Indent();
-      field_generators_.get(field).GenerateMergingCode(printer);
+      for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+        const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+        printer->Print(
+            "case k$field_name$: {\n",
+            "field_name", UnderscoresToCamelCase(field->name(), true));
+        printer->Indent();
+        field_generators_.get(field).GenerateMergingCode(printer);
+        printer->Print(
+            "break;\n");
+        printer->Outdent();
+        printer->Print(
+            "}\n");
+      }
       printer->Print(
       printer->Print(
-          "break;\n");
+          "case $cap_oneof_name$_NOT_SET: {\n"
+          "  break;\n"
+          "}\n",
+          "oneof_index",
+          SimpleItoa(descriptor_->oneof_decl(i)->index()),
+          "cap_oneof_name",
+          ToUpper(descriptor_->oneof_decl(i)->name()));
       printer->Outdent();
       printer->Outdent();
       printer->Print(
       printer->Print(
           "}\n");
           "}\n");
     }
     }
-    printer->Print(
-        "case $cap_oneof_name$_NOT_SET: {\n"
-        "  break;\n"
-        "}\n",
-        "oneof_index",
-        SimpleItoa(descriptor_->oneof_decl(i)->index()),
-        "cap_oneof_name",
-        ToUpper(descriptor_->oneof_decl(i)->name()));
+
     printer->Outdent();
     printer->Outdent();
     printer->Print(
     printer->Print(
-        "}\n");
+      "  // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
+      "}\n"
+      "\n",
+      "full_name", descriptor_->full_name());
   }
   }
 
 
-  printer->Outdent();
-  printer->Print(
-    "  // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
-    "}\n"
-    "\n",
-    "full_name", descriptor_->full_name());
-
   // Generate the shared constructor code.
   // Generate the shared constructor code.
   GenerateSharedConstructorCode(printer);
   GenerateSharedConstructorCode(printer);
 
 
@@ -2610,24 +2731,17 @@ GenerateStructors(io::Printer* printer) {
       "}\n\n",
       "}\n\n",
       "classname", classname_, "scc_name", scc_name_, "file_namespace",
       "classname", classname_, "scc_name", scc_name_, "file_namespace",
       FileLevelNamespace(descriptor_));
       FileLevelNamespace(descriptor_));
+}
 
 
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(
-      "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
-      "  return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n"
-      "}\n",
-      "classname", classname_);
-  } else {
-    printer->Print(
-      "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
-      "  $classname$* n = new $classname$;\n"
-      "  if (arena != NULL) {\n"
-      "    arena->Own(n);\n"
-      "  }\n"
-      "  return n;\n"
+void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
+  printer->Print(
+      "template<> "
+      "GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE "
+      "$classname$* Arena::$create_func$< $classname$ >(Arena* arena) {\n"
+      "  return Arena::$create_func$Internal< $classname$ >(arena);\n"
       "}\n",
       "}\n",
-      "classname", classname_);
-  }
+      "classname", QualifiedClassName(descriptor_),
+      "create_func", MessageCreateFunction(descriptor_));
 }
 }
 
 
 // Return the number of bits set in n, a non-negative integer.
 // Return the number of bits set in n, a non-negative integer.
@@ -2681,7 +2795,6 @@ GenerateClear(io::Printer* printer) {
     printer->Print("_extensions_.Clear();\n");
     printer->Print("_extensions_.Clear();\n");
   }
   }
 
 
-  int last_i = -1;
   int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear;
   int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear;
   for (int i = 0; i < optimized_order_.size(); i++) {
   for (int i = 0; i < optimized_order_.size(); i++) {
     const FieldDescriptor* field = optimized_order_[i];
     const FieldDescriptor* field = optimized_order_[i];
@@ -2693,197 +2806,162 @@ GenerateClear(io::Printer* printer) {
     unconditional_budget -= EstimateAlignmentSize(field);
     unconditional_budget -= EstimateAlignmentSize(field);
   }
   }
 
 
-  for (int i = 0; i < optimized_order_.size(); ) {
-    // Detect infinite loops.
-    GOOGLE_CHECK_NE(i, last_i);
-    last_i = i;
+  std::vector<std::vector<const FieldDescriptor*> > chunks_frag = CollectFields(
+      optimized_order_,
+      MatchRepeatedAndHasByteAndZeroInits(
+          &has_bit_indices_, HasFieldPresence(descriptor_->file())));
+
+  // Merge next non-zero initializable chunk if it has the same has_byte index
+  // and not meeting unconditional clear condition.
+  std::vector<std::vector<const FieldDescriptor*> > chunks;
+  if (!HasFieldPresence(descriptor_->file())) {
+    // Don't bother with merging without has_bit field.
+    chunks = chunks_frag;
+  } else {
+    // Note that only the next chunk is considered for merging.
+    for (int i = 0; i < chunks_frag.size(); i++) {
+      chunks.push_back(chunks_frag[i]);
+      const FieldDescriptor* field = chunks_frag[i].front();
+      const FieldDescriptor* next_field =
+          (i + 1) < chunks_frag.size() ? chunks_frag[i + 1].front() : NULL;
+      if (CanInitializeByZeroing(field) &&
+          (chunks_frag[i].size() == 1 || unconditional_budget < 0) &&
+          next_field != NULL &&
+          has_bit_indices_[field->index()] / 8 ==
+              has_bit_indices_[next_field->index()] / 8) {
+        GOOGLE_CHECK(!CanInitializeByZeroing(next_field));
+        // Insert next chunk to the current one and skip next chunk.
+        chunks.back().insert(chunks.back().end(), chunks_frag[i + 1].begin(),
+                             chunks_frag[i + 1].end());
+        i++;
+      }
+    }
+  }
+
+  for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+    std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+    GOOGLE_CHECK(!chunk.empty());
 
 
     // Step 2: Repeated fields don't use _has_bits_; emit code to clear them
     // Step 2: Repeated fields don't use _has_bits_; emit code to clear them
     // here.
     // here.
-    for (; i < optimized_order_.size(); i++) {
-      const FieldDescriptor* field = optimized_order_[i];
-      const FieldGenerator& generator = field_generators_.get(field);
+    if (chunk.front()->is_repeated()) {
+      for (int i = 0; i < chunk.size(); i++) {
+        const FieldDescriptor* field = chunk[i];
+        const FieldGenerator& generator = field_generators_.get(field);
 
 
-      if (!field->is_repeated()) {
-        break;
+        generator.GenerateMessageClearingCode(printer);
       }
       }
-
-      generator.GenerateMessageClearingCode(printer);
+      continue;
     }
     }
 
 
-    // Step 3: Greedily seek runs of fields that can be cleared by
-    // memset-to-0.
-    int last_chunk = -1;
-    int last_chunk_start = -1;
-    int last_chunk_end = -1;
-    uint32 last_chunk_mask = 0;
-
+    // Step 3: Non-repeated fields that can be cleared by memset-to-0, then
+    // non-repeated, non-zero initializable fields.
+    int last_chunk = HasFieldPresence(descriptor_->file())
+                         ? has_bit_indices_[chunk.front()->index()] / 8
+                         : 0;
+    int last_chunk_start = 0;
     int memset_run_start = -1;
     int memset_run_start = -1;
     int memset_run_end = -1;
     int memset_run_end = -1;
-    for (; i < optimized_order_.size(); i++) {
-      const FieldDescriptor* field = optimized_order_[i];
-
-      if (!CanInitializeByZeroing(field)) {
-        break;
-      }
-
-      // "index" defines where in the _has_bits_ the field appears.
-      // "i" is our loop counter within optimized_order_.
-      int index = HasFieldPresence(descriptor_->file()) ?
-          has_bit_indices_[field->index()] : 0;
-      int chunk = index / 8;
-
-      if (last_chunk == -1) {
-        last_chunk = chunk;
-        last_chunk_start = i;
-      } else if (chunk != last_chunk) {
-        // Emit the fields for this chunk so far.
-        break;
-      }
 
 
-      if (memset_run_start == -1) {
-        memset_run_start = i;
+    for (int i = 0; i < chunk.size(); i++) {
+      const FieldDescriptor* field = chunk[i];
+      if (CanInitializeByZeroing(field)) {
+        if (memset_run_start == -1) {
+          memset_run_start = i;
+        }
+        memset_run_end = i;
       }
       }
-
-      memset_run_end = i;
-      last_chunk_end = i;
-      last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
     }
     }
 
 
-    if (memset_run_start != memset_run_end && unconditional_budget >= 0) {
-      // Flush the memset fields.
-      goto flush;
-    }
+    const bool have_outer_if =
+        HasFieldPresence(descriptor_->file()) && chunk.size() > 1 &&
+        (memset_run_end != chunk.size() - 1 || unconditional_budget < 0);
 
 
-    // Step 4: Non-repeated, non-zero initializable fields.
-    for (; i < optimized_order_.size(); i++) {
-      const FieldDescriptor* field = optimized_order_[i];
-      if (field->is_repeated() || CanInitializeByZeroing(field)) {
-        break;
-      }
+    if (have_outer_if) {
+      uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+      const int count = popcnt(last_chunk_mask);
 
 
-      // "index" defines where in the _has_bits_ the field appears.
-      // "i" is our loop counter within optimized_order_.
-      int index = HasFieldPresence(descriptor_->file()) ?
-          has_bit_indices_[field->index()] : 0;
-      int chunk = index / 8;
+      // Check (up to) 8 has_bits at a time if we have more than one field in
+      // this chunk.  Due to field layout ordering, we may check
+      // _has_bits_[last_chunk * 8 / 32] multiple times.
+      GOOGLE_DCHECK_LE(2, count);
+      GOOGLE_DCHECK_GE(8, count);
 
 
-      if (last_chunk == -1) {
-        last_chunk = chunk;
-        last_chunk_start = i;
-      } else if (chunk != last_chunk) {
-        // Emit the fields for this chunk so far.
-        break;
+      if (cached_has_bit_index != last_chunk / 4) {
+        cached_has_bit_index = last_chunk / 4;
+        printer->Print("cached_has_bits = _has_bits_[$idx$];\n", "idx",
+                       SimpleItoa(cached_has_bit_index));
       }
       }
-
-      last_chunk_end = i;
-      last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
+      printer->Print("if (cached_has_bits & $mask$u) {\n", "mask",
+                     SimpleItoa(last_chunk_mask));
+      printer->Indent();
     }
     }
 
 
-flush:
-
-    if (last_chunk != -1) {
-      GOOGLE_DCHECK_NE(-1, last_chunk_start);
-      GOOGLE_DCHECK_NE(-1, last_chunk_end);
-      GOOGLE_DCHECK_NE(0, last_chunk_mask);
-
-      const int count = popcnt(last_chunk_mask);
-      const bool have_outer_if = HasFieldPresence(descriptor_->file()) &&
-          (last_chunk_start != last_chunk_end) &&
-          (memset_run_start != last_chunk_start ||
-           memset_run_end != last_chunk_end ||
-           unconditional_budget < 0);
-
-      if (have_outer_if) {
-        // Check (up to) 8 has_bits at a time if we have more than one field in
-        // this chunk.  Due to field layout ordering, we may check
-        // _has_bits_[last_chunk * 8 / 32] multiple times.
-        GOOGLE_DCHECK_LE(2, count);
-        GOOGLE_DCHECK_GE(8, count);
+    if (memset_run_start != -1) {
+      if (memset_run_start == memset_run_end) {
+        // For clarity, do not memset a single field.
+        const FieldGenerator& generator =
+            field_generators_.get(chunk[memset_run_start]);
+        generator.GenerateMessageClearingCode(printer);
+      } else {
+        const string first_field_name = FieldName(chunk[memset_run_start]);
+        const string last_field_name = FieldName(chunk[memset_run_end]);
 
 
-        if (cached_has_bit_index != last_chunk / 4) {
-          cached_has_bit_index = last_chunk / 4;
-          printer->Print(
-              "cached_has_bits = _has_bits_[$idx$];\n",
-              "idx", SimpleItoa(cached_has_bit_index));
-        }
         printer->Print(
         printer->Print(
-          "if (cached_has_bits & $mask$u) {\n",
-          "mask", SimpleItoa(last_chunk_mask));
-        printer->Indent();
-      }
-
-      if (memset_run_start != -1) {
-        if (memset_run_start == memset_run_end) {
-          // For clarity, do not memset a single field.
-          const FieldGenerator& generator =
-              field_generators_.get(optimized_order_[memset_run_start]);
-          generator.GenerateMessageClearingCode(printer);
-        } else {
-          const string first_field_name =
-              FieldName(optimized_order_[memset_run_start]);
-          const string last_field_name =
-              FieldName(optimized_order_[memset_run_end]);
-
-          printer->Print(
             "::memset(&$first$_, 0, static_cast<size_t>(\n"
             "::memset(&$first$_, 0, static_cast<size_t>(\n"
             "    reinterpret_cast<char*>(&$last$_) -\n"
             "    reinterpret_cast<char*>(&$last$_) -\n"
             "    reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n",
             "    reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n",
-            "first", first_field_name,
-            "last", last_field_name);
-        }
-
-        // Advance last_chunk_start to skip over the fields we zeroed/memset.
-        last_chunk_start = memset_run_end + 1;
+            "first", first_field_name, "last", last_field_name);
       }
       }
 
 
-      // Go back and emit clears for each of the fields we processed.
-      for (int j = last_chunk_start; j <= last_chunk_end; j++) {
-        const FieldDescriptor* field = optimized_order_[j];
-        const string fieldname = FieldName(field);
-        const FieldGenerator& generator = field_generators_.get(field);
+      // Advance last_chunk_start to skip over the fields we zeroed/memset.
+      last_chunk_start = memset_run_end + 1;
+    }
+
+    // Go back and emit clears for each of the fields we processed.
+    for (int j = last_chunk_start; j < chunk.size(); j++) {
+      const FieldDescriptor* field = chunk[j];
+      const string fieldname = FieldName(field);
+      const FieldGenerator& generator = field_generators_.get(field);
 
 
-        // It's faster to just overwrite primitive types, but we should only
-        // clear strings and messages if they were set.
-        //
-        // TODO(kenton):  Let the CppFieldGenerator decide this somehow.
-        bool should_check_bit =
+      // It's faster to just overwrite primitive types, but we should only
+      // clear strings and messages if they were set.
+      //
+      // TODO(kenton):  Let the CppFieldGenerator decide this somehow.
+      bool should_check_bit =
           field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
           field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
           field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
           field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
 
 
-        bool have_enclosing_if = false;
-        if (should_check_bit &&
-            // If no field presence, then always clear strings/messages as well.
-            HasFieldPresence(descriptor_->file())) {
-          if (!field->options().weak() &&
-              cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) {
-            cached_has_bit_index = (has_bit_indices_[field->index()] / 32);
-            printer->Print("cached_has_bits = _has_bits_[$new_index$];\n",
-                           "new_index", SimpleItoa(cached_has_bit_index));
-          }
-          if (!MaybeGenerateOptionalFieldCondition(printer, field,
-                                                   cached_has_bit_index)) {
-            printer->Print(
-                "if (has_$name$()) {\n",
-                "name", fieldname);
-          }
-          printer->Indent();
-          have_enclosing_if = true;
+      bool have_enclosing_if = false;
+      if (should_check_bit &&
+          // If no field presence, then always clear strings/messages as well.
+          HasFieldPresence(descriptor_->file())) {
+        if (!field->options().weak() &&
+            cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) {
+          cached_has_bit_index = (has_bit_indices_[field->index()] / 32);
+          printer->Print("cached_has_bits = _has_bits_[$new_index$];\n",
+                         "new_index", SimpleItoa(cached_has_bit_index));
         }
         }
-
-        generator.GenerateMessageClearingCode(printer);
-
-        if (have_enclosing_if) {
-          printer->Outdent();
-          printer->Print("}\n");
+        if (!MaybeGenerateOptionalFieldCondition(printer, field,
+                                                 cached_has_bit_index)) {
+          printer->Print("if (has_$name$()) {\n", "name", fieldname);
         }
         }
+        printer->Indent();
+        have_enclosing_if = true;
       }
       }
 
 
-      if (have_outer_if) {
+      generator.GenerateMessageClearingCode(printer);
+
+      if (have_enclosing_if) {
         printer->Outdent();
         printer->Outdent();
         printer->Print("}\n");
         printer->Print("}\n");
       }
       }
     }
     }
+
+    if (have_outer_if) {
+      printer->Outdent();
+      printer->Print("}\n");
+    }
   }
   }
 
 
   // Step 4: Unions.
   // Step 4: Unions.
@@ -3349,7 +3427,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
       "}\n");
       "}\n");
     return;
     return;
   }
   }
-
   std::vector<const FieldDescriptor*> ordered_fields =
   std::vector<const FieldDescriptor*> ordered_fields =
       SortFieldsByNumber(descriptor_);
       SortFieldsByNumber(descriptor_);
 
 
@@ -3379,9 +3456,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
     return;
     return;
   }
   }
 
 
+  if (SupportsArenas(descriptor_)) {
+    for (int i = 0; i < ordered_fields.size(); i++) {
+      const FieldDescriptor* field = ordered_fields[i];
+      const FieldGenerator& field_generator = field_generators_.get(field);
+      if (field_generator.MergeFromCodedStreamNeedsArena()) {
+        printer->Print(
+          "  ::google::protobuf::Arena* arena = GetArenaNoVirtual();\n");
+        break;
+      }
+    }
+  }
+
   printer->Print(
   printer->Print(
-    "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n"
-    "  ::google::protobuf::uint32 tag;\n");
+      "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto "
+      "failure\n"
+      "  ::google::protobuf::uint32 tag;\n");
 
 
   if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
   if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
     printer->Print(
     printer->Print(
@@ -4141,28 +4231,30 @@ GenerateByteSize(io::Printer* printer) {
     }
     }
   }
   }
 
 
-  int last_i = -1;
-  for (int i = 0; i < optimized_order_.size(); ) {
-    // Detect infinite loops.
-    GOOGLE_CHECK_NE(i, last_i);
-    last_i = i;
+  std::vector<std::vector<const FieldDescriptor*> > chunks = CollectFields(
+      optimized_order_,
+      MatchRepeatedAndHasByteAndRequired(
+          &has_bit_indices_, HasFieldPresence(descriptor_->file())));
 
 
-    // Skip required fields.
-    for (; i < optimized_order_.size() &&
-         optimized_order_[i]->is_required(); i++) {
-    }
+  // Remove chunks with required fields.
+  chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired),
+               chunks.end());
+
+  for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
+    const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
+    GOOGLE_CHECK(!chunk.empty());
 
 
     // Handle repeated fields.
     // Handle repeated fields.
-    for (; i < optimized_order_.size(); i++) {
-      const FieldDescriptor* field = optimized_order_[i];
-      if (!field->is_repeated()) {
-        break;
-      }
+    if (chunk.front()->is_repeated()) {
+      for (int i = 0; i < chunk.size(); i++) {
+        const FieldDescriptor* field = chunk[i];
 
 
-      PrintFieldComment(printer, field);
-      const FieldGenerator& generator = field_generators_.get(field);
-      generator.GenerateByteSize(printer);
-      printer->Print("\n");
+        PrintFieldComment(printer, field);
+        const FieldGenerator& generator = field_generators_.get(field);
+        generator.GenerateByteSize(printer);
+        printer->Print("\n");
+      }
+      continue;
     }
     }
 
 
     // Handle optional (non-repeated/oneof) fields.
     // Handle optional (non-repeated/oneof) fields.
@@ -4174,92 +4266,62 @@ GenerateByteSize(io::Printer* printer) {
     //  descriptor_->field(8), descriptor_->field(9), ...
     //  descriptor_->field(8), descriptor_->field(9), ...
     //  descriptor_->field(15),
     //  descriptor_->field(15),
     // etc.
     // etc.
-    int last_chunk = -1;
-    int last_chunk_start = -1;
-    int last_chunk_end = -1;
-    uint32 last_chunk_mask = 0;
-    for (; i < optimized_order_.size(); i++) {
-      const FieldDescriptor* field = optimized_order_[i];
-      if (field->is_repeated() || field->is_required()) {
-        break;
-      }
+    int last_chunk = HasFieldPresence(descriptor_->file())
+                         ? has_bit_indices_[chunk.front()->index()] / 8
+                         : 0;
+    GOOGLE_DCHECK_NE(-1, last_chunk);
 
 
-      // "index" defines where in the _has_bits_ the field appears.
-      // "i" is our loop counter within optimized_order_.
-      int index = HasFieldPresence(descriptor_->file()) ?
-          has_bit_indices_[field->index()] : 0;
-      int chunk = index / 8;
+    const bool have_outer_if =
+        HasFieldPresence(descriptor_->file()) && chunk.size() > 1;
 
 
-      if (last_chunk == -1) {
-        last_chunk = chunk;
-        last_chunk_start = i;
-      } else if (chunk != last_chunk) {
-        // Emit the fields for this chunk so far.
-        break;
-      }
+    if (have_outer_if) {
+      uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_);
+      const int count = popcnt(last_chunk_mask);
 
 
-      last_chunk_end = i;
-      last_chunk_mask |= static_cast<uint32>(1) << (index % 32);
-    }
+      // Check (up to) 8 has_bits at a time if we have more than one field in
+      // this chunk.  Due to field layout ordering, we may check
+      // _has_bits_[last_chunk * 8 / 32] multiple times.
+      GOOGLE_DCHECK_LE(2, count);
+      GOOGLE_DCHECK_GE(8, count);
 
 
-    if (last_chunk != -1) {
-      GOOGLE_DCHECK_NE(-1, last_chunk_start);
-      GOOGLE_DCHECK_NE(-1, last_chunk_end);
-      GOOGLE_DCHECK_NE(0, last_chunk_mask);
+      printer->Print("if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index",
+                     SimpleItoa(last_chunk * 8), "mask",
+                     SimpleItoa(last_chunk_mask));
+      printer->Indent();
+    }
 
 
-      const int count = popcnt(last_chunk_mask);
-      const bool have_outer_if = HasFieldPresence(descriptor_->file()) &&
-          (last_chunk_start != last_chunk_end);
+    // Go back and emit checks for each of the fields we processed.
+    for (int j = 0; j < chunk.size(); j++) {
+      const FieldDescriptor* field = chunk[j];
+      const FieldGenerator& generator = field_generators_.get(field);
 
 
-      if (have_outer_if) {
-        // Check (up to) 8 has_bits at a time if we have more than one field in
-        // this chunk.  Due to field layout ordering, we may check
-        // _has_bits_[last_chunk * 8 / 32] multiple times.
-        GOOGLE_DCHECK_LE(2, count);
-        GOOGLE_DCHECK_GE(8, count);
+      PrintFieldComment(printer, field);
 
 
-        printer->Print(
-          "if (_has_bits_[$index$ / 32] & $mask$u) {\n",
-          "index", SimpleItoa(last_chunk * 8),
-          "mask", SimpleItoa(last_chunk_mask));
+      bool have_enclosing_if = false;
+      if (HasFieldPresence(descriptor_->file())) {
+        printer->Print("if (has_$name$()) {\n", "name", FieldName(field));
         printer->Indent();
         printer->Indent();
+        have_enclosing_if = true;
+      } else {
+        // Without field presence: field is serialized only if it has a
+        // non-default value.
+        have_enclosing_if =
+            EmitFieldNonDefaultCondition(printer, "this->", field);
       }
       }
 
 
-      // Go back and emit checks for each of the fields we processed.
-      for (int j = last_chunk_start; j <= last_chunk_end; j++) {
-        const FieldDescriptor* field = optimized_order_[j];
-        const FieldGenerator& generator = field_generators_.get(field);
-
-        PrintFieldComment(printer, field);
-
-        bool have_enclosing_if = false;
-        if (HasFieldPresence(descriptor_->file())) {
-          printer->Print(
-            "if (has_$name$()) {\n",
-            "name", FieldName(field));
-          printer->Indent();
-          have_enclosing_if = true;
-        } else {
-          // Without field presence: field is serialized only if it has a
-          // non-default value.
-          have_enclosing_if = EmitFieldNonDefaultCondition(
-              printer, "this->", field);
-        }
-
-        generator.GenerateByteSize(printer);
+      generator.GenerateByteSize(printer);
 
 
-        if (have_enclosing_if) {
-          printer->Outdent();
-          printer->Print(
+      if (have_enclosing_if) {
+        printer->Outdent();
+        printer->Print(
             "}\n"
             "}\n"
             "\n");
             "\n");
-        }
       }
       }
+    }
 
 
-      if (have_outer_if) {
-        printer->Outdent();
-        printer->Print("}\n");
-      }
+    if (have_outer_if) {
+      printer->Outdent();
+      printer->Print("}\n");
     }
     }
   }
   }
 
 
@@ -4359,10 +4421,17 @@ GenerateIsInitialized(io::Printer* printer) {
         !ShouldIgnoreRequiredFieldCheck(field, options_) &&
         !ShouldIgnoreRequiredFieldCheck(field, options_) &&
         scc_analyzer_->HasRequiredFields(field->message_type())) {
         scc_analyzer_->HasRequiredFields(field->message_type())) {
       if (field->is_repeated()) {
       if (field->is_repeated()) {
-        printer->Print(
-          "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
-          " return false;\n",
-          "name", FieldName(field));
+        if (IsImplicitWeakField(field, options_)) {
+          printer->Print(
+            "if (!::google::protobuf::internal::AllAreInitializedWeak(this->$name$_))"
+            " return false;\n",
+            "name", FieldName(field));
+        } else {
+          printer->Print(
+            "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))"
+            " return false;\n",
+            "name", FieldName(field));
+        }
       } else if (field->options().weak()) {
       } else if (field->options().weak()) {
         continue;
         continue;
       } else {
       } else {

+ 3 - 0
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -106,6 +106,9 @@ class MessageGenerator {
   // Generate all non-inline methods for this class.
   // Generate all non-inline methods for this class.
   void GenerateClassMethods(io::Printer* printer);
   void GenerateClassMethods(io::Printer* printer);
 
 
+  // Generate source file code that should go outside any namespace.
+  void GenerateSourceInProto2Namespace(io::Printer* printer);
+
  private:
  private:
   // Generate declarations and definitions of accessors for fields.
   // Generate declarations and definitions of accessors for fields.
   void GenerateDependentBaseClassDefinition(io::Printer* printer);
   void GenerateDependentBaseClassDefinition(io::Printer* printer);

+ 196 - 405
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -80,11 +80,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
   (*variables)["type_default_instance"] =
   (*variables)["type_default_instance"] =
       DefaultInstanceName(descriptor->message_type());
       DefaultInstanceName(descriptor->message_type());
   (*variables)["type_reference_function"] =
   (*variables)["type_reference_function"] =
-      ReferenceFunctionName(descriptor->message_type());
-  if (descriptor->options().weak() || !descriptor->containing_oneof()) {
-    (*variables)["non_null_ptr_to_name"] =
-        StrCat("this->", (*variables)["name"], "_");
-  }
+      IsImplicitWeakField(descriptor, options)
+          ? ("  " + ReferenceFunctionName(descriptor->message_type()) + "();\n")
+          : "";
   (*variables)["stream_writer"] =
   (*variables)["stream_writer"] =
       (*variables)["declared_type"] +
       (*variables)["declared_type"] +
       (HasFastArraySerialization(descriptor->message_type()->file(), options)
       (HasFastArraySerialization(descriptor->message_type()->file(), options)
@@ -96,14 +94,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
       SafeFunctionName(descriptor->containing_type(),
       SafeFunctionName(descriptor->containing_type(),
                        descriptor, "release_");
                        descriptor, "release_");
   (*variables)["full_name"] = descriptor->full_name();
   (*variables)["full_name"] = descriptor->full_name();
-  if (options.proto_h && IsFieldDependent(descriptor)) {
-    (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor);
-    (*variables)["dependent_typename"] =
-        "typename T::" + DependentTypeName(descriptor);
-  } else {
-    (*variables)["dependent_type"] = FieldMessageTypeName(descriptor);
-    (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor);
-  }
+  (*variables)["create_func"] =
+      MessageCreateFunction(descriptor->message_type());
 }
 }
 
 
 }  // namespace
 }  // namespace
@@ -114,7 +106,6 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor,
                                              const Options& options)
                                              const Options& options)
     : FieldGenerator(options),
     : FieldGenerator(options),
       descriptor_(descriptor),
       descriptor_(descriptor),
-      dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
       implicit_weak_field_(IsImplicitWeakField(descriptor, options)) {
       implicit_weak_field_(IsImplicitWeakField(descriptor, options)) {
   SetMessageVariables(descriptor, &variables_, options);
   SetMessageVariables(descriptor, &variables_, options);
 }
 }
@@ -130,24 +121,8 @@ GeneratePrivateMembers(io::Printer* printer) const {
   }
   }
 }
 }
 
 
-void MessageFieldGenerator::
-GenerateDependentAccessorDeclarations(io::Printer* printer) const {
-  if (!dependent_field_) {
-    return;
-  }
-  printer->Print(variables_,
-                 "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
-  printer->Annotate("{", "}", descriptor_);
-}
-
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
-  if (SupportsArenas(descriptor_) && !implicit_weak_field_) {
-    printer->Print(variables_,
-       "private:\n"
-       "void _slow_mutable_$name$();\n"
-       "public:\n");
-  }
   if (implicit_weak_field_) {
   if (implicit_weak_field_) {
     // These private accessors are used by MergeFrom and
     // These private accessors are used by MergeFrom and
     // MergePartialFromCodedStream, and their purpose is to provide access to
     // MergePartialFromCodedStream, and their purpose is to provide access to
@@ -163,11 +138,9 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Annotate("name", descriptor_);
   printer->Annotate("name", descriptor_);
   printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n");
   printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n");
   printer->Annotate("release_name", descriptor_);
   printer->Annotate("release_name", descriptor_);
-  if (!dependent_field_) {
-    printer->Print(variables_,
-                   "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
-    printer->Annotate("{", "}", descriptor_);
-  }
+  printer->Print(variables_,
+                 "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n");
+  printer->Annotate("{", "}", descriptor_);
   printer->Print(variables_,
   printer->Print(variables_,
                  "$deprecated_attr$void ${$set_allocated_$name$$}$"
                  "$deprecated_attr$void ${$set_allocated_$name$$}$"
                  "($type$* $name$);\n");
                  "($type$* $name$);\n");
@@ -216,22 +189,9 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
         "          &$type_default_instance$)->New(GetArenaNoVirtual());\n"
         "          &$type_default_instance$)->New(GetArenaNoVirtual());\n"
         "    }\n"
         "    }\n"
         "  }\n"
         "  }\n"
-        "  return $name$_;\n");
-    } else {
-      printer->Print(variables_,
-        "void $classname$::_slow_mutable_$name$() {\n");
-      if (SupportsArenas(descriptor_->message_type())) {
-        printer->Print(variables_,
-          "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-          "      GetArenaNoVirtual());\n");
-      } else {
-        printer->Print(variables_,
-          "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
-          "      GetArenaNoVirtual());\n");
-      }
+        "  return $name$_;\n"
+        "}\n");
     }
     }
-    printer->Print(variables_,
-      "}\n");
 
 
     printer->Print(variables_,
     printer->Print(variables_,
       "void $classname$::unsafe_arena_set_allocated_$name$(\n"
       "void $classname$::unsafe_arena_set_allocated_$name$(\n"
@@ -267,119 +227,39 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
   }
   }
 }
 }
 
 
-void MessageFieldGenerator::
-GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
-  if (!dependent_field_) {
-    return;
-  }
-
-  std::map<string, string> variables(variables_);
-  // For the CRTP base class, all mutation methods are dependent, and so
-  // they must be in the header.
-  variables["dependent_classname"] =
-      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
-  variables["this_message"] = DependentBaseDownCast();
-  variables["casted_reference"] =
-      ReinterpretCast(variables["dependent_typename"] + "*&",
-                      variables["this_message"] + variables["name"] + "_",
-                      implicit_weak_field_);
-  if (!variables["set_hasbit"].empty()) {
-    variables["set_hasbit"] =
-        variables["this_message"] + variables["set_hasbit"];
-  }
-  if (!variables["clear_hasbit"].empty()) {
-    variables["clear_hasbit"] =
-        variables["this_message"] + variables["clear_hasbit"];
-  }
-
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
-      "template <class T>\n"
-      "inline $type$* $dependent_classname$::mutable_$name$() {\n");
-    if (implicit_weak_field_) {
-      printer->Print(variables, "  $type_reference_function$();\n");
-    }
-    printer->Print(variables,
-      "  $set_hasbit$\n"
-      "  $dependent_typename$*& $name$_ = $casted_reference$;\n"
-      "  if ($name$_ == NULL) {\n");
-    if (implicit_weak_field_) {
-      printer->Print(variables,
-          "    $name$_ = reinterpret_cast<$dependent_typename$*>(\n"
-          "        reinterpret_cast<const google::protobuf::MessageLite*>(\n"
-          "        &$type_default_instance$)->New(\n"
-          "        $this_message$GetArenaNoVirtual()));\n");
-    } else {
-      printer->Print(variables,
-        "    $this_message$_slow_mutable_$name$();\n");
-    }
-    printer->Print(variables,
-      "  }\n"
-      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $name$_;\n"
-      "}\n");
-  } else {
-    printer->Print(variables,
-      "template <class T>\n"
-      "inline $type$* $dependent_classname$::mutable_$name$() {\n"
-      "  $set_hasbit$\n"
-      "  $dependent_typename$*& $name$_ = $casted_reference$;\n"
-      "  if ($name$_ == NULL) {\n"
-      "    $name$_ = new $dependent_typename$;\n"
-      "  }\n"
-      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $name$_;\n"
-      "}\n");
-  }
-}
-
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  std::map<string, string> variables(variables_);
-  variables["const_member"] = ReinterpretCast(
-      "const " + variables["type"] + "*", variables["name"] + "_",
-      implicit_weak_field_);
-  printer->Print(variables,
-    "inline const $type$& $classname$::$name$() const {\n");
-  if (implicit_weak_field_) {
-    printer->Print(variables, "  $type_reference_function$();\n");
-  }
-  printer->Print(variables,
-    "  const $type$* p = $const_member$;\n"
+  printer->Print(variables_,
+    "inline const $type$& $classname$::$name$() const {\n"
+    "$type_reference_function$"
+    "  const $type$* p = $casted_member$;\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n"
     "  return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n"
     "      &$type_default_instance$);\n"
     "      &$type_default_instance$);\n"
     "}\n");
     "}\n");
 
 
-  printer->Print(variables,
+  printer->Print(variables_,
     "inline $type$* $classname$::$release_name$() {\n"
     "inline $type$* $classname$::$release_name$() {\n"
-    "  // @@protoc_insertion_point(field_release:$full_name$)\n");
-  if (implicit_weak_field_) {
-    printer->Print(variables, "  $type_reference_function$();\n");
-  }
-  printer->Print(variables,
+    "  // @@protoc_insertion_point(field_release:$full_name$)\n"
+    "$type_reference_function$"
     "  $clear_hasbit$\n"
     "  $clear_hasbit$\n"
     "  $type$* temp = $casted_member$;\n");
     "  $type$* temp = $casted_member$;\n");
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
+    printer->Print(variables_,
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "    temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n"
       "    temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n"
       "  }\n");
       "  }\n");
   }
   }
-  printer->Print(variables,
+  printer->Print(variables_,
     "  $name$_ = NULL;\n"
     "  $name$_ = NULL;\n"
     "  return temp;\n"
     "  return temp;\n"
     "}\n");
     "}\n");
 
 
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
+    printer->Print(variables_,
       "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
       "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
-      "  // @@protoc_insertion_point("
-      "field_unsafe_arena_release:$full_name$)\n");
-    if (implicit_weak_field_) {
-      printer->Print(variables, "  $type_reference_function$();\n");
-    }
-    printer->Print(variables,
+      "  // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n"
+      "$type_reference_function$"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  $type$* temp = $casted_member$;\n"
       "  $type$* temp = $casted_member$;\n"
       "  $name$_ = NULL;\n"
       "  $name$_ = NULL;\n"
@@ -387,71 +267,58 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "}\n");
       "}\n");
   }
   }
 
 
-  if (!dependent_field_) {
-    if (SupportsArenas(descriptor_)) {
-      printer->Print(variables,
-        "inline $type$* $classname$::mutable_$name$() {\n"
-        "  $set_hasbit$\n"
-        "  if ($name$_ == NULL) {\n");
-      if (implicit_weak_field_) {
-        printer->Print(variables,
-          "    _internal_mutable_$name$();\n");
-      } else {
-        printer->Print(variables,
-          "    _slow_mutable_$name$();\n");
-      }
-      printer->Print(variables,
-        "  }\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-        "  return $casted_member$;\n"
-        "}\n");
-    } else {
-      printer->Print(variables,
-        "inline $type$* $classname$::mutable_$name$() {\n"
-        "  $set_hasbit$\n"
-        "  if ($name$_ == NULL) {\n"
-        "    $name$_ = new $type$;\n"
-        "  }\n"
-        "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-        "  return $casted_member$;\n"
-        "}\n");
-    }
+  printer->Print(variables_,
+    "inline $type$* $classname$::mutable_$name$() {\n"
+    "$type_reference_function$"
+    "  $set_hasbit$\n"
+    "  if ($name$_ == NULL) {\n");
+  if (implicit_weak_field_) {
+    printer->Print(variables_,
+      "    _internal_mutable_$name$();\n");
+  } else {
+    printer->Print(variables_,
+      "    $name$_ = ::google::protobuf::Arena::$create_func$< $type$ >(\n"
+      "        GetArenaNoVirtual());\n");
   }
   }
-
+  printer->Print(variables_,
+    "  }\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+    "  return $casted_member$;\n"
+    "}\n");
 
 
   // We handle the most common case inline, and delegate less common cases to
   // We handle the most common case inline, and delegate less common cases to
   // the slow fallback function.
   // the slow fallback function.
-  printer->Print(variables,
+  printer->Print(variables_,
     "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
     "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
     "  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n");
     "  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n");
-  printer->Print(variables,
+  printer->Print(variables_,
     "  if (message_arena == NULL) {\n");
     "  if (message_arena == NULL) {\n");
   if (IsCrossFileMessage(descriptor_)) {
   if (IsCrossFileMessage(descriptor_)) {
-    printer->Print(variables,
+    printer->Print(variables_,
       "    delete reinterpret_cast< ::google::protobuf::MessageLite*>($name$_);\n");
       "    delete reinterpret_cast< ::google::protobuf::MessageLite*>($name$_);\n");
   } else {
   } else {
-    printer->Print(variables,
+    printer->Print(variables_,
       "    delete $name$_;\n");
       "    delete $name$_;\n");
   }
   }
-  printer->Print(variables,
+  printer->Print(variables_,
     "  }\n"
     "  }\n"
     "  if ($name$) {\n");
     "  if ($name$) {\n");
   if (SupportsArenas(descriptor_->message_type()) &&
   if (SupportsArenas(descriptor_->message_type()) &&
       IsCrossFileMessage(descriptor_)) {
       IsCrossFileMessage(descriptor_)) {
     // We have to read the arena through the virtual method, because the type
     // We have to read the arena through the virtual method, because the type
     // isn't defined in this file.
     // isn't defined in this file.
-    printer->Print(variables,
+    printer->Print(variables_,
       "    ::google::protobuf::Arena* submessage_arena =\n"
       "    ::google::protobuf::Arena* submessage_arena =\n"
       "      reinterpret_cast< ::google::protobuf::MessageLite*>($name$)->GetArena();\n");
       "      reinterpret_cast< ::google::protobuf::MessageLite*>($name$)->GetArena();\n");
   } else if (!SupportsArenas(descriptor_->message_type())) {
   } else if (!SupportsArenas(descriptor_->message_type())) {
-    printer->Print(variables,
+    printer->Print(variables_,
       "    ::google::protobuf::Arena* submessage_arena = NULL;\n");
       "    ::google::protobuf::Arena* submessage_arena = NULL;\n");
   } else {
   } else {
-    printer->Print(variables,
+    printer->Print(variables_,
       "    ::google::protobuf::Arena* submessage_arena =\n"
       "    ::google::protobuf::Arena* submessage_arena =\n"
       "      ::google::protobuf::Arena::GetArena($name$);\n");
       "      ::google::protobuf::Arena::GetArena($name$);\n");
   }
   }
-  printer->Print(variables,
+  printer->Print(variables_,
     "    if (message_arena != submessage_arena) {\n"
     "    if (message_arena != submessage_arena) {\n"
     "      $name$ = ::google::protobuf::internal::GetOwnedMessage(\n"
     "      $name$ = ::google::protobuf::internal::GetOwnedMessage(\n"
     "          message_arena, $name$, submessage_arena);\n"
     "          message_arena, $name$, submessage_arena);\n"
@@ -461,13 +328,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    $clear_hasbit$\n"
     "    $clear_hasbit$\n"
     "  }\n");
     "  }\n");
   if (implicit_weak_field_) {
   if (implicit_weak_field_) {
-    printer->Print(variables,
+    printer->Print(variables_,
       "  $name$_ = reinterpret_cast<MessageLite*>($name$);\n");
       "  $name$_ = reinterpret_cast<MessageLite*>($name$);\n");
   } else {
   } else {
-    printer->Print(variables,
+    printer->Print(variables_,
       "  $name$_ = $name$;\n");
       "  $name$_ = $name$;\n");
   }
   }
-  printer->Print(variables,
+  printer->Print(variables_,
     "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "}\n");
     "}\n");
 }
 }
@@ -540,34 +407,12 @@ GenerateConstructorCode(io::Printer* printer) const {
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateCopyConstructorCode(io::Printer* printer) const {
 GenerateCopyConstructorCode(io::Printer* printer) const {
-  // For non-Arena enabled messages, everything always goes on the heap.
-  //
-  // For Arena enabled messages, the logic is a bit more convoluted.
-  //
-  // In the copy constructor, we call InternalMetadataWithArena::MergeFrom,
-  // which does *not* copy the Arena pointer.  In the generated MergeFrom
-  // (see MessageFieldGenerator::GenerateMergingCode), we:
-  // -> copy the has bits (but this is done in bulk by a memcpy in the copy
-  //    constructor)
-  // -> check whether the destination field pointer is NULL (it will be, since
-  //    we're initializing it and would have called SharedCtor) and if so:
-  // -> call _slow_mutable_$name$(), which calls either
-  //    ::google::protobuf::Arena::CreateMessage<>(GetArenaNoVirtual()), or
-  //    ::google::protobuf::Arena::Create<>(GetArenaNoVirtual())
-  //
-  // At this point, GetArenaNoVirtual returns NULL since the Arena pointer
-  // wasn't copied, so both of these methods allocate the submessage on the
-  // heap.
-
-  string new_expression = (implicit_weak_field_ ? "from.$name$_->New()"
-                                                : "new $type$(*from.$name$_)");
-  string output =
-      "if (from.has_$name$()) {\n"
-      "  $name$_ = " + new_expression + ";\n"
-      "} else {\n"
-      "  $name$_ = NULL;\n"
-      "}\n";
-  printer->Print(variables_, output.c_str());
+  printer->Print(variables_,
+    "if (from.has_$name$()) {\n"
+    "  $name$_ = new $type$(*from.$name$_);\n"
+    "} else {\n"
+    "  $name$_ = NULL;\n"
+    "}\n");
 }
 }
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
@@ -591,7 +436,7 @@ void MessageFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
     "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
     "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
-    "  $number$, *$non_null_ptr_to_name$, output);\n");
+    "  $number$, *$field_member$, output);\n");
 }
 }
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
@@ -599,7 +444,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
     "target = ::google::protobuf::internal::WireFormatLite::\n"
     "target = ::google::protobuf::internal::WireFormatLite::\n"
     "  InternalWrite$declared_type$ToArray(\n"
     "  InternalWrite$declared_type$ToArray(\n"
-    "    $number$, *$non_null_ptr_to_name$, deterministic, target);\n");
+    "    $number$, *$field_member$, deterministic, target);\n");
 }
 }
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
@@ -607,7 +452,7 @@ GenerateByteSize(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
     "total_size += $tag_size$ +\n"
     "total_size += $tag_size$ +\n"
     "  ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
     "  ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
-    "    *$non_null_ptr_to_name$);\n");
+    "    *$field_member$);\n");
 }
 }
 
 
 // ===================================================================
 // ===================================================================
@@ -650,57 +495,27 @@ void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions(
     "          message_arena, $name$, submessage_arena);\n"
     "          message_arena, $name$, submessage_arena);\n"
     "    }\n"
     "    }\n"
     "    set_has_$name$();\n"
     "    set_has_$name$();\n"
-    "    $oneof_prefix$$name$_ = $name$;\n"
+    "    $field_member$ = $name$;\n"
     "  }\n"
     "  }\n"
     "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
     "}\n");
     "}\n");
 }
 }
 
 
-void MessageOneofFieldGenerator::
-GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
-  // For the CRTP base class, all mutation methods are dependent, and so
-  // they must be in the header.
-  if (!dependent_base_) {
-    return;
-  }
-  std::map<string, string> variables(variables_);
-  variables["dependent_classname"] =
-      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
-  variables["this_message"] = "reinterpret_cast<T*>(this)->";
-  // Const message access is needed for the dependent getter.
-  variables["this_const_message"] = "reinterpret_cast<const T*>(this)->";
-  variables["tmpl"] = "template <class T>\n";
-  variables["field_member"] = variables["this_message"] +
-                              variables["oneof_prefix"] + variables["name"] +
-                              "_";
-  InternalGenerateInlineAccessorDefinitions(variables, printer);
-}
-
 void MessageOneofFieldGenerator::
 void MessageOneofFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-
-  std::map<string, string> variables(variables_);
-  variables["dependent_classname"] = variables["classname"];
-  variables["this_message"] = "";
-  variables["this_const_message"] = "";
-  variables["tmpl"] = "";
-  variables["field_member"] =
-      variables["oneof_prefix"] + variables["name"] + "_";
-  variables["dependent_type"] = variables["type"];
-
-  printer->Print(variables,
+  printer->Print(variables_,
     "inline $type$* $classname$::$release_name$() {\n"
     "inline $type$* $classname$::$release_name$() {\n"
     "  // @@protoc_insertion_point(field_release:$full_name$)\n"
     "  // @@protoc_insertion_point(field_release:$full_name$)\n"
-    "  if ($this_message$has_$name$()) {\n"
-    "    $this_message$clear_has_$oneof_name$();\n"
+    "  if (has_$name$()) {\n"
+    "    clear_has_$oneof_name$();\n"
     "      $type$* temp = $field_member$;\n");
     "      $type$* temp = $field_member$;\n");
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
-      "    if ($this_message$GetArenaNoVirtual() != NULL) {\n"
+    printer->Print(variables_,
+      "    if (GetArenaNoVirtual() != NULL) {\n"
       "      temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n"
       "      temp = ::google::protobuf::internal::DuplicateIfNonNull(temp, NULL);\n"
       "    }\n");
       "    }\n");
   }
   }
-  printer->Print(variables,
+  printer->Print(variables_,
     "    $field_member$ = NULL;\n"
     "    $field_member$ = NULL;\n"
     "    return temp;\n"
     "    return temp;\n"
     "  } else {\n"
     "  } else {\n"
@@ -708,23 +523,23 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "  }\n"
     "  }\n"
     "}\n");
     "}\n");
 
 
-  printer->Print(variables,
+  printer->Print(variables_,
     "inline const $type$& $classname$::$name$() const {\n"
     "inline const $type$& $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-    "  return $this_const_message$has_$name$()\n"
-    "      ? *$this_const_message$$oneof_prefix$$name$_\n"
+    "  return has_$name$()\n"
+    "      ? *$field_member$\n"
     "      : *reinterpret_cast< $type$*>(&$type_default_instance$);\n"
     "      : *reinterpret_cast< $type$*>(&$type_default_instance$);\n"
     "}\n");
     "}\n");
 
 
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
-      "inline $type$* $dependent_classname$::unsafe_arena_release_$name$() {\n"
+    printer->Print(variables_,
+      "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
       "  // @@protoc_insertion_point(field_unsafe_arena_release"
       "  // @@protoc_insertion_point(field_unsafe_arena_release"
       ":$full_name$)\n"
       ":$full_name$)\n"
-      "  if ($this_message$has_$name$()) {\n"
-      "    $this_message$clear_has_$oneof_name$();\n"
-      "    $type$* temp = $this_message$$oneof_prefix$$name$_;\n"
-      "    $this_message$$oneof_prefix$$name$_ = NULL;\n"
+      "  if (has_$name$()) {\n"
+      "    clear_has_$oneof_name$();\n"
+      "    $type$* temp = $field_member$;\n"
+      "    $field_member$ = NULL;\n"
       "    return temp;\n"
       "    return temp;\n"
       "  } else {\n"
       "  } else {\n"
       "    return NULL;\n"
       "    return NULL;\n"
@@ -738,58 +553,24 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
       "  clear_$oneof_name$();\n"
       "  clear_$oneof_name$();\n"
       "  if ($name$) {\n"
       "  if ($name$) {\n"
       "    set_has_$name$();\n"
       "    set_has_$name$();\n"
-      "    $oneof_prefix$$name$_ = $name$;\n"
+      "    $field_member$ = $name$;\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
       "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
       "$full_name$)\n"
       "$full_name$)\n"
       "}\n");
       "}\n");
   }
   }
 
 
-  if (dependent_base_) {
-    return;
-  }
-
-  InternalGenerateInlineAccessorDefinitions(variables, printer);
-}
-
-void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions(
-    const std::map<string, string>& variables, io::Printer* printer) const {
-  if (SupportsArenas(descriptor_)) {
-    printer->Print(variables,
-      "$tmpl$"
-      "inline $type$* $dependent_classname$::mutable_$name$() {\n"
-      "  if (!$this_message$has_$name$()) {\n"
-      "    $this_message$clear_$oneof_name$();\n"
-      "    $this_message$set_has_$name$();\n");
-    if (SupportsArenas(descriptor_->message_type())) {
-      printer->Print(variables,
-         "    $field_member$ = \n"
-         "      ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n"
-         "      $this_message$GetArenaNoVirtual());\n");
-    } else {
-      printer->Print(variables,
-         "    $this_message$$oneof_prefix$$name$_ = \n"
-         "      ::google::protobuf::Arena::Create< $dependent_typename$ >(\n"
-         "      $this_message$GetArenaNoVirtual());\n");
-    }
-    printer->Print(variables,
-      "  }\n"
-      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $field_member$;\n"
-      "}\n");
-  } else {
-    printer->Print(variables,
-      "$tmpl$"
-      "inline $type$* $dependent_classname$::mutable_$name$() {\n"
-      "  if (!$this_message$has_$name$()) {\n"
-      "    $this_message$clear_$oneof_name$();\n"
-      "    $this_message$set_has_$name$();\n"
-      "    $field_member$ = new $dependent_typename$;\n"
-      "  }\n"
-      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $field_member$;\n"
-      "}\n");
-  }
+  printer->Print(variables_,
+    "inline $type$* $classname$::mutable_$name$() {\n"
+    "  if (!has_$name$()) {\n"
+    "    clear_$oneof_name$();\n"
+    "    set_has_$name$();\n"
+    "    $field_member$ = ::google::protobuf::Arena::$create_func$< $type$ >(\n"
+    "        GetArenaNoVirtual());\n"
+    "  }\n"
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+    "  return $field_member$;\n"
+    "}\n");
 }
 }
 
 
 void MessageOneofFieldGenerator::
 void MessageOneofFieldGenerator::
@@ -797,11 +578,11 @@ GenerateClearingCode(io::Printer* printer) const {
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
     printer->Print(variables_,
       "if (GetArenaNoVirtual() == NULL) {\n"
       "if (GetArenaNoVirtual() == NULL) {\n"
-      "  delete $oneof_prefix$$name$_;\n"
+      "  delete $field_member$;\n"
       "}\n");
       "}\n");
   } else {
   } else {
     printer->Print(variables_,
     printer->Print(variables_,
-      "delete $oneof_prefix$$name$_;\n");
+      "delete $field_member$;\n");
   }
   }
 }
 }
 
 
@@ -834,7 +615,7 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
     : FieldGenerator(options),
     : FieldGenerator(options),
       descriptor_(descriptor),
       descriptor_(descriptor),
       dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
       dependent_field_(options.proto_h && IsFieldDependent(descriptor)),
-      dependent_getter_(dependent_field_ && options.safe_boundary_check) {
+      implicit_weak_field_(IsImplicitWeakField(descriptor, options)) {
   SetMessageVariables(descriptor, &variables_, options);
   SetMessageVariables(descriptor, &variables_, options);
 }
 }
 
 
@@ -848,30 +629,12 @@ GeneratePrivateMembers(io::Printer* printer) const {
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
 InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
-  printer->Print(variables_,
-                 "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n");
-  printer->Annotate("{", "}", descriptor_);
   printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n");
   printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n");
   printer->Annotate("{", "}", descriptor_);
   printer->Annotate("{", "}", descriptor_);
-  if (dependent_getter_) {
-    printer->Print(variables_,
-      "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-      "    $name$() const;\n");
-    printer->Annotate("name", descriptor_);
-  }
-  printer->Print(variables_,
-                 "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
-                 "    ${$mutable_$name$$}$();\n");
-  printer->Annotate("{", "}", descriptor_);
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateDependentAccessorDeclarations(io::Printer* printer) const {
 GenerateDependentAccessorDeclarations(io::Printer* printer) const {
-  if (dependent_getter_) {
-    printer->Print(variables_,
-      "$deprecated_attr$const $type$& $name$(int index) const;\n");
-    printer->Annotate("name", descriptor_);
-  }
   if (dependent_field_) {
   if (dependent_field_) {
     InternalGenerateTypeDependentAccessorDeclarations(printer);
     InternalGenerateTypeDependentAccessorDeclarations(printer);
   }
   }
@@ -879,20 +642,24 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const {
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
 GenerateAccessorDeclarations(io::Printer* printer) const {
-  if (!dependent_getter_) {
-    printer->Print(variables_,
-      "$deprecated_attr$const $type$& $name$(int index) const;\n");
-    printer->Annotate("name", descriptor_);
-  }
+  printer->Print(variables_,
+                 "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n");
+  printer->Annotate("{", "}", descriptor_);
+  printer->Print(variables_,
+                 "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n"
+                 "    ${$mutable_$name$$}$();\n");
+  printer->Annotate("{", "}", descriptor_);
+
+  printer->Print(variables_,
+    "$deprecated_attr$const $type$& $name$(int index) const;\n");
+  printer->Annotate("name", descriptor_);
   if (!dependent_field_) {
   if (!dependent_field_) {
     InternalGenerateTypeDependentAccessorDeclarations(printer);
     InternalGenerateTypeDependentAccessorDeclarations(printer);
   }
   }
-  if (!dependent_getter_) {
-    printer->Print(variables_,
-      "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-      "    $name$() const;\n");
-    printer->Annotate("name", descriptor_);
-  }
+  printer->Print(variables_,
+    "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+    "    $name$() const;\n");
+  printer->Annotate("name", descriptor_);
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
@@ -908,103 +675,97 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
   variables["this_message"] = DependentBaseDownCast();
   variables["this_message"] = DependentBaseDownCast();
   variables["this_const_message"] = DependentBaseConstDownCast();
   variables["this_const_message"] = DependentBaseConstDownCast();
 
 
-  if (dependent_getter_) {
-    printer->Print(variables,
-      "template <class T>\n"
-      "inline const $type$& $dependent_classname$::$name$(int index) const {\n"
-      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-      "  return $this_const_message$$name$_.$cppget$(index);\n"
-      "}\n");
-  }
-
   // Generate per-element accessors:
   // Generate per-element accessors:
   printer->Print(variables,
   printer->Print(variables,
-    "template <class T>\n"
-    "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n"
-    // TODO(dlj): move insertion points
-    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-    "  return $this_message$$name$_.Mutable(index);\n"
-    "}\n"
     "template <class T>\n"
     "template <class T>\n"
     "inline $type$* $dependent_classname$::add_$name$() {\n"
     "inline $type$* $dependent_classname$::add_$name$() {\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+    "$type_reference_function$"
     "  return $this_message$$name$_.Add();\n"
     "  return $this_message$$name$_.Add();\n"
     "}\n");
     "}\n");
+}
 
 
-  if (dependent_getter_) {
-    printer->Print(variables,
-      "template <class T>\n"
-      "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-      "$dependent_classname$::$name$() const {\n"
-      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
-      "  return $this_const_message$$name$_;\n"
-      "}\n");
-  }
-
-  // Generate mutable access to the entire list:
-  printer->Print(variables,
-    "template <class T>\n"
+void RepeatedMessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  printer->Print(variables_,
+    "inline $type$* $classname$::mutable_$name$(int index) {\n"
+    // TODO(dlj): move insertion points
+    "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+    "$type_reference_function$"
+    "  return $name$_.Mutable(index);\n"
+    "}\n"
     "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
-    "$dependent_classname$::mutable_$name$() {\n"
+    "$classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
-    "  return &$this_message$$name$_;\n"
+    "$type_reference_function$"
+    "  return &$name$_;\n"
     "}\n");
     "}\n");
-}
 
 
-void RepeatedMessageFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer) const {
-  if (!dependent_getter_) {
+  if (options_.safe_boundary_check) {
+    printer->Print(variables_,
+      "inline const $type$& $classname$::$name$(int index) const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "$type_reference_function$"
+      "  return $name$_.InternalCheckedGet(index,\n"
+      "      *reinterpret_cast<const $type$*>(&$type_default_instance$));\n"
+      "}\n");
+  } else {
     printer->Print(variables_,
     printer->Print(variables_,
       "inline const $type$& $classname$::$name$(int index) const {\n"
       "inline const $type$& $classname$::$name$(int index) const {\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
       "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-      "  return $name$_.$cppget$(index);\n"
+      "$type_reference_function$"
+      "  return $name$_.Get(index);\n"
       "}\n");
       "}\n");
   }
   }
 
 
   if (!dependent_field_) {
   if (!dependent_field_) {
     printer->Print(variables_,
     printer->Print(variables_,
-      "inline $type$* $classname$::mutable_$name$(int index) {\n"
-      // TODO(dlj): move insertion points
-      "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $name$_.Mutable(index);\n"
-      "}\n"
       "inline $type$* $classname$::add_$name$() {\n"
       "inline $type$* $classname$::add_$name$() {\n"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
       "  // @@protoc_insertion_point(field_add:$full_name$)\n"
+      "$type_reference_function$"
       "  return $name$_.Add();\n"
       "  return $name$_.Add();\n"
       "}\n");
       "}\n");
   }
   }
 
 
-  if (!dependent_field_) {
-    printer->Print(variables_,
-      "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
-      "$classname$::mutable_$name$() {\n"
-      "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
-      "  return &$name$_;\n"
-      "}\n");
-  }
-  if (!dependent_getter_) {
-    printer->Print(variables_,
-      "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-      "$classname$::$name$() const {\n"
-      "  // @@protoc_insertion_point(field_list:$full_name$)\n"
-      "  return $name$_;\n"
-      "}\n");
-  }
+  printer->Print(variables_,
+    "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
+    "$classname$::$name$() const {\n"
+    "  // @@protoc_insertion_point(field_list:$full_name$)\n"
+    "$type_reference_function$"
+    "  return $name$_;\n"
+    "}\n");
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Clear();\n");
+  if (implicit_weak_field_) {
+    printer->Print(
+        variables_,
+        "CastToBase(&$name$_)->Clear<"
+        "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>();\n");
+  } else {
+    printer->Print(variables_, "$name$_.Clear();\n");
+  }
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
 GenerateMergingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+  if (implicit_weak_field_) {
+    printer->Print(
+        variables_,
+        "CastToBase(&$name$_)->MergeFrom<"
+        "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase("
+        "from.$name$_));\n");
+  } else {
+    printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+  }
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
+  printer->Print(
+      variables_,
+      "CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n");
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
@@ -1015,9 +776,18 @@ GenerateConstructorCode(io::Printer* printer) const {
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
-    printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormatLite::"
-      "ReadMessage(input, add_$name$()));\n");
+    if (implicit_weak_field_) {
+      printer->Print(variables_,
+        "DO_(::google::protobuf::internal::WireFormatLite::"
+        "ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n"
+        "    reinterpret_cast<const ::google::protobuf::MessageLite*>(\n"
+        "        &$type_default_instance$))));\n");
+    } else {
+      printer->Print(variables_,
+        "DO_(::google::protobuf::internal::WireFormatLite::"
+        "ReadMessage(\n"
+        "      input, add_$name$()));\n");
+    }
   } else {
   } else {
     printer->Print(variables_,
     printer->Print(variables_,
       "DO_(::google::protobuf::internal::WireFormatLite::"
       "DO_(::google::protobuf::internal::WireFormatLite::"
@@ -1031,7 +801,19 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
     "for (unsigned int i = 0,\n"
     "for (unsigned int i = 0,\n"
     "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
     "    n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n"
     "  ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
     "  ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
-    "    $number$, this->$name$(static_cast<int>(i)), output);\n"
+    "    $number$,\n");
+  if (implicit_weak_field_) {
+    printer->Print(
+        variables_,
+        "    CastToBase($name$_).Get<"
+        "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>("
+        "static_cast<int>(i)),\n");
+  } else {
+    printer->Print(variables_,
+      "    this->$name$(static_cast<int>(i)),\n");
+  }
+  printer->Print(variables_,
+    "    output);\n"
     "}\n");
     "}\n");
 }
 }
 
 
@@ -1056,9 +838,18 @@ GenerateByteSize(io::Printer* printer) const {
     "total_size += $tag_size$UL * count;\n"
     "total_size += $tag_size$UL * count;\n"
     "for (unsigned int i = 0; i < count; i++) {\n"
     "for (unsigned int i = 0; i < count; i++) {\n"
     "  total_size +=\n"
     "  total_size +=\n"
-    "    ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
-    "      this->$name$(static_cast<int>(i)));\n"
-    "}\n");
+    "    ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n");
+  if (implicit_weak_field_) {
+    printer->Print(
+        variables_,
+        "      CastToBase($name$_).Get<"
+        "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>("
+        "static_cast<int>(i)));\n");
+  } else {
+    printer->Print(variables_,
+        "      this->$name$(static_cast<int>(i)));\n");
+  }
+  printer->Print(variables_, "}\n");
   printer->Outdent();
   printer->Outdent();
   printer->Print("}\n");
   printer->Print("}\n");
 }
 }

+ 1 - 8
src/google/protobuf/compiler/cpp/cpp_message_field.h

@@ -54,9 +54,7 @@ class MessageFieldGenerator : public FieldGenerator {
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
   void GeneratePrivateMembers(io::Printer* printer) const;
-  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
-  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
@@ -73,7 +71,6 @@ class MessageFieldGenerator : public FieldGenerator {
 
 
  protected:
  protected:
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
-  const bool dependent_field_;
   const bool implicit_weak_field_;
   const bool implicit_weak_field_;
   std::map<string, string> variables_;
   std::map<string, string> variables_;
 
 
@@ -88,7 +85,6 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
   ~MessageOneofFieldGenerator();
   ~MessageOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
-  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
@@ -101,9 +97,6 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
 
 
  private:
  private:
-  void InternalGenerateInlineAccessorDefinitions(
-      const std::map<string, string>& variables, io::Printer* printer) const;
-
   const bool dependent_base_;
   const bool dependent_base_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
 };
 };
@@ -136,7 +129,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
 
 
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
   const bool dependent_field_;
   const bool dependent_field_;
-  const bool dependent_getter_;
+  const bool implicit_weak_field_;
   std::map<string, string> variables_;
   std::map<string, string> variables_;
 
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);

+ 2 - 0
src/google/protobuf/compiler/cpp/cpp_options.h

@@ -54,6 +54,7 @@ struct Options {
         table_driven_parsing(false),
         table_driven_parsing(false),
         table_driven_serialization(false),
         table_driven_serialization(false),
         lite_implicit_weak_fields(false),
         lite_implicit_weak_fields(false),
+        num_cc_files(0),
         access_info_map(NULL) {}
         access_info_map(NULL) {}
 
 
   string dllexport_decl;
   string dllexport_decl;
@@ -65,6 +66,7 @@ struct Options {
   bool table_driven_parsing;
   bool table_driven_parsing;
   bool table_driven_serialization;
   bool table_driven_serialization;
   bool lite_implicit_weak_fields;
   bool lite_implicit_weak_fields;
+  int num_cc_files;
   string annotation_pragma_name;
   string annotation_pragma_name;
   string annotation_guard_name;
   string annotation_guard_name;
   const AccessInfoMap* access_info_map;
   const AccessInfoMap* access_info_map;

+ 4 - 4
src/google/protobuf/compiler/cpp/cpp_primitive_field.cc

@@ -215,7 +215,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "inline $type$ $classname$::$name$() const {\n"
     "inline $type$ $classname$::$name$() const {\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  // @@protoc_insertion_point(field_get:$full_name$)\n"
     "  if (has_$name$()) {\n"
     "  if (has_$name$()) {\n"
-    "    return $oneof_prefix$$name$_;\n"
+    "    return $field_member$;\n"
     "  }\n"
     "  }\n"
     "  return $default$;\n"
     "  return $default$;\n"
     "}\n"
     "}\n"
@@ -224,14 +224,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
     "    clear_$oneof_name$();\n"
     "    clear_$oneof_name$();\n"
     "    set_has_$name$();\n"
     "    set_has_$name$();\n"
     "  }\n"
     "  }\n"
-    "  $oneof_prefix$$name$_ = value;\n"
+    "  $field_member$ = value;\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "  // @@protoc_insertion_point(field_set:$full_name$)\n"
     "}\n");
     "}\n");
 }
 }
 
 
 void PrimitiveOneofFieldGenerator::
 void PrimitiveOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$oneof_prefix$$name$_ = $default$;\n");
+  printer->Print(variables_, "$field_member$ = $default$;\n");
 }
 }
 
 
 void PrimitiveOneofFieldGenerator::
 void PrimitiveOneofFieldGenerator::
@@ -251,7 +251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
     "clear_$oneof_name$();\n"
     "clear_$oneof_name$();\n"
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "         $type$, $wire_format_field_type$>(\n"
     "         $type$, $wire_format_field_type$>(\n"
-    "       input, &$oneof_prefix$$name$_)));\n"
+    "       input, &$field_member$)));\n"
     "set_has_$name$();\n");
     "set_has_$name$();\n");
 }
 }
 
 

+ 59 - 47
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -402,11 +402,11 @@ GenerateMessageClearingCode(io::Printer* printer) const {
     // When Arenas are disabled and field presence has been checked, we can
     // When Arenas are disabled and field presence has been checked, we can
     // safely treat the ArenaStringPtr as a string*.
     // safely treat the ArenaStringPtr as a string*.
     if (descriptor_->default_value_string().empty()) {
     if (descriptor_->default_value_string().empty()) {
-      printer->Print(variables_,
-        "(*$name$_.UnsafeRawStringPointer())->clear();\n");
+      printer->Print(variables_, "$name$_.UnsafeMutablePointer()->clear();\n");
     } else {
     } else {
-      printer->Print(variables_,
-        "(*$name$_.UnsafeRawStringPointer())->assign(*$default_variable$);\n");
+      printer->Print(
+          variables_,
+          "$name$_.UnsafeMutablePointer()->assign(*$default_variable$);\n");
     }
     }
   } else {
   } else {
     if (descriptor_->default_value_string().empty()) {
     if (descriptor_->default_value_string().empty()) {
@@ -504,6 +504,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
   }
   }
 }
 }
 
 
+bool StringFieldGenerator::
+MergeFromCodedStreamNeedsArena() const {
+  return false;
+}
+
 void StringFieldGenerator::
 void StringFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
   if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
@@ -559,7 +564,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "inline const ::std::string& $classname$::$name$() const {\n"
         "inline const ::std::string& $classname$::$name$() const {\n"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "  if (has_$name$()) {\n"
-        "    return $oneof_prefix$$name$_.Get();\n"
+        "    return $field_member$.Get();\n"
         "  }\n"
         "  }\n"
         "  return *$default_variable$;\n"
         "  return *$default_variable$;\n"
         "}\n"
         "}\n"
@@ -567,9 +572,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.Set$lite$($default_variable$, value,\n"
+        "  $field_member$.Set$lite$($default_variable$, value,\n"
         "      GetArenaNoVirtual());\n"
         "      GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "}\n"
@@ -579,9 +584,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.Set$lite$(\n"
+        "  $field_member$.Set$lite$(\n"
         "    $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
         "    $default_variable$, ::std::move(value), GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "}\n"
@@ -591,9 +596,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.Set$lite$($default_variable$,\n"
+        "  $field_member$.Set$lite$($default_variable$,\n"
         "      $string_piece$(value), GetArenaNoVirtual());\n"
         "      $string_piece$(value), GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
         "}\n"
         "}\n"
@@ -603,9 +608,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.Set$lite$(\n"
+        "  $field_member$.Set$lite$(\n"
         "      $default_variable$, $string_piece$(\n"
         "      $default_variable$, $string_piece$(\n"
         "      reinterpret_cast<const char*>(value), size),\n"
         "      reinterpret_cast<const char*>(value), size),\n"
         "      GetArenaNoVirtual());\n"
         "      GetArenaNoVirtual());\n"
@@ -615,9 +620,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  return $oneof_prefix$$name$_.Mutable($default_variable$,\n"
+        "  return $field_member$.Mutable($default_variable$,\n"
         "      GetArenaNoVirtual());\n"
         "      GetArenaNoVirtual());\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "}\n"
         "}\n"
@@ -625,7 +630,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "  if (has_$name$()) {\n"
         "    clear_has_$oneof_name$();\n"
         "    clear_has_$oneof_name$();\n"
-        "    return $oneof_prefix$$name$_.Release($default_variable$,\n"
+        "    return $field_member$.Release($default_variable$,\n"
         "        GetArenaNoVirtual());\n"
         "        GetArenaNoVirtual());\n"
         "  } else {\n"
         "  } else {\n"
         "    return NULL;\n"
         "    return NULL;\n"
@@ -633,12 +638,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "}\n"
         "}\n"
         "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
         "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
         "  clear_$oneof_name$();\n"
         "  clear_$oneof_name$();\n"
         "  if ($name$ != NULL) {\n"
         "  if ($name$ != NULL) {\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n"
+        "    $field_member$.SetAllocated($default_variable$, $name$,\n"
         "        GetArenaNoVirtual());\n"
         "        GetArenaNoVirtual());\n"
         "  }\n"
         "  }\n"
         "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
@@ -649,7 +654,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
         "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
         "  if (has_$name$()) {\n"
         "  if (has_$name$()) {\n"
         "    clear_has_$oneof_name$();\n"
         "    clear_has_$oneof_name$();\n"
-        "    return $oneof_prefix$$name$_.UnsafeArenaRelease(\n"
+        "    return $field_member$.UnsafeArenaRelease(\n"
         "        $default_variable$, GetArenaNoVirtual());\n"
         "        $default_variable$, GetArenaNoVirtual());\n"
         "  } else {\n"
         "  } else {\n"
         "    return NULL;\n"
         "    return NULL;\n"
@@ -659,12 +664,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "::std::string* $name$) {\n"
         "::std::string* $name$) {\n"
         "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
         "  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
         "  clear_$oneof_name$();\n"
         "  clear_$oneof_name$();\n"
         "  if ($name$) {\n"
         "  if ($name$) {\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, "
+        "    $field_member$.UnsafeArenaSetAllocated($default_variable$, "
         "$name$, GetArenaNoVirtual());\n"
         "$name$, GetArenaNoVirtual());\n"
         "  }\n"
         "  }\n"
         "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
         "  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
@@ -677,7 +682,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "inline const ::std::string& $classname$::$name$() const {\n"
         "inline const ::std::string& $classname$::$name$() const {\n"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  // @@protoc_insertion_point(field_get:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "  if (has_$name$()) {\n"
-        "    return $oneof_prefix$$name$_.GetNoArena();\n"
+        "    return $field_member$.GetNoArena();\n"
         "  }\n"
         "  }\n"
         "  return *$default_variable$;\n"
         "  return *$default_variable$;\n"
         "}\n"
         "}\n"
@@ -686,9 +691,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
+        "  $field_member$.SetNoArena($default_variable$, value);\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set:$full_name$)\n"
         "}\n"
         "}\n"
         "#if LANG_CXX11\n"
         "#if LANG_CXX11\n"
@@ -697,10 +702,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.SetNoArena(\n"
-        "    $default_variable$, ::std::move(value));\n"
+        "  $field_member$.SetNoArena($default_variable$, ::std::move(value));\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
         "}\n"
         "}\n"
         "#endif\n"
         "#endif\n"
@@ -709,9 +713,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.SetNoArena($default_variable$,\n"
+        "  $field_member$.SetNoArena($default_variable$,\n"
         "      $string_piece$(value));\n"
         "      $string_piece$(value));\n"
         "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_char:$full_name$)\n"
         "}\n"
         "}\n"
@@ -721,10 +725,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
-        "  $oneof_prefix$$name$_.SetNoArena($default_variable$, "
-        "$string_piece$(\n"
+        "  $field_member$.SetNoArena($default_variable$, $string_piece$(\n"
         "      reinterpret_cast<const char*>(value), size));\n"
         "      reinterpret_cast<const char*>(value), size));\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
         "}\n"
         "}\n"
@@ -732,29 +735,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
         "    clear_$oneof_name$();\n"
         "    clear_$oneof_name$();\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
         "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-        "  return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
+        "  return $field_member$.MutableNoArena($default_variable$);\n"
         "}\n"
         "}\n"
         "inline ::std::string* $classname$::$release_name$() {\n"
         "inline ::std::string* $classname$::$release_name$() {\n"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  // @@protoc_insertion_point(field_release:$full_name$)\n"
         "  if (has_$name$()) {\n"
         "  if (has_$name$()) {\n"
         "    clear_has_$oneof_name$();\n"
         "    clear_has_$oneof_name$();\n"
-        "    return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
+        "    return $field_member$.ReleaseNoArena($default_variable$);\n"
         "  } else {\n"
         "  } else {\n"
         "    return NULL;\n"
         "    return NULL;\n"
         "  }\n"
         "  }\n"
         "}\n"
         "}\n"
         "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
         "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
         "  if (!has_$name$()) {\n"
         "  if (!has_$name$()) {\n"
-        "    $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+        "    $field_member$.UnsafeSetDefault($default_variable$);\n"
         "  }\n"
         "  }\n"
         "  clear_$oneof_name$();\n"
         "  clear_$oneof_name$();\n"
         "  if ($name$ != NULL) {\n"
         "  if ($name$ != NULL) {\n"
         "    set_has_$name$();\n"
         "    set_has_$name$();\n"
-        "    $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n"
-        "        $name$);\n"
+        "    $field_member$.SetAllocatedNoArena($default_variable$, $name$);\n"
         "  }\n"
         "  }\n"
         "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
         "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
         "}\n");
         "}\n");
@@ -765,12 +767,11 @@ void StringOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
     printer->Print(variables_,
-      "$oneof_prefix$$name$_.Destroy($default_variable$,\n"
+      "$field_member$.Destroy($default_variable$,\n"
       "    GetArenaNoVirtual());\n");
       "    GetArenaNoVirtual());\n");
   } else {
   } else {
     printer->Print(variables_,
     printer->Print(variables_,
-      "$oneof_prefix$$name$_."
-      "DestroyNoArena($default_variable$);\n");
+      "$field_member$.DestroyNoArena($default_variable$);\n");
   }
   }
 }
 }
 
 
@@ -796,7 +797,7 @@ void StringOneofFieldGenerator::
 GenerateDestructorCode(io::Printer* printer) const {
 GenerateDestructorCode(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
     "if (has_$name$()) {\n"
     "if (has_$name$()) {\n"
-    "  $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"
+    "  $field_member$.DestroyNoArena($default_variable$);\n"
     "}\n");
     "}\n");
 }
 }
 
 
@@ -912,11 +913,21 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
 
 
 void RepeatedStringFieldGenerator::
 void RepeatedStringFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
 GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+  if (options_.safe_boundary_check) {
+    printer->Print(variables_,
+      "inline const ::std::string& $classname$::$name$(int index) const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $name$_.InternalCheckedGet(\n"
+      "      index, ::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "inline const ::std::string& $classname$::$name$(int index) const {\n"
+      "  // @@protoc_insertion_point(field_get:$full_name$)\n"
+      "  return $name$_.Get(index);\n"
+      "}\n");
+  }
   printer->Print(variables_,
   printer->Print(variables_,
-    "inline const ::std::string& $classname$::$name$(int index) const {\n"
-    "  // @@protoc_insertion_point(field_get:$full_name$)\n"
-    "  return $name$_.$cppget$(index);\n"
-    "}\n"
     "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
     "inline ::std::string* $classname$::mutable_$name$(int index) {\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  return $name$_.Mutable(index);\n"
     "  return $name$_.Mutable(index);\n"
@@ -991,7 +1002,8 @@ GenerateMergingCode(io::Printer* printer) const {
 
 
 void RepeatedStringFieldGenerator::
 void RepeatedStringFieldGenerator::
 GenerateSwappingCode(io::Printer* printer) const {
 GenerateSwappingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n");
+  printer->Print(variables_,
+                 "$name$_.InternalSwap(CastToBase(&other->$name$_));\n");
 }
 }
 
 
 void RepeatedStringFieldGenerator::
 void RepeatedStringFieldGenerator::

+ 2 - 0
src/google/protobuf/compiler/cpp/cpp_string_field.h

@@ -69,6 +69,8 @@ class StringFieldGenerator : public FieldGenerator {
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
 
+  bool MergeFromCodedStreamNeedsArena() const;
+
  protected:
  protected:
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
   std::map<string, string> variables_;
   std::map<string, string> variables_;

+ 23 - 22
src/google/protobuf/compiler/cpp/cpp_unittest.cc

@@ -995,75 +995,76 @@ TEST(GeneratedMessageTest, TestEmbedOptimizedForSize) {
 
 
 TEST(GeneratedMessageTest, TestSpaceUsed) {
 TEST(GeneratedMessageTest, TestSpaceUsed) {
   unittest::TestAllTypes message1;
   unittest::TestAllTypes message1;
-  // sizeof provides a lower bound on SpaceUsed().
-  EXPECT_LE(sizeof(unittest::TestAllTypes), message1.SpaceUsed());
-  const int empty_message_size = message1.SpaceUsed();
+  // sizeof provides a lower bound on SpaceUsedLong().
+  EXPECT_LE(sizeof(unittest::TestAllTypes), message1.SpaceUsedLong());
+  const size_t empty_message_size = message1.SpaceUsedLong();
 
 
   // Setting primitive types shouldn't affect the space used.
   // Setting primitive types shouldn't affect the space used.
   message1.set_optional_int32(123);
   message1.set_optional_int32(123);
   message1.set_optional_int64(12345);
   message1.set_optional_int64(12345);
   message1.set_optional_uint32(123);
   message1.set_optional_uint32(123);
   message1.set_optional_uint64(12345);
   message1.set_optional_uint64(12345);
-  EXPECT_EQ(empty_message_size, message1.SpaceUsed());
+  EXPECT_EQ(empty_message_size, message1.SpaceUsedLong());
 
 
   // On some STL implementations, setting the string to a small value should
   // On some STL implementations, setting the string to a small value should
-  // only increase SpaceUsed() by the size of a string object, though this is
-  // not true everywhere.
+  // only increase SpaceUsedLong() by the size of a string object, though this
+  // is not true everywhere.
   message1.set_optional_string("abc");
   message1.set_optional_string("abc");
-  EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed());
+  EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsedLong());
 
 
   // Setting a string to a value larger than the string object itself should
   // Setting a string to a value larger than the string object itself should
-  // increase SpaceUsed(), because it cannot store the value internally.
+  // increase SpaceUsedLong(), because it cannot store the value internally.
   message1.set_optional_string(string(sizeof(string) + 1, 'x'));
   message1.set_optional_string(string(sizeof(string) + 1, 'x'));
   int min_expected_increase = message1.optional_string().capacity() +
   int min_expected_increase = message1.optional_string().capacity() +
       sizeof(string);
       sizeof(string);
   EXPECT_LE(empty_message_size + min_expected_increase,
   EXPECT_LE(empty_message_size + min_expected_increase,
-            message1.SpaceUsed());
+            message1.SpaceUsedLong());
 
 
-  int previous_size = message1.SpaceUsed();
+  size_t previous_size = message1.SpaceUsedLong();
   // Adding an optional message should increase the size by the size of the
   // Adding an optional message should increase the size by the size of the
   // nested message type. NestedMessage is simple enough (1 int field) that it
   // nested message type. NestedMessage is simple enough (1 int field) that it
   // is equal to sizeof(NestedMessage)
   // is equal to sizeof(NestedMessage)
   message1.mutable_optional_nested_message();
   message1.mutable_optional_nested_message();
   ASSERT_EQ(sizeof(unittest::TestAllTypes::NestedMessage),
   ASSERT_EQ(sizeof(unittest::TestAllTypes::NestedMessage),
-            message1.optional_nested_message().SpaceUsed());
+            message1.optional_nested_message().SpaceUsedLong());
   EXPECT_EQ(previous_size +
   EXPECT_EQ(previous_size +
             sizeof(unittest::TestAllTypes::NestedMessage),
             sizeof(unittest::TestAllTypes::NestedMessage),
-            message1.SpaceUsed());
+            message1.SpaceUsedLong());
 }
 }
 
 
 TEST(GeneratedMessageTest, TestOneofSpaceUsed) {
 TEST(GeneratedMessageTest, TestOneofSpaceUsed) {
   unittest::TestOneof2 message1;
   unittest::TestOneof2 message1;
-  EXPECT_LE(sizeof(unittest::TestOneof2), message1.SpaceUsed());
+  EXPECT_LE(sizeof(unittest::TestOneof2), message1.SpaceUsedLong());
 
 
-  const int empty_message_size = message1.SpaceUsed();
+  const size_t empty_message_size = message1.SpaceUsedLong();
   // Setting primitive types shouldn't affect the space used.
   // Setting primitive types shouldn't affect the space used.
   message1.set_foo_int(123);
   message1.set_foo_int(123);
   message1.set_bar_int(12345);
   message1.set_bar_int(12345);
-  EXPECT_EQ(empty_message_size, message1.SpaceUsed());
+  EXPECT_EQ(empty_message_size, message1.SpaceUsedLong());
 
 
-  // Setting a string in oneof to a small value should only increase SpaceUsed()
-  // by the size of a string object.
+  // Setting a string in oneof to a small value should only increase
+  // SpaceUsedLong() by the size of a string object.
   message1.set_foo_string("abc");
   message1.set_foo_string("abc");
-  EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed());
+  EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsedLong());
 
 
   // Setting a string in oneof to a value larger than the string object itself
   // Setting a string in oneof to a value larger than the string object itself
-  // should increase SpaceUsed(), because it cannot store the value internally.
+  // should increase SpaceUsedLong(), because it cannot store the value
+  // internally.
   message1.set_foo_string(string(sizeof(string) + 1, 'x'));
   message1.set_foo_string(string(sizeof(string) + 1, 'x'));
   int min_expected_increase = message1.foo_string().capacity() +
   int min_expected_increase = message1.foo_string().capacity() +
       sizeof(string);
       sizeof(string);
   EXPECT_LE(empty_message_size + min_expected_increase,
   EXPECT_LE(empty_message_size + min_expected_increase,
-            message1.SpaceUsed());
+            message1.SpaceUsedLong());
 
 
   // Setting a message in oneof should delete the other fields and increase the
   // Setting a message in oneof should delete the other fields and increase the
   // size by the size of the nested message type. NestedMessage is simple enough
   // size by the size of the nested message type. NestedMessage is simple enough
   // that it is equal to sizeof(NestedMessage)
   // that it is equal to sizeof(NestedMessage)
   message1.mutable_foo_message();
   message1.mutable_foo_message();
   ASSERT_EQ(sizeof(unittest::TestOneof2::NestedMessage),
   ASSERT_EQ(sizeof(unittest::TestOneof2::NestedMessage),
-            message1.foo_message().SpaceUsed());
+            message1.foo_message().SpaceUsedLong());
   EXPECT_EQ(empty_message_size +
   EXPECT_EQ(empty_message_size +
             sizeof(unittest::TestOneof2::NestedMessage),
             sizeof(unittest::TestOneof2::NestedMessage),
-            message1.SpaceUsed());
+            message1.SpaceUsedLong());
 }
 }
 
 
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS

+ 1 - 3
src/google/protobuf/compiler/cpp/metadata_test.cc

@@ -72,9 +72,7 @@ class CppMetadataTest : public ::testing::Test {
         TestTempDir();
         TestTempDir();
 
 
     const bool result =
     const bool result =
-        atu::CaptureMetadata(filename, cpp_out,
-                             /* meta_file_suffix */ "", &cli, file,
-                             /* outputs */ NULL);
+        atu::RunProtoCompiler(filename, cpp_out, &cli, file);
 
 
     if (!result) {
     if (!result) {
       return result;
       return result;

+ 15 - 13
src/google/protobuf/compiler/java/java_message.cc

@@ -1259,19 +1259,9 @@ GenerateParsingConstructor(io::Printer* printer) {
   printer->Indent();
   printer->Indent();
 
 
   printer->Print(
   printer->Print(
-    "case 0:\n"  // zero signals EOF / limit reached
-    "  done = true;\n"
-    "  break;\n"
-    "default: {\n"
-    "  if (!parseUnknownField$suffix$(\n"
-    "      input, unknownFields, extensionRegistry, tag)) {\n"
-    "    done = true;\n"  // it's an endgroup tag
-    "  }\n"
-    "  break;\n"
-    "}\n",
-    "suffix",
-    descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ? "Proto3"
-                                                                   : "");
+      "case 0:\n"  // zero signals EOF / limit reached
+      "  done = true;\n"
+      "  break;\n");
 
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = sorted_fields[i];
     const FieldDescriptor* field = sorted_fields[i];
@@ -1309,6 +1299,18 @@ GenerateParsingConstructor(io::Printer* printer) {
     }
     }
   }
   }
 
 
+  printer->Print(
+      "default: {\n"
+      "  if (!parseUnknownField$suffix$(\n"
+      "      input, unknownFields, extensionRegistry, tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n",
+      "suffix",
+      descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ? "Proto3"
+                                                                     : "");
+
   printer->Outdent();
   printer->Outdent();
   printer->Outdent();
   printer->Outdent();
   printer->Print(
   printer->Print(

+ 31 - 31
src/google/protobuf/compiler/java/java_message_lite.cc

@@ -1005,37 +1005,6 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream(
         "  done = true;\n"
         "  done = true;\n"
         "  break;\n");
         "  break;\n");
 
 
-    if (descriptor_->extension_range_count() > 0) {
-      if (descriptor_->options().message_set_wire_format()) {
-        printer->Print(
-            "default: {\n"
-            "  if (!parseUnknownFieldAsMessageSet(\n"
-            "      getDefaultInstanceForType(), input, extensionRegistry,\n"
-            "      tag)) {\n"
-            "    done = true;\n"  // it's an endgroup tag
-            "  }\n"
-            "  break;\n"
-            "}\n");
-      } else {
-        printer->Print(
-            "default: {\n"
-            "  if (!parseUnknownField(getDefaultInstanceForType(),\n"
-            "      input, extensionRegistry, tag)) {\n"
-            "    done = true;\n"  // it's an endgroup tag
-            "  }\n"
-            "  break;\n"
-            "}\n");
-      }
-    } else {
-      printer->Print(
-          "default: {\n"
-          "  if (!parseUnknownField(tag, input)) {\n"
-          "    done = true;\n"  // it's an endgroup tag
-          "  }\n"
-          "  break;\n"
-          "}\n");
-    }
-
     google::protobuf::scoped_array<const FieldDescriptor* > sorted_fields(
     google::protobuf::scoped_array<const FieldDescriptor* > sorted_fields(
         SortFieldsByNumber(descriptor_));
         SortFieldsByNumber(descriptor_));
     for (int i = 0; i < descriptor_->field_count(); i++) {
     for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1073,6 +1042,37 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream(
       }
       }
     }
     }
 
 
+    if (descriptor_->extension_range_count() > 0) {
+      if (descriptor_->options().message_set_wire_format()) {
+        printer->Print(
+            "default: {\n"
+            "  if (!parseUnknownFieldAsMessageSet(\n"
+            "      getDefaultInstanceForType(), input, extensionRegistry,\n"
+            "      tag)) {\n"
+            "    done = true;\n"  // it's an endgroup tag
+            "  }\n"
+            "  break;\n"
+            "}\n");
+      } else {
+        printer->Print(
+            "default: {\n"
+            "  if (!parseUnknownField(getDefaultInstanceForType(),\n"
+            "      input, extensionRegistry, tag)) {\n"
+            "    done = true;\n"  // it's an endgroup tag
+            "  }\n"
+            "  break;\n"
+            "}\n");
+      }
+    } else {
+      printer->Print(
+          "default: {\n"
+          "  if (!parseUnknownField(tag, input)) {\n"
+          "    done = true;\n"  // it's an endgroup tag
+          "  }\n"
+          "  break;\n"
+          "}\n");
+    }
+
     printer->Outdent();
     printer->Outdent();
     printer->Outdent();
     printer->Outdent();
     printer->Print(
     printer->Print(

+ 24 - 11
src/google/protobuf/compiler/js/js_generator.cc

@@ -195,9 +195,9 @@ string ModuleAlias(const string& filename) {
   // We'll worry about this problem if/when we actually see it.  This name isn't
   // We'll worry about this problem if/when we actually see it.  This name isn't
   // exposed to users so we can change it later if we need to.
   // exposed to users so we can change it later if we need to.
   string basename = StripProto(filename);
   string basename = StripProto(filename);
-  StripString(&basename, "-", '$');
-  StripString(&basename, "/", '_');
-  StripString(&basename, ".", '_');
+  ReplaceCharacters(&basename, "-", '$');
+  ReplaceCharacters(&basename, "/", '_');
+  ReplaceCharacters(&basename, ".", '_');
   return basename + "_pb";
   return basename + "_pb";
 }
 }
 
 
@@ -1028,7 +1028,7 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options,
       if (!IsPrimitive(jstype)) {
       if (!IsPrimitive(jstype)) {
         jstype = "!" + jstype;
         jstype = "!" + jstype;
       }
       }
-      jstype = "Array.<" + jstype + ">";
+      jstype = "Array<" + jstype + ">";
     }
     }
   }
   }
 
 
@@ -1558,6 +1558,22 @@ bool GenerateJspbAllowedSet(const GeneratorOptions& options,
   return true;
   return true;
 }
 }
 
 
+// Embeds base64 encoded GeneratedCodeInfo proto in a comment at the end of
+// file.
+void EmbedCodeAnnotations(const GeneratedCodeInfo& annotations,
+                          io::Printer* printer) {
+  // Serialize annotations proto into base64 string.
+  string meta_content;
+  annotations.SerializeToString(&meta_content);
+  string meta_64;
+  Base64Escape(meta_content, &meta_64);
+
+  // Print base64 encoded annotations at the end of output file in
+  // a comment.
+  printer->Print("\n// Below is base64 encoded GeneratedCodeInfo proto");
+  printer->Print("\n// $encoded_proto$\n", "encoded_proto", meta_64);
+}
+
 }  // anonymous namespace
 }  // anonymous namespace
 
 
 void Generator::GenerateHeader(const GeneratorOptions& options,
 void Generator::GenerateHeader(const GeneratorOptions& options,
@@ -2822,7 +2838,7 @@ void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
         "so that it\n"
         "so that it\n"
         " * works in OPTIMIZED mode.\n"
         " * works in OPTIMIZED mode.\n"
         " *\n"
         " *\n"
-        " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n"
+        " * @type {!Object<number, jspb.ExtensionFieldInfo>}\n"
         " */\n"
         " */\n"
         "$class$.extensions = {};\n"
         "$class$.extensions = {};\n"
         "\n",
         "\n",
@@ -2843,7 +2859,7 @@ void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
         "so that it\n"
         "so that it\n"
         " * works in OPTIMIZED mode.\n"
         " * works in OPTIMIZED mode.\n"
         " *\n"
         " *\n"
-        " * @type {!Object.<number, jspb.ExtensionFieldBinaryInfo>}\n"
+        " * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}\n"
         " */\n"
         " */\n"
         "$class$.extensionsBinary = {};\n"
         "$class$.extensionsBinary = {};\n"
         "\n",
         "\n",
@@ -3195,7 +3211,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
       "/**\n"
       "/**\n"
       " * A tuple of {field number, class constructor} for the extension\n"
       " * A tuple of {field number, class constructor} for the extension\n"
       " * field named `$name$`.\n"
       " * field named `$name$`.\n"
-      " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
+      " * @type {!jspb.ExtensionFieldInfo<$extensionType$>}\n"
       " */\n"
       " */\n"
       "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
       "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
       "name", JSObjectFieldName(options, field),
       "name", JSObjectFieldName(options, field),
@@ -3634,10 +3650,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
       }
       }
 
 
       if (options.annotate_code) {
       if (options.annotate_code) {
-        const string meta_file = filename + ".meta";
-        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
-          context->Open(meta_file));
-        annotations.SerializeToZeroCopyStream(info_output.get());
+        EmbedCodeAnnotations(annotations, &printer);
       }
       }
     }
     }
   }
   }

+ 1 - 1
src/google/protobuf/compiler/mock_code_generator.cc

@@ -70,7 +70,7 @@ namespace compiler {
 
 
 // Returns the list of the names of files in all_files in the form of a
 // Returns the list of the names of files in all_files in the form of a
 // comma-separated string.
 // comma-separated string.
-string CommaSeparatedList(const std::vector<const FileDescriptor*> all_files) {
+string CommaSeparatedList(const std::vector<const FileDescriptor*>& all_files) {
   std::vector<string> names;
   std::vector<string> names;
   for (size_t i = 0; i < all_files.size(); i++) {
   for (size_t i = 0; i < all_files.size(); i++) {
     names.push_back(all_files[i]->name());
     names.push_back(all_files[i]->name());

+ 38 - 44
src/google/protobuf/compiler/plugin.pb.cc

@@ -325,13 +325,6 @@ const Version& Version::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Version* Version::New(::google::protobuf::Arena* arena) const {
-  Version* n = new Version;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void Version::Clear() {
 void Version::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.Version)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.Version)
@@ -342,7 +335,7 @@ void Version::Clear() {
   cached_has_bits = _has_bits_[0];
   cached_has_bits = _has_bits_[0];
   if (cached_has_bits & 0x00000001u) {
   if (cached_has_bits & 0x00000001u) {
     GOOGLE_DCHECK(!suffix_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
     GOOGLE_DCHECK(!suffix_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-    (*suffix_.UnsafeRawStringPointer())->clear();
+    suffix_.UnsafeMutablePointer()->clear();
   }
   }
   if (cached_has_bits & 14u) {
   if (cached_has_bits & 14u) {
     ::memset(&major_, 0, static_cast<size_t>(
     ::memset(&major_, 0, static_cast<size_t>(
@@ -723,13 +716,6 @@ const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena) const {
-  CodeGeneratorRequest* n = new CodeGeneratorRequest;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void CodeGeneratorRequest::Clear() {
 void CodeGeneratorRequest::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest)
@@ -743,7 +729,7 @@ void CodeGeneratorRequest::Clear() {
   if (cached_has_bits & 3u) {
   if (cached_has_bits & 3u) {
     if (cached_has_bits & 0x00000001u) {
     if (cached_has_bits & 0x00000001u) {
       GOOGLE_DCHECK(!parameter_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
       GOOGLE_DCHECK(!parameter_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-      (*parameter_.UnsafeRawStringPointer())->clear();
+      parameter_.UnsafeMutablePointer()->clear();
     }
     }
     if (cached_has_bits & 0x00000002u) {
     if (cached_has_bits & 0x00000002u) {
       GOOGLE_DCHECK(compiler_version_ != NULL);
       GOOGLE_DCHECK(compiler_version_ != NULL);
@@ -813,7 +799,8 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream(
       case 15: {
       case 15: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(122u /* 122 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(122u /* 122 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_proto_file()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_proto_file()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -870,14 +857,16 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   // optional .google.protobuf.compiler.Version compiler_version = 3;
   if (cached_has_bits & 0x00000002u) {
   if (cached_has_bits & 0x00000002u) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      3, *this->compiler_version_, output);
+      3, *compiler_version_, output);
   }
   }
 
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->proto_file_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->proto_file_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      15, this->proto_file(static_cast<int>(i)), output);
+      15,
+      this->proto_file(static_cast<int>(i)),
+      output);
   }
   }
 
 
   if (_internal_metadata_.have_unknown_fields()) {
   if (_internal_metadata_.have_unknown_fields()) {
@@ -920,7 +909,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes(
   if (cached_has_bits & 0x00000002u) {
   if (cached_has_bits & 0x00000002u) {
     target = ::google::protobuf::internal::WireFormatLite::
     target = ::google::protobuf::internal::WireFormatLite::
       InternalWriteMessageToArray(
       InternalWriteMessageToArray(
-        3, *this->compiler_version_, deterministic, target);
+        3, *compiler_version_, deterministic, target);
   }
   }
 
 
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
@@ -979,7 +968,7 @@ size_t CodeGeneratorRequest::ByteSizeLong() const {
     if (has_compiler_version()) {
     if (has_compiler_version()) {
       total_size += 1 +
       total_size += 1 +
         ::google::protobuf::internal::WireFormatLite::MessageSize(
         ::google::protobuf::internal::WireFormatLite::MessageSize(
-          *this->compiler_version_);
+          *compiler_version_);
     }
     }
 
 
   }
   }
@@ -1051,8 +1040,8 @@ void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) {
 }
 }
 void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
 void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
   using std::swap;
   using std::swap;
-  file_to_generate_.InternalSwap(&other->file_to_generate_);
-  proto_file_.InternalSwap(&other->proto_file_);
+  file_to_generate_.InternalSwap(CastToBase(&other->file_to_generate_));
+  CastToBase(&proto_file_)->InternalSwap(CastToBase(&other->proto_file_));
   parameter_.Swap(&other->parameter_);
   parameter_.Swap(&other->parameter_);
   swap(compiler_version_, other->compiler_version_);
   swap(compiler_version_, other->compiler_version_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   swap(_has_bits_[0], other->_has_bits_[0]);
@@ -1138,13 +1127,6 @@ const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance()
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf::Arena* arena) const {
-  CodeGeneratorResponse_File* n = new CodeGeneratorResponse_File;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void CodeGeneratorResponse_File::Clear() {
 void CodeGeneratorResponse_File::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File)
@@ -1156,15 +1138,15 @@ void CodeGeneratorResponse_File::Clear() {
   if (cached_has_bits & 7u) {
   if (cached_has_bits & 7u) {
     if (cached_has_bits & 0x00000001u) {
     if (cached_has_bits & 0x00000001u) {
       GOOGLE_DCHECK(!name_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
       GOOGLE_DCHECK(!name_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-      (*name_.UnsafeRawStringPointer())->clear();
+      name_.UnsafeMutablePointer()->clear();
     }
     }
     if (cached_has_bits & 0x00000002u) {
     if (cached_has_bits & 0x00000002u) {
       GOOGLE_DCHECK(!insertion_point_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
       GOOGLE_DCHECK(!insertion_point_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-      (*insertion_point_.UnsafeRawStringPointer())->clear();
+      insertion_point_.UnsafeMutablePointer()->clear();
     }
     }
     if (cached_has_bits & 0x00000004u) {
     if (cached_has_bits & 0x00000004u) {
       GOOGLE_DCHECK(!content_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
       GOOGLE_DCHECK(!content_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-      (*content_.UnsafeRawStringPointer())->clear();
+      content_.UnsafeMutablePointer()->clear();
     }
     }
   }
   }
   _has_bits_.Clear();
   _has_bits_.Clear();
@@ -1518,13 +1500,6 @@ const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* arena) const {
-  CodeGeneratorResponse* n = new CodeGeneratorResponse;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void CodeGeneratorResponse::Clear() {
 void CodeGeneratorResponse::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse)
@@ -1536,7 +1511,7 @@ void CodeGeneratorResponse::Clear() {
   cached_has_bits = _has_bits_[0];
   cached_has_bits = _has_bits_[0];
   if (cached_has_bits & 0x00000001u) {
   if (cached_has_bits & 0x00000001u) {
     GOOGLE_DCHECK(!error_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
     GOOGLE_DCHECK(!error_.IsDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()));
-    (*error_.UnsafeRawStringPointer())->clear();
+    error_.UnsafeMutablePointer()->clear();
   }
   }
   _has_bits_.Clear();
   _has_bits_.Clear();
   _internal_metadata_.Clear();
   _internal_metadata_.Clear();
@@ -1572,7 +1547,8 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream(
       case 15: {
       case 15: {
         if (static_cast< ::google::protobuf::uint8>(tag) ==
         if (static_cast< ::google::protobuf::uint8>(tag) ==
             static_cast< ::google::protobuf::uint8>(122u /* 122 & 0xFF */)) {
             static_cast< ::google::protobuf::uint8>(122u /* 122 & 0xFF */)) {
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_file()));
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(
+                input, add_file()));
         } else {
         } else {
           goto handle_unusual;
           goto handle_unusual;
         }
         }
@@ -1620,7 +1596,9 @@ void CodeGeneratorResponse::SerializeWithCachedSizes(
   for (unsigned int i = 0,
   for (unsigned int i = 0,
       n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
       n = static_cast<unsigned int>(this->file_size()); i < n; i++) {
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
     ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
-      15, this->file(static_cast<int>(i)), output);
+      15,
+      this->file(static_cast<int>(i)),
+      output);
   }
   }
 
 
   if (_internal_metadata_.have_unknown_fields()) {
   if (_internal_metadata_.have_unknown_fields()) {
@@ -1752,7 +1730,7 @@ void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) {
 }
 }
 void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
 void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
   using std::swap;
   using std::swap;
-  file_.InternalSwap(&other->file_);
+  CastToBase(&file_)->InternalSwap(CastToBase(&other->file_));
   error_.Swap(&other->error_);
   error_.Swap(&other->error_);
   swap(_has_bits_[0], other->_has_bits_[0]);
   swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   _internal_metadata_.Swap(&other->_internal_metadata_);
@@ -1769,5 +1747,21 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::compiler::Version* Arena::Create< ::google::protobuf::compiler::Version >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::compiler::Version >(arena);
+}
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::compiler::CodeGeneratorRequest* Arena::Create< ::google::protobuf::compiler::CodeGeneratorRequest >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::compiler::CodeGeneratorRequest >(arena);
+}
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::compiler::CodeGeneratorResponse_File* Arena::Create< ::google::protobuf::compiler::CodeGeneratorResponse_File >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::compiler::CodeGeneratorResponse_File >(arena);
+}
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::compiler::CodeGeneratorResponse* Arena::Create< ::google::protobuf::compiler::CodeGeneratorResponse >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::compiler::CodeGeneratorResponse >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 54 - 29
src/google/protobuf/compiler/plugin.pb.h

@@ -84,6 +84,14 @@ LIBPROTOC_EXPORT extern VersionDefaultTypeInternal _Version_default_instance_;
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOC_EXPORT ::google::protobuf::compiler::CodeGeneratorRequest* Arena::Create< ::google::protobuf::compiler::CodeGeneratorRequest>(Arena*);
+template<> LIBPROTOC_EXPORT ::google::protobuf::compiler::CodeGeneratorResponse* Arena::Create< ::google::protobuf::compiler::CodeGeneratorResponse>(Arena*);
+template<> LIBPROTOC_EXPORT ::google::protobuf::compiler::CodeGeneratorResponse_File* Arena::Create< ::google::protobuf::compiler::CodeGeneratorResponse_File>(Arena*);
+template<> LIBPROTOC_EXPORT ::google::protobuf::compiler::Version* Arena::Create< ::google::protobuf::compiler::Version>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 namespace compiler {
 namespace compiler {
 
 
 // ===================================================================
 // ===================================================================
@@ -139,9 +147,13 @@ class LIBPROTOC_EXPORT Version : public ::google::protobuf::Message /* @@protoc_
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Version* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Version* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Version>(NULL);
+  }
 
 
-  Version* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Version* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<Version>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Version& from);
   void CopyFrom(const Version& from);
@@ -287,9 +299,13 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline CodeGeneratorRequest* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline CodeGeneratorRequest* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorRequest>(NULL);
+  }
 
 
-  CodeGeneratorRequest* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  CodeGeneratorRequest* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorRequest>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const CodeGeneratorRequest& from);
   void CopyFrom(const CodeGeneratorRequest& from);
@@ -351,11 +367,11 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message
   int proto_file_size() const;
   int proto_file_size() const;
   void clear_proto_file();
   void clear_proto_file();
   static const int kProtoFileFieldNumber = 15;
   static const int kProtoFileFieldNumber = 15;
-  const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
   ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
   ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
-  ::google::protobuf::FileDescriptorProto* add_proto_file();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
       mutable_proto_file();
       mutable_proto_file();
+  const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
+  ::google::protobuf::FileDescriptorProto* add_proto_file();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
       proto_file() const;
       proto_file() const;
 
 
@@ -453,9 +469,13 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::M
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline CodeGeneratorResponse_File* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline CodeGeneratorResponse_File* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorResponse_File>(NULL);
+  }
 
 
-  CodeGeneratorResponse_File* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  CodeGeneratorResponse_File* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorResponse_File>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const CodeGeneratorResponse_File& from);
   void CopyFrom(const CodeGeneratorResponse_File& from);
@@ -607,9 +627,13 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline CodeGeneratorResponse* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline CodeGeneratorResponse* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorResponse>(NULL);
+  }
 
 
-  CodeGeneratorResponse* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  CodeGeneratorResponse* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<CodeGeneratorResponse>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const CodeGeneratorResponse& from);
   void CopyFrom(const CodeGeneratorResponse& from);
@@ -651,11 +675,11 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag
   int file_size() const;
   int file_size() const;
   void clear_file();
   void clear_file();
   static const int kFileFieldNumber = 15;
   static const int kFileFieldNumber = 15;
-  const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
   ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
   ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
-  ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
       mutable_file();
       mutable_file();
+  const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
+  ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
   const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
       file() const;
       file() const;
 
 
@@ -973,23 +997,23 @@ inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* paramet
 inline int CodeGeneratorRequest::proto_file_size() const {
 inline int CodeGeneratorRequest::proto_file_size() const {
   return proto_file_.size();
   return proto_file_.size();
 }
 }
-inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
-  return proto_file_.Get(index);
-}
 inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
 inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   return proto_file_.Mutable(index);
   return proto_file_.Mutable(index);
 }
 }
-inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
-  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
-  return proto_file_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
 CodeGeneratorRequest::mutable_proto_file() {
 CodeGeneratorRequest::mutable_proto_file() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   return &proto_file_;
   return &proto_file_;
 }
 }
+inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Get(index);
+}
+inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
+  return proto_file_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
 CodeGeneratorRequest::proto_file() const {
 CodeGeneratorRequest::proto_file() const {
   // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
   // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file)
@@ -1026,7 +1050,8 @@ inline ::google::protobuf::compiler::Version* CodeGeneratorRequest::release_comp
 inline ::google::protobuf::compiler::Version* CodeGeneratorRequest::mutable_compiler_version() {
 inline ::google::protobuf::compiler::Version* CodeGeneratorRequest::mutable_compiler_version() {
   set_has_compiler_version();
   set_has_compiler_version();
   if (compiler_version_ == NULL) {
   if (compiler_version_ == NULL) {
-    compiler_version_ = new ::google::protobuf::compiler::Version;
+    compiler_version_ = ::google::protobuf::Arena::Create< ::google::protobuf::compiler::Version >(
+        GetArenaNoVirtual());
   }
   }
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.compiler_version)
   return compiler_version_;
   return compiler_version_;
@@ -1317,23 +1342,23 @@ inline int CodeGeneratorResponse::file_size() const {
 inline void CodeGeneratorResponse::clear_file() {
 inline void CodeGeneratorResponse::clear_file() {
   file_.Clear();
   file_.Clear();
 }
 }
-inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
-  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
-  return file_.Get(index);
-}
 inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
 inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
   // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file)
   return file_.Mutable(index);
   return file_.Mutable(index);
 }
 }
-inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
-  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
-  return file_.Add();
-}
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
 inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
 CodeGeneratorResponse::mutable_file() {
 CodeGeneratorResponse::mutable_file() {
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
   // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file)
   return &file_;
   return &file_;
 }
 }
+inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Get(index);
+}
+inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
+  // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file)
+  return file_.Add();
+}
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
 inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
 CodeGeneratorResponse::file() const {
 CodeGeneratorResponse::file() const {
   // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)
   // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file)

+ 65 - 47
src/google/protobuf/descriptor.cc

@@ -32,7 +32,10 @@
 //  Based on original Protocol Buffers design by
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 
+#include <algorithm>
+#include <functional>
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/hash.h>
+#include <limits>
 #include <map>
 #include <map>
 #include <memory>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #ifndef _SHARED_PTR_H
@@ -41,8 +44,6 @@
 #include <set>
 #include <set>
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
-#include <algorithm>
-#include <limits>
 
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/logging.h>
@@ -375,15 +376,13 @@ class PrefixRemover {
   string prefix_;
   string prefix_;
 };
 };
 
 
-// A DescriptorPool contains a bunch of hash_maps to implement the
+// A DescriptorPool contains a bunch of hash-maps to implement the
 // various Find*By*() methods.  Since hashtable lookups are O(1), it's
 // various Find*By*() methods.  Since hashtable lookups are O(1), it's
-// most efficient to construct a fixed set of large hash_maps used by
+// most efficient to construct a fixed set of large hash-maps used by
 // all objects in the pool rather than construct one or more small
 // all objects in the pool rather than construct one or more small
-// hash_maps for each object.
+// hash-maps for each object.
 //
 //
-// The keys to these hash_maps are (parent, name) or (parent, number)
-// pairs.  Unfortunately STL doesn't provide hash functions for pair<>,
-// so we must invent our own.
+// The keys to these hash-maps are (parent, name) or (parent, number) pairs.
 //
 //
 // TODO(kenton):  Use StringPiece rather than const char* in keys?  It would
 // TODO(kenton):  Use StringPiece rather than const char* in keys?  It would
 //   be a lot cleaner but we'd just have to convert it back to const char*
 //   be a lot cleaner but we'd just have to convert it back to const char*
@@ -398,6 +397,13 @@ struct PointerStringPairEqual {
   }
   }
 };
 };
 
 
+typedef std::pair<const Descriptor*, int> DescriptorIntPair;
+typedef std::pair<const EnumDescriptor*, int> EnumIntPair;
+
+#define HASH_MAP hash_map
+#define HASH_SET hash_set
+#define HASH_FXN hash
+
 template<typename PairType>
 template<typename PairType>
 struct PointerIntegerPairHash {
 struct PointerIntegerPairHash {
   size_t operator()(const PairType& p) const {
   size_t operator()(const PairType& p) const {
@@ -417,9 +423,6 @@ struct PointerIntegerPairHash {
   }
   }
 };
 };
 
 
-typedef std::pair<const Descriptor*, int> DescriptorIntPair;
-typedef std::pair<const EnumDescriptor*, int> EnumIntPair;
-
 struct PointerStringPairHash {
 struct PointerStringPairHash {
   size_t operator()(const PointerStringPair& p) const {
   size_t operator()(const PointerStringPair& p) const {
     // FIXME(kenton):  What is the best way to compute this hash?  I have
     // FIXME(kenton):  What is the best way to compute this hash?  I have
@@ -445,31 +448,37 @@ struct PointerStringPairHash {
 
 
 const Symbol kNullSymbol;
 const Symbol kNullSymbol;
 
 
-typedef hash_map<const char*, Symbol,
-                 hash<const char*>, streq>
-  SymbolsByNameMap;
-typedef hash_map<PointerStringPair, Symbol,
-                 PointerStringPairHash, PointerStringPairEqual>
-  SymbolsByParentMap;
-typedef hash_map<const char*, const FileDescriptor*,
-                 hash<const char*>, streq>
-  FilesByNameMap;
-typedef hash_map<PointerStringPair, const FieldDescriptor*,
+typedef HASH_MAP<const char*, Symbol, HASH_FXN<const char*>, streq>
+    SymbolsByNameMap;
+
+typedef HASH_MAP<PointerStringPair, Symbol, PointerStringPairHash,
+                 PointerStringPairEqual>
+    SymbolsByParentMap;
+
+typedef HASH_MAP<const char*, const FileDescriptor*, HASH_FXN<const char*>,
+                 streq>
+    FilesByNameMap;
+
+typedef HASH_MAP<PointerStringPair, const FieldDescriptor*,
                  PointerStringPairHash, PointerStringPairEqual>
                  PointerStringPairHash, PointerStringPairEqual>
-  FieldsByNameMap;
-typedef hash_map<DescriptorIntPair, const FieldDescriptor*,
-                 PointerIntegerPairHash<DescriptorIntPair> >
-  FieldsByNumberMap;
-typedef hash_map<EnumIntPair, const EnumValueDescriptor*,
-                 PointerIntegerPairHash<EnumIntPair> >
-  EnumValuesByNumberMap;
-// This is a map rather than a hash_map, since we use it to iterate
+    FieldsByNameMap;
+
+typedef HASH_MAP<DescriptorIntPair, const FieldDescriptor*,
+                 PointerIntegerPairHash<DescriptorIntPair>,
+                 std::equal_to<DescriptorIntPair> >
+    FieldsByNumberMap;
+
+typedef HASH_MAP<EnumIntPair, const EnumValueDescriptor*,
+                 PointerIntegerPairHash<EnumIntPair>,
+                 std::equal_to<EnumIntPair> >
+    EnumValuesByNumberMap;
+// This is a map rather than a hash-map, since we use it to iterate
 // through all the extensions that extend a given Descriptor, and an
 // through all the extensions that extend a given Descriptor, and an
 // ordered data structure that implements lower_bound is convenient
 // ordered data structure that implements lower_bound is convenient
 // for that.
 // for that.
 typedef std::map<DescriptorIntPair, const FieldDescriptor*>
 typedef std::map<DescriptorIntPair, const FieldDescriptor*>
   ExtensionsGroupedByDescriptorMap;
   ExtensionsGroupedByDescriptorMap;
-typedef hash_map<string, const SourceCodeInfo_Location*> LocationsByPathMap;
+typedef HASH_MAP<string, const SourceCodeInfo_Location*> LocationsByPathMap;
 
 
 std::set<string>* allowed_proto3_extendees_ = NULL;
 std::set<string>* allowed_proto3_extendees_ = NULL;
 GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_);
 GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_);
@@ -564,17 +573,17 @@ class DescriptorPool::Tables {
   // execution of the current public API call, but for compatibility with
   // execution of the current public API call, but for compatibility with
   // legacy clients, this is cleared at the beginning of each public API call.
   // legacy clients, this is cleared at the beginning of each public API call.
   // Not used when fallback_database_ == NULL.
   // Not used when fallback_database_ == NULL.
-  hash_set<string> known_bad_files_;
+  HASH_SET<string> known_bad_files_;
 
 
   // A set of symbols which we have tried to load from the fallback database
   // A set of symbols which we have tried to load from the fallback database
   // and encountered errors. We will not attempt to load them again during
   // and encountered errors. We will not attempt to load them again during
   // execution of the current public API call, but for compatibility with
   // execution of the current public API call, but for compatibility with
   // legacy clients, this is cleared at the beginning of each public API call.
   // legacy clients, this is cleared at the beginning of each public API call.
-  hash_set<string> known_bad_symbols_;
+  HASH_SET<string> known_bad_symbols_;
 
 
   // The set of descriptors for which we've already loaded the full
   // The set of descriptors for which we've already loaded the full
   // set of extensions numbers from fallback_database_.
   // set of extensions numbers from fallback_database_.
-  hash_set<const Descriptor*> extensions_loaded_from_db_;
+  HASH_SET<const Descriptor*> extensions_loaded_from_db_;
 
 
   // -----------------------------------------------------------------
   // -----------------------------------------------------------------
   // Finding items.
   // Finding items.
@@ -787,14 +796,13 @@ class FileDescriptorTables {
 };
 };
 
 
 DescriptorPool::Tables::Tables()
 DescriptorPool::Tables::Tables()
-    // Start some hash_map and hash_set objects with a small # of buckets
+    // Start some hash-map and hash-set objects with a small # of buckets
     : known_bad_files_(3),
     : known_bad_files_(3),
       known_bad_symbols_(3),
       known_bad_symbols_(3),
       extensions_loaded_from_db_(3),
       extensions_loaded_from_db_(3),
       symbols_by_name_(3),
       symbols_by_name_(3),
       files_by_name_(3) {}
       files_by_name_(3) {}
 
 
-
 DescriptorPool::Tables::~Tables() {
 DescriptorPool::Tables::~Tables() {
   GOOGLE_DCHECK(checkpoints_.empty());
   GOOGLE_DCHECK(checkpoints_.empty());
   // Note that the deletion order is important, since the destructors of some
   // Note that the deletion order is important, since the destructors of some
@@ -948,8 +956,10 @@ inline Symbol FileDescriptorTables::FindNestedSymbolOfType(
 Symbol DescriptorPool::Tables::FindByNameHelper(
 Symbol DescriptorPool::Tables::FindByNameHelper(
     const DescriptorPool* pool, const string& name) {
     const DescriptorPool* pool, const string& name) {
   MutexLockMaybe lock(pool->mutex_);
   MutexLockMaybe lock(pool->mutex_);
-  known_bad_symbols_.clear();
-  known_bad_files_.clear();
+  if (pool->fallback_database_ != NULL) {
+    known_bad_symbols_.clear();
+    known_bad_files_.clear();
+  }
   Symbol result = FindSymbol(name);
   Symbol result = FindSymbol(name);
 
 
   if (result.IsNull() && pool->underlay_ != NULL) {
   if (result.IsNull() && pool->underlay_ != NULL) {
@@ -1403,8 +1413,10 @@ void DescriptorPool::InternalAddGeneratedFile(
 
 
 const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
 const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
   MutexLockMaybe lock(mutex_);
   MutexLockMaybe lock(mutex_);
-  tables_->known_bad_symbols_.clear();
-  tables_->known_bad_files_.clear();
+  if (fallback_database_ != NULL) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
   const FileDescriptor* result = tables_->FindFile(name);
   const FileDescriptor* result = tables_->FindFile(name);
   if (result != NULL) return result;
   if (result != NULL) return result;
   if (underlay_ != NULL) {
   if (underlay_ != NULL) {
@@ -1421,8 +1433,10 @@ const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
 const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
 const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
     const string& symbol_name) const {
     const string& symbol_name) const {
   MutexLockMaybe lock(mutex_);
   MutexLockMaybe lock(mutex_);
-  tables_->known_bad_symbols_.clear();
-  tables_->known_bad_files_.clear();
+  if (fallback_database_ != NULL) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
   Symbol result = tables_->FindSymbol(symbol_name);
   Symbol result = tables_->FindSymbol(symbol_name);
   if (!result.IsNull()) return result.GetFile();
   if (!result.IsNull()) return result.GetFile();
   if (underlay_ != NULL) {
   if (underlay_ != NULL) {
@@ -1508,8 +1522,10 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
     }
     }
   }
   }
   MutexLockMaybe lock(mutex_);
   MutexLockMaybe lock(mutex_);
-  tables_->known_bad_symbols_.clear();
-  tables_->known_bad_files_.clear();
+  if (fallback_database_ != NULL) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
   const FieldDescriptor* result = tables_->FindExtension(extendee, number);
   const FieldDescriptor* result = tables_->FindExtension(extendee, number);
   if (result != NULL) {
   if (result != NULL) {
     return result;
     return result;
@@ -1531,8 +1547,10 @@ void DescriptorPool::FindAllExtensions(
     const Descriptor* extendee,
     const Descriptor* extendee,
     std::vector<const FieldDescriptor*>* out) const {
     std::vector<const FieldDescriptor*>* out) const {
   MutexLockMaybe lock(mutex_);
   MutexLockMaybe lock(mutex_);
-  tables_->known_bad_symbols_.clear();
-  tables_->known_bad_files_.clear();
+  if (fallback_database_ != NULL) {
+    tables_->known_bad_symbols_.clear();
+    tables_->known_bad_files_.clear();
+  }
 
 
   // Initialize tables_->extensions_ from the fallback database first
   // Initialize tables_->extensions_ from the fallback database first
   // (but do this only once per descriptor).
   // (but do this only once per descriptor).
@@ -4539,7 +4557,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
     }
     }
   }
   }
 
 
-  hash_set<string> reserved_name_set;
+  HASH_SET<string> reserved_name_set;
   for (int i = 0; i < proto.reserved_name_size(); i++) {
   for (int i = 0; i < proto.reserved_name_size(); i++) {
     const string& name = proto.reserved_name(i);
     const string& name = proto.reserved_name(i);
     if (reserved_name_set.find(name) == reserved_name_set.end()) {
     if (reserved_name_set.find(name) == reserved_name_set.end()) {
@@ -5125,7 +5143,7 @@ void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
     }
     }
   }
   }
 
 
-  hash_set<string> reserved_name_set;
+  HASH_SET<string> reserved_name_set;
   for (int i = 0; i < proto.reserved_name_size(); i++) {
   for (int i = 0; i < proto.reserved_name_size(); i++) {
     const string& name = proto.reserved_name(i);
     const string& name = proto.reserved_name(i);
     if (reserved_name_set.find(name) == reserved_name_set.end()) {
     if (reserved_name_set.find(name) == reserved_name_set.end()) {

Diff do ficheiro suprimidas por serem muito extensas
+ 143 - 176
src/google/protobuf/descriptor.pb.cc


Diff do ficheiro suprimidas por serem muito extensas
+ 263 - 154
src/google/protobuf/descriptor.pb.h


+ 3 - 0
src/google/protobuf/descriptor_unittest.cc

@@ -431,6 +431,7 @@ TEST_F(FileDescriptorTest, FindExtensionByNumber) {
   EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == NULL);
   EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == NULL);
 }
 }
 
 
+
 TEST_F(FileDescriptorTest, BuildAgain) {
 TEST_F(FileDescriptorTest, BuildAgain) {
   // Test that if te call BuildFile again on the same input we get the same
   // Test that if te call BuildFile again on the same input we get the same
   // FileDescriptor back.
   // FileDescriptor back.
@@ -973,6 +974,7 @@ TEST_F(DescriptorTest, FieldEnumType) {
   EXPECT_EQ(enum_, bar_->enum_type());
   EXPECT_EQ(enum_, bar_->enum_type());
 }
 }
 
 
+
 // ===================================================================
 // ===================================================================
 
 
 // Test simple flat messages and fields.
 // Test simple flat messages and fields.
@@ -1943,6 +1945,7 @@ TEST_F(ExtensionDescriptorTest, FindAllExtensions) {
   EXPECT_EQ(39, extensions[3]->number());
   EXPECT_EQ(39, extensions[3]->number());
 }
 }
 
 
+
 TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
 TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) {
   DescriptorPool pool;
   DescriptorPool pool;
   FileDescriptorProto file_proto;
   FileDescriptorProto file_proto;

+ 7 - 3
src/google/protobuf/duration.pb.cc

@@ -191,9 +191,6 @@ const Duration& Duration::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Duration* Duration::New(::google::protobuf::Arena* arena) const {
-  return ::google::protobuf::Arena::CreateMessage<Duration>(arena);
-}
 
 
 void Duration::Clear() {
 void Duration::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Duration)
@@ -427,5 +424,12 @@ void Duration::InternalSwap(Duration* other) {
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Duration* Arena::CreateMessage< ::google::protobuf::Duration >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::google::protobuf::Duration >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 11 - 2
src/google/protobuf/duration.pb.h

@@ -57,6 +57,11 @@ LIBPROTOBUF_EXPORT extern DurationDefaultTypeInternal _Duration_default_instance
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Duration* Arena::CreateMessage< ::google::protobuf::Duration>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -111,9 +116,13 @@ class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message /* @@prot
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Duration* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Duration* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::CreateMessage<Duration>(NULL);
+  }
 
 
-  Duration* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Duration* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::CreateMessage<Duration>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Duration& from);
   void CopyFrom(const Duration& from);

+ 44 - 34
src/google/protobuf/dynamic_message.cc

@@ -263,7 +263,7 @@ class DynamicMessage : public Message {
 
 
   Message* New() const;
   Message* New() const;
   Message* New(::google::protobuf::Arena* arena) const;
   Message* New(::google::protobuf::Arena* arena) const;
-  ::google::protobuf::Arena* GetArena() const { return NULL; };
+  ::google::protobuf::Arena* GetArena() const { return arena_; }
 
 
   int GetCachedSize() const;
   int GetCachedSize() const;
   void SetCachedSize(int size) const;
   void SetCachedSize(int size) const;
@@ -282,7 +282,6 @@ class DynamicMessage : public Message {
 #endif  // !_MSC_VER
 #endif  // !_MSC_VER
 
 
  private:
  private:
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
   DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena);
   DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena);
 
 
   void SharedCtor(bool lock_factory);
   void SharedCtor(bool lock_factory);
@@ -302,25 +301,25 @@ class DynamicMessage : public Message {
   }
   }
 
 
   const TypeInfo* type_info_;
   const TypeInfo* type_info_;
+  Arena* const arena_;
   // TODO(kenton):  Make this an atomic<int> when C++ supports it.
   // TODO(kenton):  Make this an atomic<int> when C++ supports it.
   mutable int cached_byte_size_;
   mutable int cached_byte_size_;
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
 };
 };
 
 
 DynamicMessage::DynamicMessage(const TypeInfo* type_info)
 DynamicMessage::DynamicMessage(const TypeInfo* type_info)
-  : type_info_(type_info),
-    cached_byte_size_(0) {
+    : type_info_(type_info), arena_(NULL), cached_byte_size_(0) {
   SharedCtor(true);
   SharedCtor(true);
 }
 }
 
 
 DynamicMessage::DynamicMessage(const TypeInfo* type_info,
 DynamicMessage::DynamicMessage(const TypeInfo* type_info,
                                ::google::protobuf::Arena* arena)
                                ::google::protobuf::Arena* arena)
-  : type_info_(type_info),
-    cached_byte_size_(0) {
+    : type_info_(type_info), arena_(arena), cached_byte_size_(0) {
   SharedCtor(true);
   SharedCtor(true);
 }
 }
 
 
 DynamicMessage::DynamicMessage(const TypeInfo* type_info, bool lock_factory)
 DynamicMessage::DynamicMessage(const TypeInfo* type_info, bool lock_factory)
-    : type_info_(type_info), cached_byte_size_(0) {
+    : type_info_(type_info), arena_(NULL), cached_byte_size_(0) {
   SharedCtor(lock_factory);
   SharedCtor(lock_factory);
 }
 }
 
 
@@ -342,10 +341,10 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
   }
   }
 
 
   new (OffsetToPointer(type_info_->internal_metadata_offset))
   new (OffsetToPointer(type_info_->internal_metadata_offset))
-      InternalMetadataWithArena;
+      InternalMetadataWithArena(arena_);
 
 
   if (type_info_->extensions_offset != -1) {
   if (type_info_->extensions_offset != -1) {
-    new (OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
+    new (OffsetToPointer(type_info_->extensions_offset)) ExtensionSet(arena_);
   }
   }
   for (int i = 0; i < descriptor->field_count(); i++) {
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor* field = descriptor->field(i);
     const FieldDescriptor* field = descriptor->field(i);
@@ -354,14 +353,14 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
       continue;
       continue;
     }
     }
     switch (field->cpp_type()) {
     switch (field->cpp_type()) {
-#define HANDLE_TYPE(CPPTYPE, TYPE)                                           \
-      case FieldDescriptor::CPPTYPE_##CPPTYPE:                               \
-        if (!field->is_repeated()) {                                         \
-          new(field_ptr) TYPE(field->default_value_##TYPE());                \
-        } else {                                                             \
-          new(field_ptr) RepeatedField<TYPE>();                              \
-        }                                                                    \
-        break;
+#define HANDLE_TYPE(CPPTYPE, TYPE)                         \
+  case FieldDescriptor::CPPTYPE_##CPPTYPE:                 \
+    if (!field->is_repeated()) {                           \
+      new (field_ptr) TYPE(field->default_value_##TYPE()); \
+    } else {                                               \
+      new (field_ptr) RepeatedField<TYPE>(arena_);         \
+    }                                                      \
+    break;
 
 
       HANDLE_TYPE(INT32 , int32 );
       HANDLE_TYPE(INT32 , int32 );
       HANDLE_TYPE(INT64 , int64 );
       HANDLE_TYPE(INT64 , int64 );
@@ -376,7 +375,7 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
         if (!field->is_repeated()) {
         if (!field->is_repeated()) {
           new(field_ptr) int(field->default_value_enum()->number());
           new(field_ptr) int(field->default_value_enum()->number());
         } else {
         } else {
-          new(field_ptr) RepeatedField<int>();
+          new (field_ptr) RepeatedField<int>(arena_);
         }
         }
         break;
         break;
 
 
@@ -397,7 +396,7 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
               ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr();
               ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr();
               asp->UnsafeSetDefault(default_value);
               asp->UnsafeSetDefault(default_value);
             } else {
             } else {
-              new(field_ptr) RepeatedPtrField<string>();
+              new (field_ptr) RepeatedPtrField<string>(arena_);
             }
             }
             break;
             break;
         }
         }
@@ -412,15 +411,28 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
             // when the constructor is called inside GetPrototype(), in which
             // when the constructor is called inside GetPrototype(), in which
             // case we have already locked the factory.
             // case we have already locked the factory.
             if (lock_factory) {
             if (lock_factory) {
-              new (field_ptr) DynamicMapField(
-                  type_info_->factory->GetPrototype(field->message_type()));
+              if (arena_ != NULL) {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()),
+                    arena_);
+              } else {
+                new (field_ptr) DynamicMapField(
+                    type_info_->factory->GetPrototype(field->message_type()));
+              }
             } else {
             } else {
-              new (field_ptr)
-                  DynamicMapField(type_info_->factory->GetPrototypeNoLock(
-                      field->message_type()));
+              if (arena_ != NULL) {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                                        field->message_type()),
+                                    arena_);
+              } else {
+                new (field_ptr)
+                    DynamicMapField(type_info_->factory->GetPrototypeNoLock(
+                        field->message_type()));
+              }
             }
             }
           } else {
           } else {
-            new (field_ptr) RepeatedPtrField<Message>();
+            new (field_ptr) RepeatedPtrField<Message>(arena_);
           }
           }
         }
         }
         break;
         break;
@@ -568,19 +580,17 @@ void DynamicMessage::CrossLinkPrototypes() {
   }
   }
 }
 }
 
 
-Message* DynamicMessage::New() const {
-  void* new_base = operator new(type_info_->size);
-  memset(new_base, 0, type_info_->size);
-  return new(new_base) DynamicMessage(type_info_);
-}
+Message* DynamicMessage::New() const { return New(NULL); }
 
 
 Message* DynamicMessage::New(::google::protobuf::Arena* arena) const {
 Message* DynamicMessage::New(::google::protobuf::Arena* arena) const {
   if (arena != NULL) {
   if (arena != NULL) {
-    Message* message = New();
-    arena->Own(message);
-    return message;
+    void* new_base = Arena::CreateArray<char>(arena, type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_, arena);
   } else {
   } else {
-    return New();
+    void* new_base = operator new(type_info_->size);
+    memset(new_base, 0, type_info_->size);
+    return new (new_base) DynamicMessage(type_info_);
   }
   }
 }
 }
 
 

+ 51 - 17
src/google/protobuf/dynamic_message_unittest.cc

@@ -60,7 +60,7 @@
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
 
 
-class DynamicMessageTest : public testing::Test {
+class DynamicMessageTest : public ::testing::TestWithParam<bool> {
  protected:
  protected:
   DescriptorPool pool_;
   DescriptorPool pool_;
   DynamicMessageFactory factory_;
   DynamicMessageFactory factory_;
@@ -144,38 +144,54 @@ TEST_F(DynamicMessageTest, Defaults) {
   reflection_tester.ExpectClearViaReflection(*prototype_);
   reflection_tester.ExpectClearViaReflection(*prototype_);
 }
 }
 
 
-TEST_F(DynamicMessageTest, IndependentOffsets) {
+TEST_P(DynamicMessageTest, IndependentOffsets) {
   // Check that all fields have independent offsets by setting each
   // Check that all fields have independent offsets by setting each
   // one to a unique value then checking that they all still have those
   // one to a unique value then checking that they all still have those
   // unique values (i.e. they don't stomp each other).
   // unique values (i.e. they don't stomp each other).
-  google::protobuf::scoped_ptr<Message> message(prototype_->New());
+  Arena arena;
+  Message* message = prototype_->New(GetParam()? &arena : NULL);
   TestUtil::ReflectionTester reflection_tester(descriptor_);
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
 
-  reflection_tester.SetAllFieldsViaReflection(message.get());
+  reflection_tester.SetAllFieldsViaReflection(message);
   reflection_tester.ExpectAllFieldsSetViaReflection(*message);
   reflection_tester.ExpectAllFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
 }
 }
 
 
-TEST_F(DynamicMessageTest, Extensions) {
+TEST_P(DynamicMessageTest, Extensions) {
   // Check that extensions work.
   // Check that extensions work.
-  google::protobuf::scoped_ptr<Message> message(extensions_prototype_->New());
+  Arena arena;
+  Message* message = extensions_prototype_->New(GetParam()? &arena : NULL);
   TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
   TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
 
 
-  reflection_tester.SetAllFieldsViaReflection(message.get());
+  reflection_tester.SetAllFieldsViaReflection(message);
   reflection_tester.ExpectAllFieldsSetViaReflection(*message);
   reflection_tester.ExpectAllFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
 }
 }
 
 
-TEST_F(DynamicMessageTest, PackedFields) {
+TEST_P(DynamicMessageTest, PackedFields) {
   // Check that packed fields work properly.
   // Check that packed fields work properly.
-  google::protobuf::scoped_ptr<Message> message(packed_prototype_->New());
+  Arena arena;
+  Message* message = packed_prototype_->New(GetParam()? &arena : NULL);
   TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
   TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
 
 
-  reflection_tester.SetPackedFieldsViaReflection(message.get());
+  reflection_tester.SetPackedFieldsViaReflection(message);
   reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
   reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
 }
 }
 
 
-TEST_F(DynamicMessageTest, Oneof) {
+TEST_P(DynamicMessageTest, Oneof) {
   // Check that oneof fields work properly.
   // Check that oneof fields work properly.
-  google::protobuf::scoped_ptr<Message> message(oneof_prototype_->New());
+  Arena arena;
+  Message* message = oneof_prototype_->New(GetParam()? &arena : NULL);
 
 
   // Check default values.
   // Check default values.
   const Descriptor* descriptor = message->GetDescriptor();
   const Descriptor* descriptor = message->GetDescriptor();
@@ -226,29 +242,46 @@ TEST_F(DynamicMessageTest, Oneof) {
 
 
   // Check set functions.
   // Check set functions.
   TestUtil::ReflectionTester reflection_tester(oneof_descriptor_);
   TestUtil::ReflectionTester reflection_tester(oneof_descriptor_);
-  reflection_tester.SetOneofViaReflection(message.get());
+  reflection_tester.SetOneofViaReflection(message);
   reflection_tester.ExpectOneofSetViaReflection(*message);
   reflection_tester.ExpectOneofSetViaReflection(*message);
+
+  if (!GetParam()) {
+    delete message;
+  }
 }
 }
 
 
-TEST_F(DynamicMessageTest, SpaceUsed) {
+TEST_P(DynamicMessageTest, SpaceUsed) {
   // Test that SpaceUsed() works properly
   // Test that SpaceUsed() works properly
 
 
   // Since we share the implementation with generated messages, we don't need
   // Since we share the implementation with generated messages, we don't need
   // to test very much here.  Just make sure it appears to be working.
   // to test very much here.  Just make sure it appears to be working.
 
 
-  google::protobuf::scoped_ptr<Message> message(prototype_->New());
+  Arena arena;
+  Message* message = prototype_->New(GetParam()? &arena : NULL);
   TestUtil::ReflectionTester reflection_tester(descriptor_);
   TestUtil::ReflectionTester reflection_tester(descriptor_);
 
 
   int initial_space_used = message->SpaceUsed();
   int initial_space_used = message->SpaceUsed();
 
 
-  reflection_tester.SetAllFieldsViaReflection(message.get());
+  reflection_tester.SetAllFieldsViaReflection(message);
   EXPECT_LT(initial_space_used, message->SpaceUsed());
   EXPECT_LT(initial_space_used, message->SpaceUsed());
+
+  if (!GetParam()) {
+    delete message;
+  }
 }
 }
 
 
 TEST_F(DynamicMessageTest, Arena) {
 TEST_F(DynamicMessageTest, Arena) {
   Arena arena;
   Arena arena;
   Message* message = prototype_->New(&arena);
   Message* message = prototype_->New(&arena);
-  (void)message;  // avoid unused-variable error.
+  Message* extension_message = extensions_prototype_->New(&arena);
+  Message* packed_message = packed_prototype_->New(&arena);
+  Message* oneof_message = oneof_prototype_->New(&arena);
+
+  // avoid unused-variable error.
+  (void)message;
+  (void)extension_message;
+  (void)packed_message;
+  (void)oneof_message;
   // Return without freeing: should not leak.
   // Return without freeing: should not leak.
 }
 }
 
 
@@ -286,6 +319,7 @@ TEST_F(DynamicMessageTest, Proto3) {
   delete message;
   delete message;
 }
 }
 
 
+INSTANTIATE_TEST_CASE_P(UseArena, DynamicMessageTest, ::testing::Bool());
 
 
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google

+ 7 - 3
src/google/protobuf/empty.pb.cc

@@ -180,9 +180,6 @@ const Empty& Empty::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-Empty* Empty::New(::google::protobuf::Arena* arena) const {
-  return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
-}
 
 
 void Empty::Clear() {
 void Empty::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Empty)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.Empty)
@@ -338,5 +335,12 @@ void Empty::InternalSwap(Empty* other) {
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::Empty* Arena::CreateMessage< ::google::protobuf::Empty >(Arena* arena) {
+  return Arena::CreateMessageInternal< ::google::protobuf::Empty >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 11 - 2
src/google/protobuf/empty.pb.h

@@ -57,6 +57,11 @@ LIBPROTOBUF_EXPORT extern EmptyDefaultTypeInternal _Empty_default_instance_;
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::Empty* Arena::CreateMessage< ::google::protobuf::Empty>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -111,9 +116,13 @@ class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message /* @@protoc_
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline Empty* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline Empty* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::CreateMessage<Empty>(NULL);
+  }
 
 
-  Empty* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  Empty* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::CreateMessage<Empty>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const Empty& from);
   void CopyFrom(const Empty& from);

+ 12 - 4
src/google/protobuf/extension_set.cc

@@ -33,6 +33,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 
 #include <google/protobuf/stubs/hash.h>
 #include <google/protobuf/stubs/hash.h>
+#include <utility>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/stubs/once.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/extension_set.h>
@@ -750,8 +751,10 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
 
 
   // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
   // RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
   // allocate an abstract object, so we have to be tricky.
   // allocate an abstract object, so we have to be tricky.
-  MessageLite* result = extension->repeated_message_value
-      ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+  MessageLite* result =
+      reinterpret_cast< ::google::protobuf::internal::RepeatedPtrFieldBase*>(
+          extension->repeated_message_value)
+          ->AddFromCleared<GenericTypeHandler<MessageLite> >();
   if (result == NULL) {
   if (result == NULL) {
     result = prototype.New(arena_);
     result = prototype.New(arena_);
     extension->repeated_message_value->AddAllocated(result);
     extension->repeated_message_value->AddAllocated(result);
@@ -925,8 +928,10 @@ void ExtensionSet::InternalExtensionMergeFrom(
             other_extension.repeated_message_value;
             other_extension.repeated_message_value;
         for (int i = 0; i < other_repeated_message->size(); i++) {
         for (int i = 0; i < other_repeated_message->size(); i++) {
           const MessageLite& other_message = other_repeated_message->Get(i);
           const MessageLite& other_message = other_repeated_message->Get(i);
-          MessageLite* target = extension->repeated_message_value
-                   ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+          MessageLite* target =
+              reinterpret_cast< ::google::protobuf::internal::RepeatedPtrFieldBase*>(
+                  extension->repeated_message_value)
+                  ->AddFromCleared<GenericTypeHandler<MessageLite> >();
           if (target == NULL) {
           if (target == NULL) {
             target = other_message.New(arena_);
             target = other_message.New(arena_);
             extension->repeated_message_value->AddAllocated(target);
             extension->repeated_message_value->AddAllocated(target);
@@ -1747,6 +1752,9 @@ void ExtensionSet::Extension::Free() {
 // Defined in extension_set_heavy.cc.
 // Defined in extension_set_heavy.cc.
 // int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
 // int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
 
 
+// Dummy key method to avoid weak vtable.
+void ExtensionSet::LazyMessageExtension::UnusedKeyMethod() {}
+
 // ==================================================================
 // ==================================================================
 // Default repeated field instances for iterator-compatible accessors
 // Default repeated field instances for iterator-compatible accessors
 
 

+ 2 - 0
src/google/protobuf/extension_set.h

@@ -483,6 +483,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
     }
     }
 
 
    private:
    private:
+    virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
+
     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
   };
   };
   struct Extension {
   struct Extension {

+ 7 - 3
src/google/protobuf/extension_set_heavy.cc

@@ -259,8 +259,10 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
 
 
   // RepeatedPtrField<Message> does not know how to Add() since it cannot
   // RepeatedPtrField<Message> does not know how to Add() since it cannot
   // allocate an abstract object, so we have to be tricky.
   // allocate an abstract object, so we have to be tricky.
-  MessageLite* result = extension->repeated_message_value
-      ->AddFromCleared<GenericTypeHandler<MessageLite> >();
+  MessageLite* result =
+      reinterpret_cast< ::google::protobuf::internal::RepeatedPtrFieldBase*>(
+          extension->repeated_message_value)
+          ->AddFromCleared<GenericTypeHandler<MessageLite> >();
   if (result == NULL) {
   if (result == NULL) {
     const MessageLite* prototype;
     const MessageLite* prototype;
     if (extension->repeated_message_value->size() == 0) {
     if (extension->repeated_message_value->size() == 0) {
@@ -391,7 +393,9 @@ size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const {
         // type handler.
         // type handler.
         total_size +=
         total_size +=
             sizeof(*repeated_message_value) +
             sizeof(*repeated_message_value) +
-            RepeatedMessage_SpaceUsedExcludingSelfLong(repeated_message_value);
+            RepeatedMessage_SpaceUsedExcludingSelfLong(
+                reinterpret_cast< ::google::protobuf::internal::RepeatedPtrFieldBase*>(
+                    repeated_message_value));
         break;
         break;
     }
     }
   } else {
   } else {

+ 7 - 2
src/google/protobuf/extension_set_unittest.cc

@@ -792,11 +792,16 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
     message.AddExtension(unittest::repeated_##type##_extension, value);        \
     message.AddExtension(unittest::repeated_##type##_extension, value);        \
     EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type;        \
     EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type;        \
     message.ClearExtension(unittest::repeated_##type##_extension);             \
     message.ClearExtension(unittest::repeated_##type##_extension);             \
+    const int old_capacity =                                                   \
+        message.GetRepeatedExtension(unittest::repeated_##type##_extension)    \
+        .Capacity();                                                           \
+    EXPECT_GE(old_capacity, kMinRepeatedFieldAllocationSize);                  \
     for (int i = 0; i < 16; ++i) {                                             \
     for (int i = 0; i < 16; ++i) {                                             \
       message.AddExtension(unittest::repeated_##type##_extension, value);      \
       message.AddExtension(unittest::repeated_##type##_extension, value);      \
     }                                                                          \
     }                                                                          \
-    int expected_size = sizeof(cpptype) * (16 -                                \
-        kMinRepeatedFieldAllocationSize) + empty_repeated_field_size;          \
+    int expected_size = sizeof(cpptype) *                                      \
+        (message.GetRepeatedExtension(unittest::repeated_##type##_extension)   \
+         .Capacity() - old_capacity) + empty_repeated_field_size;              \
     EXPECT_LE(expected_size, message.SpaceUsed()) << #type;                    \
     EXPECT_LE(expected_size, message.SpaceUsed()) << #type;                    \
   } while (0)
   } while (0)
 
 

+ 8 - 8
src/google/protobuf/field_mask.pb.cc

@@ -169,13 +169,6 @@ const FieldMask& FieldMask::default_instance() {
   return *internal_default_instance();
   return *internal_default_instance();
 }
 }
 
 
-FieldMask* FieldMask::New(::google::protobuf::Arena* arena) const {
-  FieldMask* n = new FieldMask;
-  if (arena != NULL) {
-    arena->Own(n);
-  }
-  return n;
-}
 
 
 void FieldMask::Clear() {
 void FieldMask::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
 // @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask)
@@ -355,7 +348,7 @@ void FieldMask::Swap(FieldMask* other) {
 }
 }
 void FieldMask::InternalSwap(FieldMask* other) {
 void FieldMask::InternalSwap(FieldMask* other) {
   using std::swap;
   using std::swap;
-  paths_.InternalSwap(&other->paths_);
+  paths_.InternalSwap(CastToBase(&other->paths_));
   _internal_metadata_.Swap(&other->_internal_metadata_);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   swap(_cached_size_, other->_cached_size_);
   swap(_cached_size_, other->_cached_size_);
 }
 }
@@ -369,5 +362,12 @@ void FieldMask::InternalSwap(FieldMask* other) {
 // @@protoc_insertion_point(namespace_scope)
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
 }  // namespace protobuf
 }  // namespace google
 }  // namespace google
+namespace google {
+namespace protobuf {
+template<> GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE ::google::protobuf::FieldMask* Arena::Create< ::google::protobuf::FieldMask >(Arena* arena) {
+  return Arena::CreateInternal< ::google::protobuf::FieldMask >(arena);
+}
+}  // namespace protobuf
+}  // namespace google
 
 
 // @@protoc_insertion_point(global_scope)
 // @@protoc_insertion_point(global_scope)

+ 11 - 2
src/google/protobuf/field_mask.pb.h

@@ -57,6 +57,11 @@ LIBPROTOBUF_EXPORT extern FieldMaskDefaultTypeInternal _FieldMask_default_instan
 }  // namespace google
 }  // namespace google
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+template<> LIBPROTOBUF_EXPORT ::google::protobuf::FieldMask* Arena::Create< ::google::protobuf::FieldMask>(Arena*);
+}  // namespace protobuf
+}  // namespace google
+namespace google {
+namespace protobuf {
 
 
 // ===================================================================
 // ===================================================================
 
 
@@ -104,9 +109,13 @@ class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message /* @@pro
 
 
   // implements Message ----------------------------------------------
   // implements Message ----------------------------------------------
 
 
-  inline FieldMask* New() const PROTOBUF_FINAL { return New(NULL); }
+  inline FieldMask* New() const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<FieldMask>(NULL);
+  }
 
 
-  FieldMask* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  FieldMask* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL {
+    return ::google::protobuf::Arena::Create<FieldMask>(arena);
+  }
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
   void CopyFrom(const FieldMask& from);
   void CopyFrom(const FieldMask& from);

+ 0 - 1
src/google/protobuf/generated_enum_reflection.h

@@ -41,7 +41,6 @@
 
 
 #include <string>
 #include <string>
 
 
-#include <google/protobuf/stubs/template_util.h>
 #include <google/protobuf/generated_enum_util.h>
 #include <google/protobuf/generated_enum_util.h>
 
 
 namespace google {
 namespace google {

+ 1 - 1
src/google/protobuf/generated_enum_util.h

@@ -31,7 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 #ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 #define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 #define GOOGLE_PROTOBUF_GENERATED_ENUM_UTIL_H__
 
 
-#include <google/protobuf/stubs/template_util.h>
+#include <google/protobuf/stubs/type_traits.h>
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {

+ 0 - 12
src/google/protobuf/generated_message_reflection.cc

@@ -1124,9 +1124,6 @@ string GeneratedMessageReflection::GetString(
         return GetField<ArenaStringPtr>(message, field).Get();
         return GetField<ArenaStringPtr>(message, field).Get();
       }
       }
     }
     }
-
-    GOOGLE_LOG(FATAL) << "Can't get here.";
-    return GetEmptyString();  // Make compiler happy.
   }
   }
 }
 }
 
 
@@ -1144,9 +1141,6 @@ const string& GeneratedMessageReflection::GetStringReference(
         return GetField<ArenaStringPtr>(message, field).Get();
         return GetField<ArenaStringPtr>(message, field).Get();
       }
       }
     }
     }
-
-    GOOGLE_LOG(FATAL) << "Can't get here.";
-    return GetEmptyString();  // Make compiler happy.
   }
   }
 }
 }
 
 
@@ -1188,9 +1182,6 @@ string GeneratedMessageReflection::GetRepeatedString(
       case FieldOptions::STRING:
       case FieldOptions::STRING:
         return GetRepeatedPtrField<string>(message, field, index);
         return GetRepeatedPtrField<string>(message, field, index);
     }
     }
-
-    GOOGLE_LOG(FATAL) << "Can't get here.";
-    return GetEmptyString();  // Make compiler happy.
   }
   }
 }
 }
 
 
@@ -1206,9 +1197,6 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference(
       case FieldOptions::STRING:
       case FieldOptions::STRING:
         return GetRepeatedPtrField<string>(message, field, index);
         return GetRepeatedPtrField<string>(message, field, index);
     }
     }
-
-    GOOGLE_LOG(FATAL) << "Can't get here.";
-    return GetEmptyString();  // Make compiler happy.
   }
   }
 }
 }
 
 

+ 2 - 6
src/google/protobuf/generated_message_reflection.h

@@ -655,12 +655,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection PROTOBUF_FINAL : public Refl
 // dynamic_cast_if_available() implements this logic.  If RTTI is
 // dynamic_cast_if_available() implements this logic.  If RTTI is
 // enabled, it does a dynamic_cast.  If RTTI is disabled, it just returns
 // enabled, it does a dynamic_cast.  If RTTI is disabled, it just returns
 // NULL.
 // NULL.
-//
-// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
-// On MSVC, this should be detected automatically.
 template<typename To, typename From>
 template<typename To, typename From>
 inline To dynamic_cast_if_available(From from) {
 inline To dynamic_cast_if_available(From from) {
-#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
+#ifdef GOOGLE_PROTOBUF_NO_RTTI
   // Avoid the compiler warning about unused variables.
   // Avoid the compiler warning about unused variables.
   (void)from;
   (void)from;
   return NULL;
   return NULL;
@@ -688,8 +685,7 @@ T* DynamicCastToGenerated(const Message* from) {
   const Message* unused = static_cast<T*>(NULL);
   const Message* unused = static_cast<T*>(NULL);
   (void)unused;
   (void)unused;
 
 
-#if defined(GOOGLE_PROTOBUF_NO_RTTI) || \
-  (defined(_MSC_VER) && !defined(_CPPRTTI))
+#ifdef GOOGLE_PROTOBUF_NO_RTTI
   bool ok = &T::default_instance() ==
   bool ok = &T::default_instance() ==
             from->GetReflection()->GetMessageFactory()->GetPrototype(
             from->GetReflection()->GetMessageFactory()->GetPrototype(
                 from->GetDescriptor());
                 from->GetDescriptor());

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff