down-integrate internal changes
diff --git a/.gitignore b/.gitignore
index 6508ecc..38755c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@
 
 .dirstamp
 
+any_test.pb.*
 map*unittest.pb.*
 unittest*.pb.*
 cpp_test*.pb.*
diff --git a/Android.mk b/Android.mk
index 18bdd09..bbd1574 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,14 +90,20 @@
     src/google/protobuf/compiler/cpp/cpp_string_field.cc \
     src/google/protobuf/compiler/java/java_enum.cc \
     src/google/protobuf/compiler/java/java_enum_field.cc \
+    src/google/protobuf/compiler/java/java_enum_field_lite.cc \
     src/google/protobuf/compiler/java/java_extension.cc \
     src/google/protobuf/compiler/java/java_field.cc \
     src/google/protobuf/compiler/java/java_file.cc \
     src/google/protobuf/compiler/java/java_generator.cc \
     src/google/protobuf/compiler/java/java_helpers.cc \
     src/google/protobuf/compiler/java/java_message.cc \
+    src/google/protobuf/compiler/java/java_message_lite.cc \
+    src/google/protobuf/compiler/java/java_message_builder.cc \
+    src/google/protobuf/compiler/java/java_message_builder_lite.cc \
     src/google/protobuf/compiler/java/java_message_field.cc \
+    src/google/protobuf/compiler/java/java_message_field_lite.cc \
     src/google/protobuf/compiler/java/java_primitive_field.cc \
+    src/google/protobuf/compiler/java/java_primitive_field_lite.cc \
     src/google/protobuf/compiler/java/java_service.cc \
     src/google/protobuf/compiler/javamicro/javamicro_enum.cc \
     src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc \
diff --git a/Makefile.am b/Makefile.am
index 45d44f5..645c924 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,28 +43,34 @@
   java/src/main/java/com/google/protobuf/AbstractMessage.java                \
   java/src/main/java/com/google/protobuf/AbstractMessageLite.java            \
   java/src/main/java/com/google/protobuf/AbstractParser.java                 \
+  java/src/main/java/com/google/protobuf/AbstractProtobufList.java           \
   java/src/main/java/com/google/protobuf/BlockingRpcChannel.java             \
   java/src/main/java/com/google/protobuf/BlockingService.java                \
   java/src/main/java/com/google/protobuf/BoundedByteString.java              \
+  java/src/main/java/com/google/protobuf/BooleanArrayList.java               \
   java/src/main/java/com/google/protobuf/ByteString.java                     \
   java/src/main/java/com/google/protobuf/CodedInputStream.java               \
   java/src/main/java/com/google/protobuf/CodedOutputStream.java              \
   java/src/main/java/com/google/protobuf/Descriptors.java                    \
+  java/src/main/java/com/google/protobuf/DoubleArrayList.java                \
   java/src/main/java/com/google/protobuf/DynamicMessage.java                 \
   java/src/main/java/com/google/protobuf/Extension.java                      \
   java/src/main/java/com/google/protobuf/ExtensionLite.java                  \
   java/src/main/java/com/google/protobuf/ExtensionRegistry.java              \
   java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java          \
   java/src/main/java/com/google/protobuf/FieldSet.java                       \
+  java/src/main/java/com/google/protobuf/FloatArrayList.java                 \
   java/src/main/java/com/google/protobuf/GeneratedMessage.java               \
   java/src/main/java/com/google/protobuf/GeneratedMessageLite.java           \
   java/src/main/java/com/google/protobuf/Internal.java                       \
+  java/src/main/java/com/google/protobuf/IntArrayList.java                   \
   java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
   java/src/main/java/com/google/protobuf/LazyField.java                      \
   java/src/main/java/com/google/protobuf/LazyFieldLite.java                  \
   java/src/main/java/com/google/protobuf/LazyStringArrayList.java            \
   java/src/main/java/com/google/protobuf/LazyStringList.java                 \
   java/src/main/java/com/google/protobuf/LiteralByteString.java              \
+  java/src/main/java/com/google/protobuf/LongArrayList.java                  \
   java/src/main/java/com/google/protobuf/MapEntry.java                       \
   java/src/main/java/com/google/protobuf/MapEntryLite.java                   \
   java/src/main/java/com/google/protobuf/MapField.java                       \
@@ -74,7 +80,9 @@
   java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java           \
   java/src/main/java/com/google/protobuf/MessageOrBuilder.java               \
   java/src/main/java/com/google/protobuf/MessageReflection.java              \
+  java/src/main/java/com/google/protobuf/MutabilityOracle.java               \
   java/src/main/java/com/google/protobuf/Parser.java                         \
+  java/src/main/java/com/google/protobuf/ProtobufArrayList.java              \
   java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java            \
   java/src/main/java/com/google/protobuf/ProtocolStringList.java             \
   java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java           \
@@ -96,16 +104,20 @@
   java/src/main/java/com/google/protobuf/WireFormat.java                     \
   java/src/test/java/com/google/protobuf/AbstractMessageTest.java            \
   java/src/test/java/com/google/protobuf/BoundedByteStringTest.java          \
+  java/src/test/java/com/google/protobuf/BooleanArrayListTest.java           \
   java/src/test/java/com/google/protobuf/ByteStringTest.java                 \
   java/src/test/java/com/google/protobuf/CheckUtf8Test.java                  \
   java/src/test/java/com/google/protobuf/CodedInputStreamTest.java           \
   java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java          \
   java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java            \
   java/src/test/java/com/google/protobuf/DescriptorsTest.java                \
+  java/src/test/java/com/google/protobuf/DoubleArrayListTest.java            \
   java/src/test/java/com/google/protobuf/DynamicMessageTest.java             \
   java/src/test/java/com/google/protobuf/FieldPresenceTest.java              \
+  java/src/test/java/com/google/protobuf/FloatArrayListTest.java             \
   java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java       \
   java/src/test/java/com/google/protobuf/GeneratedMessageTest.java           \
+  java/src/test/java/com/google/protobuf/IntArrayListTest.java               \
   java/src/test/java/com/google/protobuf/IsValidUtf8Test.java                \
   java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java            \
   java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java              \
@@ -116,12 +128,14 @@
   java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java          \
   java/src/test/java/com/google/protobuf/LiteralByteStringTest.java          \
   java/src/test/java/com/google/protobuf/LiteTest.java                       \
+  java/src/test/java/com/google/protobuf/LongArrayListTest.java              \
   java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java           \
   java/src/test/java/com/google/protobuf/MapForProto2Test.java               \
   java/src/test/java/com/google/protobuf/MapTest.java                        \
   java/src/test/java/com/google/protobuf/MessageTest.java                    \
   java/src/test/java/com/google/protobuf/NestedBuildersTest.java             \
   java/src/test/java/com/google/protobuf/ParserTest.java                     \
+  java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java          \
   java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java       \
   java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java    \
   java/src/test/java/com/google/protobuf/RopeByteStringTest.java             \
diff --git a/conformance/conformance.proto b/conformance/conformance.proto
index 7b67689..39eafdb 100644
--- a/conformance/conformance.proto
+++ b/conformance/conformance.proto
@@ -71,7 +71,7 @@
   }
 
   // Which format should the testee serialize its message to?
-  optional RequestedOutput requested_output = 3;
+  RequestedOutput requested_output = 3;
 }
 
 // Represents a single test case's output.
@@ -103,8 +103,8 @@
 // forms.
 message TestAllTypes {
   message NestedMessage {
-    optional int32 a = 1;
-    optional TestAllTypes corecursive = 2;
+    int32 a = 1;
+    TestAllTypes corecursive = 2;
   }
 
   enum NestedEnum {
@@ -115,36 +115,32 @@
   }
 
   // Singular
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
+  int32 optional_int32    =  1;
+  int64 optional_int64    =  2;
+  uint32 optional_uint32   =  3;
+  uint64 optional_uint64   =  4;
+  sint32 optional_sint32   =  5;
+  sint64 optional_sint64   =  6;
+  fixed32 optional_fixed32  =  7;
+  fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+  float optional_float    = 11;
+  double optional_double   = 12;
+  bool optional_bool     = 13;
+  string optional_string   = 14;
+  bytes optional_bytes    = 15;
 
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
 
-  optional NestedMessage                        optional_nested_message  = 18;
-  optional ForeignMessage                       optional_foreign_message = 19;
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
 
-  optional NestedEnum                           optional_nested_enum     = 21;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
 
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
-
-  optional TestAllTypes recursive_message = 27;
+  TestAllTypes recursive_message = 27;
 
   // Repeated
   repeated    int32 repeated_int32    = 31;
@@ -163,10 +159,6 @@
   repeated   string repeated_string   = 44;
   repeated    bytes repeated_bytes    = 45;
 
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
-
   repeated NestedMessage                        repeated_nested_message  = 48;
   repeated ForeignMessage                       repeated_foreign_message = 49;
 
@@ -206,7 +198,7 @@
 }
 
 message ForeignMessage {
-  optional int32 c = 1;
+  int32 c = 1;
 }
 
 enum ForeignEnum {
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index 61029e4..857f215 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -295,6 +295,7 @@
   failures_ = 0;
 
   for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
+    if (i == FieldDescriptor::TYPE_GROUP) continue;
     TestPrematureEOFForType(static_cast<WireFormatLite::FieldType>(i));
   }
 
diff --git a/editors/proto.vim b/editors/proto.vim
index 23085a2..7f1aeb7 100644
--- a/editors/proto.vim
+++ b/editors/proto.vim
@@ -57,7 +57,7 @@
 syn keyword pbStructure  package message group oneof
 syn keyword pbRepeat     optional required repeated
 syn keyword pbDefault    default
-syn keyword pbExtend     extend extensions to max
+syn keyword pbExtend     extend extensions to max reserved
 syn keyword pbRPC        service rpc returns
 
 syn keyword pbType      int32 int64 uint32 uint64 sint32 sint64
diff --git a/editors/protobuf-mode.el b/editors/protobuf-mode.el
index 09aecc9..f615a0a 100644
--- a/editors/protobuf-mode.el
+++ b/editors/protobuf-mode.el
@@ -106,7 +106,7 @@
 ;; cc-mode.  So, we approximate as best we can.
 
 (c-lang-defconst c-type-list-kwds
-  protobuf '("extensions" "to"))
+  protobuf '("extensions" "to" "reserved"))
 
 (c-lang-defconst c-typeless-decl-kwds
   protobuf '("extend" "rpc" "option" "returns"))
diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh
index 27d293a..89449e1 100755
--- a/generate_descriptor_proto.sh
+++ b/generate_descriptor_proto.sh
@@ -43,8 +43,11 @@
   google/protobuf/wrappers.proto)
 
 CORE_PROTO_IS_CORRECT=0
+PROCESS_ROUND=1
+echo "Updating descriptor protos..."
 while [ $CORE_PROTO_IS_CORRECT -ne 1 ]
 do
+  echo "Round $PROCESS_ROUND"
   CORE_PROTO_IS_CORRECT=1
   for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
     BASE_NAME=${PROTO_FILE%.*}
@@ -86,5 +89,7 @@
   done
   rm google/protobuf/compiler/plugin.pb.h.tmp
   rm google/protobuf/compiler/plugin.pb.cc.tmp
+
+  PROCESS_ROUND=$((PROCESS_ROUND + 1))
 done
 cd ..
diff --git a/java/pom.xml b/java/pom.xml
index 3eb7a70..9f27011 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -134,6 +134,7 @@
                   <arg value="src/test/java/com/google/protobuf/map_for_proto2_lite_test.proto" />
                   <arg value="src/test/java/com/google/protobuf/map_for_proto2_test.proto" />
                   <arg value="src/test/java/com/google/protobuf/map_test.proto" />
+                  <arg value="src/test/java/com/google/protobuf/map_initialization_order_test.proto" />
                 </exec>
               </tasks>
               <testSourceRoot>target/generated-test-sources</testSourceRoot>
@@ -227,25 +228,33 @@
               <includes>
                 <include>**/AbstractMessageLite.java</include>
                 <include>**/AbstractParser.java</include>
+                <include>**/AbstractProtobufList.java</include>
                 <include>**/BoundedByteString.java</include>
+                <include>**/BooleanArrayList.java</include>
                 <include>**/ByteString.java</include>
                 <include>**/CodedInputStream.java</include>
                 <include>**/CodedOutputStream.java</include>
+                <include>**/DoublerrayList.java</include>
                 <include>**/ExtensionLite.java</include>
                 <include>**/ExtensionRegistryLite.java</include>
                 <include>**/FieldSet.java</include>
+                <include>**/FloatArrayList.java</include>
                 <include>**/GeneratedMessageLite.java</include>
+                <include>**/IntArrayList.java</include>
                 <include>**/Internal.java</include>
                 <include>**/InvalidProtocolBufferException.java</include>
                 <include>**/LazyFieldLite.java</include>
                 <include>**/LazyStringArrayList.java</include>
                 <include>**/LazyStringList.java</include>
                 <include>**/LiteralByteString.java</include>
+                <include>**/LongArrayList.java</include>
                 <include>**/MapEntryLite.java</include>
                 <include>**/MapFieldLite.java</include>
                 <include>**/MessageLite.java</include>
                 <include>**/MessageLiteOrBuilder.java</include>
+                <include>**/MutabilityOracle.java</include>
                 <include>**/Parser.java</include>
+                <include>**/ProtobufArrayList.java</include>
                 <include>**/ProtocolStringList.java</include>
                 <include>**/RopeByteString.java</include>
                 <include>**/SmallSortedMap.java</include>
@@ -257,8 +266,14 @@
               </includes>
               <testIncludes>
                 <testInclude>**/*Lite.java</testInclude>
+                <testInclude>**/BooleanArrayListTest.java</testInclude>
+                <testInclude>**/DoubleArrayListTest.java</testInclude>
+                <testInclude>**/FloatArrayListTest.java</testInclude>
+                <testInclude>**/IntArrayListTest.java</testInclude>
                 <testInclude>**/LazyMessageLiteTest.java</testInclude>
                 <testInclude>**/LiteTest.java</testInclude>
+                <testInclude>**/LongArrayListTest.java</testInclude>
+                <testInclude>**/ProtobufArrayListTest.java</testInclude>
                 <testInclude>**/UnknownFieldSetLiteTest.java</testInclude>
               </testIncludes>
             </configuration>
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
index aac4fa7..1238498 100644
--- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -31,8 +31,8 @@
 package com.google.protobuf;
 
 import java.io.FilterInputStream;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Collection;
 
@@ -109,6 +109,11 @@
     }
   }
 
+  protected static <T> void addAll(final Iterable<T> values,
+      final Collection<? super T> list) {
+    Builder.addAll(values, list);
+  }
+  
   /**
    * A partial implementation of the {@link Message.Builder} interface which
    * implements as many methods of that interface as possible in terms of
@@ -320,12 +325,15 @@
      * Adds the {@code values} to the {@code list}.  This is a helper method
      * used by generated code.  Users should ignore it.
      *
-     * @throws NullPointerException if any of the elements of {@code values} is
-     * null. When that happens, some elements of {@code values} may have already
-     * been added to the result {@code list}.
+     * @throws NullPointerException if {@code values} or any of the elements of
+     * {@code values} is null. When that happens, some elements of
+     * {@code values} may have already been added to the result {@code list}.
      */
     protected static <T> void addAll(final Iterable<T> values,
                                      final Collection<? super T> list) {
+      if (values == null) {
+        throw new NullPointerException();
+      }
       if (values instanceof LazyStringList) {
         // For StringOrByteStringLists, check the underlying elements to avoid
         // forcing conversions of ByteStrings to Strings.
diff --git a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java
new file mode 100644
index 0000000..bb6446b
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java
@@ -0,0 +1,136 @@
+// 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;
+
+import com.google.protobuf.Internal.ProtobufList;
+
+import java.util.AbstractList;
+import java.util.Collection;
+
+/**
+ * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate
+ * methods are check if the list is mutable before proceeding. Subclasses must invoke
+ * {@link #ensureIsMutable()} manually when overriding those methods.
+ */
+abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
+
+  /**
+   * Whether or not this list is modifiable.
+   */
+  private boolean isMutable;
+  
+  /**
+   * Constructs a mutable list by default.
+   */
+  AbstractProtobufList() {
+    isMutable = true;
+  }
+
+  @Override
+  public boolean add(E e) {
+    ensureIsMutable();
+    return super.add(e);
+  }
+
+  @Override
+  public void add(int index, E element) {
+    ensureIsMutable();
+    super.add(index, element);
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends E> c) {
+    ensureIsMutable();
+    return super.addAll(c);
+  }
+  
+  @Override
+  public boolean addAll(int index, Collection<? extends E> c) {
+    ensureIsMutable();
+    return super.addAll(index, c);
+  }
+
+  @Override
+  public void clear() {
+    ensureIsMutable();
+    super.clear();
+  }
+  
+  @Override
+  public boolean isModifiable() {
+    return isMutable;
+  }
+  
+  @Override
+  public final void makeImmutable() {
+    isMutable = false;
+  }
+  
+  @Override
+  public E remove(int index) {
+    ensureIsMutable();
+    return super.remove(index);
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    return super.remove(o);
+  }
+  
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    ensureIsMutable();
+    return super.removeAll(c);
+  }
+  
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    ensureIsMutable();
+    return super.retainAll(c);
+  }
+  
+  @Override
+  public E set(int index, E element) {
+    ensureIsMutable();
+    return super.set(index, element);
+  }
+  
+  /**
+   * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are
+   * responsible for invoking this method on mutate operations.
+   */
+  protected void ensureIsMutable() {
+    if (!isMutable) {
+      throw new UnsupportedOperationException();
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/src/main/java/com/google/protobuf/BooleanArrayList.java
new file mode 100644
index 0000000..45492d2
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -0,0 +1,244 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Internal.BooleanList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link BooleanList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class BooleanArrayList
+    extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess {
+  
+  private static final int DEFAULT_CAPACITY = 10;
+  
+  private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static BooleanArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private boolean[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList}.
+   */
+  BooleanArrayList() {
+    array = new boolean[DEFAULT_CAPACITY];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code BooleanArrayList} containing the same elements as
+   * {@code other}.
+   */
+  BooleanArrayList(List<Boolean> other) {
+    if (other instanceof BooleanArrayList) {
+      BooleanArrayList list = (BooleanArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new boolean[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @Override
+  public Boolean get(int index) {
+    return getBoolean(index);
+  }
+
+  @Override
+  public boolean getBoolean(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Boolean set(int index, Boolean element) {
+    return setBoolean(index, element);
+  }
+
+  @Override
+  public boolean setBoolean(int index, boolean element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    boolean previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Boolean element) {
+    addBoolean(index, element);
+  }
+
+  /**
+   * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addBoolean(boolean element) {
+    addBoolean(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element.
+   */
+  private void addBoolean(int index, boolean element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      boolean[] newArray = new boolean[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Boolean> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another BooleanArrayList to avoid boxing elements.
+    if (!(collection instanceof BooleanArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    BooleanArrayList list = (BooleanArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Boolean remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    boolean value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
index b60bd36..3658410 100644
--- a/java/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/src/main/java/com/google/protobuf/Descriptors.java
@@ -644,6 +644,30 @@
       return false;
     }
 
+    /** Determines if the given field number is reserved. */
+    public boolean isReservedNumber(final int number) {
+      for (final DescriptorProto.ReservedRange range :
+          proto.getReservedRangeList()) {
+        if (range.getStart() <= number && number < range.getEnd()) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    /** Determines if the given field name is reserved. */
+    public boolean isReservedName(final String name) {
+      if (name == null) {
+        throw new NullPointerException();
+      }
+      for (final String reservedName : proto.getReservedNameList()) {
+        if (reservedName.equals(name)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
     /**
      * Indicates whether the message can be extended.  That is, whether it has
      * any "extensions x to y" ranges declared on it.
@@ -917,9 +941,18 @@
       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
     }
 
-    /** Does this field have the {@code [packed = true]} option? */
+    /** Does this field have the {@code [packed = true]} option or is this field
+     *  packable in proto3 and not explicitly setted to unpacked?
+     */
     public boolean isPacked() {
-      return getOptions().getPacked();
+      if (!isPackable()) {
+        return false;
+      }
+      if (getFile().getSyntax() == FileDescriptor.Syntax.PROTO2) {
+        return getOptions().getPacked();
+      } else {
+        return !getOptions().hasPacked() || getOptions().getPacked();
+      }
     }
 
     /** Can this field be packed? i.e. is it a repeated primitive field? */
@@ -2317,6 +2350,11 @@
 
     public int getFieldCount() { return fieldCount; }
 
+    /** Get a list of this message type's fields. */
+    public List<FieldDescriptor> getFields() {
+      return Collections.unmodifiableList(Arrays.asList(fields));
+    }
+
     public FieldDescriptor getField(int index) {
       return fields[index];
     }
diff --git a/java/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/src/main/java/com/google/protobuf/DoubleArrayList.java
new file mode 100644
index 0000000..90ebe10
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -0,0 +1,243 @@
+// 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;
+
+import com.google.protobuf.Internal.DoubleList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link DoubleList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class DoubleArrayList
+    extends AbstractProtobufList<Double> implements DoubleList, RandomAccess {
+  
+  private static final int DEFAULT_CAPACITY = 10;
+  
+  private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static DoubleArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private double[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList}.
+   */
+  DoubleArrayList() {
+    array = new double[DEFAULT_CAPACITY];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
+   */
+  DoubleArrayList(List<Double> other) {
+    if (other instanceof DoubleArrayList) {
+      DoubleArrayList list = (DoubleArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new double[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @Override
+  public Double get(int index) {
+    return getDouble(index);
+  }
+
+  @Override
+  public double getDouble(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Double set(int index, Double element) {
+    return setDouble(index, element);
+  }
+
+  @Override
+  public double setDouble(int index, double element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    double previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Double element) {
+    addDouble(index, element);
+  }
+
+  /**
+   * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addDouble(double element) {
+    addDouble(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Double)} but more efficient in that it doesn't box the element.
+   */
+  private void addDouble(int index, double element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      double[] newArray = new double[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Double> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another DoubleArrayList to avoid boxing elements.
+    if (!(collection instanceof DoubleArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    DoubleArrayList list = (DoubleArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Double remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    double value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/FloatArrayList.java b/java/src/main/java/com/google/protobuf/FloatArrayList.java
new file mode 100644
index 0000000..293eaff
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -0,0 +1,242 @@
+// 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;
+
+import com.google.protobuf.Internal.FloatList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link FloatList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class FloatArrayList extends AbstractProtobufList<Float> implements FloatList, RandomAccess {
+  
+  private static final int DEFAULT_CAPACITY = 10;
+  
+  private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static FloatArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private float[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList}.
+   */
+  FloatArrayList() {
+    array = new float[DEFAULT_CAPACITY];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
+   */
+  FloatArrayList(List<Float> other) {
+    if (other instanceof FloatArrayList) {
+      FloatArrayList list = (FloatArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new float[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @Override
+  public Float get(int index) {
+    return getFloat(index);
+  }
+
+  @Override
+  public float getFloat(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Float set(int index, Float element) {
+    return setFloat(index, element);
+  }
+
+  @Override
+  public float setFloat(int index, float element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    float previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Float element) {
+    addFloat(index, element);
+  }
+
+  /**
+   * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addFloat(float element) {
+    addFloat(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Float)} but more efficient in that it doesn't box the element.
+   */
+  private void addFloat(int index, float element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      float[] newArray = new float[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Float> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another FloatArrayList to avoid boxing elements.
+    if (!(collection instanceof FloatArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    FloatArrayList list = (FloatArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Float remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    float value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index 6839c9d..bd6bc46 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -30,6 +30,12 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.Internal.BooleanList;
+import com.google.protobuf.Internal.DoubleList;
+import com.google.protobuf.Internal.FloatList;
+import com.google.protobuf.Internal.IntList;
+import com.google.protobuf.Internal.LongList;
+import com.google.protobuf.Internal.ProtobufList;
 import com.google.protobuf.WireFormat.FieldType;
 
 import java.io.IOException;
@@ -76,7 +82,11 @@
   private static final long serialVersionUID = 1L;
 
   /** For use by generated code only.  */
-  protected UnknownFieldSetLite unknownFields;
+  protected UnknownFieldSetLite unknownFields =
+      UnknownFieldSetLite.getDefaultInstance();
+  
+  /** For use by generated code only.  */
+  protected int memoizedSerializedSize = -1;
   
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final Parser<MessageType> getParserForType() {
@@ -109,10 +119,67 @@
     return unknownFields.mergeFieldFrom(tag, input);
   }
 
-  // The default behavior. If a message has required fields in its subtree, the
-  // generated code will override.
-  public boolean isInitialized() {
-    return true;
+  public final boolean isInitialized() {
+    return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
+  }
+
+  public final BuilderType toBuilder() {
+    BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
+    builder.mergeFrom((MessageType) this);
+    return builder;
+  }
+
+  /**
+   * Defines which method path to invoke in {@link GeneratedMessageLite
+   * #dynamicMethod(MethodToInvoke, Object...)}.
+   * <p>
+   * For use by generated code only.
+   */
+  public static enum MethodToInvoke {
+    IS_INITIALIZED,
+    PARSE_PARTIAL_FROM,
+    MERGE_FROM,
+    MAKE_IMMUTABLE,
+    NEW_INSTANCE,
+    NEW_BUILDER;
+  }
+
+  /**
+   * A method that implements different types of operations described in {@link MethodToInvoke}.
+   * Theses different kinds of operations are required to implement message-level operations for
+   * builders in the runtime. This method bundles those operations to reduce the generated methods
+   * count.
+   * <ul>
+   * <li>{@code PARSE_PARTIAL_FROM} is parameterized with an {@link CodedInputStream} and
+   * {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the
+   * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the
+   * implementation wraps it in a RuntimeException
+   * <li>{@code NEW_INSTANCE} returns a new instance of the protocol buffer
+   * <li>{@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to
+   * memoize. It returns {@code null} for false and the default instance for true. We optionally
+   * memoize to support the Builder case, where memoization is not desired.
+   * <li>{@code NEW_BUILDER} returns a {@code BuilderType} instance.
+   * <li>{@code MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from
+   * that instance into this instance.
+   * <li>{@code MAKE_IMMUTABLE} sets all internal fields to an immutable state.
+   * </ul>
+   * This method, plus the implementation of the Builder, enables the Builder class to be proguarded
+   * away entirely on Android.
+   * <p>
+   * For use by generated code only.
+   */
+  protected abstract Object dynamicMethod(
+      MethodToInvoke method,
+      Object... args);
+
+  /**
+   * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
+   * message.
+   *
+   * <p>For use by generated code only.
+   */
+  protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) {
+    this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
   }
 
   @SuppressWarnings("unchecked")
@@ -122,24 +189,37 @@
           extends AbstractMessageLite.Builder<BuilderType> {
 
     private final MessageType defaultInstance;
-
-    /** For use by generated code only. */
-    protected UnknownFieldSetLite unknownFields =
-        UnknownFieldSetLite.getDefaultInstance();
+    protected MessageType instance;
+    protected boolean isBuilt;
 
     protected Builder(MessageType defaultInstance) {
       this.defaultInstance = defaultInstance;
+      this.instance = (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+      isBuilt = false;
     }
 
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      return true;
+    /**
+     * Called before any method that would mutate the builder to ensure that it correctly copies
+     * any state before the write happens to preserve immutability guarantees.
+     */
+    protected void copyOnWrite() {
+      if (isBuilt) {
+        MessageType newInstance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
+        newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance);
+        instance = newInstance;
+        isBuilt = false;
+      }
     }
 
     //@Override (Java 1.6 override semantics, but we must support 1.5)
-    public BuilderType clear() {
-      unknownFields = UnknownFieldSetLite.getDefaultInstance();
+    public final boolean isInitialized() {
+      return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */);
+    }
+
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public final BuilderType clear() {
+      // No need to copy on write since we're dropping the instance anyways.
+      instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE);
       return (BuilderType) this;
     }
 
@@ -151,8 +231,12 @@
       return builder;
     }
 
-    /** All subclasses implement this. */
-    public abstract MessageType buildPartial();
+    //@Override (Java 1.6 override semantics, but we must support 1.5)
+    public MessageType buildPartial() {
+      instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+      isBuilt = true;
+      return instance;
+    }
 
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final MessageType build() {
@@ -162,9 +246,13 @@
       }
       return result;
     }
-
+    
     /** All subclasses implement this. */
-    public abstract BuilderType mergeFrom(MessageType message);
+    public BuilderType mergeFrom(MessageType message) {
+      copyOnWrite();
+      instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message);
+      return (BuilderType) this;
+    }
     
     public MessageType getDefaultInstanceForType() {
       return defaultInstance;
@@ -181,18 +269,6 @@
         int tag) throws IOException {
       return unknownFields.mergeFieldFrom(tag, input);
     }
-
-    /**
-     * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
-     * message.
-     *
-     * <p>For use by generated code only.
-     */
-    protected final BuilderType mergeUnknownFields(
-        final UnknownFieldSetLite unknownFields) {
-      this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
-      return (BuilderType) this;
-    }
     
     public BuilderType mergeFrom(
         com.google.protobuf.CodedInputStream input,
@@ -259,19 +335,13 @@
      */
     protected FieldSet<ExtensionDescriptor> extensions = FieldSet.newFieldSet();
 
-    // -1 => not memoized, 0 => false, 1 => true.
-    private byte memoizedIsInitialized = -1;
-
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      if (memoizedIsInitialized == -1) {
-        memoizedIsInitialized = (byte) (extensions.isInitialized() ? 1 : 0);
+    protected final void mergeExtensionFields(final MessageType other) {
+      if (extensions.isImmutable()) {
+        extensions = extensions.clone();
       }
-
-      return memoizedIsInitialized == 1;
+      extensions.mergeFrom(((ExtendableMessage) other).extensions);
     }
-
+    
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
       if (extension.getContainingTypeDefaultInstance() !=
@@ -420,46 +490,38 @@
       implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
     protected ExtendableBuilder(MessageType defaultInstance) {
       super(defaultInstance);
-    }
-
-    private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
-    private boolean extensionsIsMutable;
-
-    // The default behavior. If a message has required fields in its subtree,
-    // the generated code will override.
-    public boolean isInitialized() {
-      return extensions.isInitialized();
+      
+      // 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.
     void internalSetExtensionSet(FieldSet<ExtensionDescriptor> extensions) {
-      this.extensions = extensions;
+      copyOnWrite();
+      instance.extensions = extensions;
     }
 
-    @Override
-    public BuilderType clear() {
-      extensions.clear();
-      extensionsIsMutable = false;
-      return super.clear();
-    }
-
-    private void ensureExtensionsIsMutable() {
-      if (!extensionsIsMutable) {
-        extensions = extensions.clone();
-        extensionsIsMutable = true;
+    // @Override (Java 1.6 override semantics, but we must support 1.5)
+    protected void copyOnWrite() {
+      if (!isBuilt) {
+        return;
       }
+      
+      super.copyOnWrite();
+      instance.extensions = instance.extensions.clone();
     }
 
-    /**
-     * Called by the build code path to create a copy of the extensions for
-     * building the message.
-     * <p>
-     * For use by generated code only.
-     */
-    protected final FieldSet<ExtensionDescriptor> buildExtensions() {
-      extensions.makeImmutable();
-      extensionsIsMutable = false;
-      return extensions;
+    // @Override (Java 1.6 override semantics, but we must support 1.5)
+    public final MessageType buildPartial() {
+      if (isBuilt) {
+        return instance;
+      }
+
+      instance.extensions.makeImmutable();
+      return super.buildPartial();
     }
 
     private void verifyExtensionContainingType(
@@ -477,22 +539,14 @@
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> boolean hasExtension(
         final ExtensionLite<MessageType, Type> extension) {
-      GeneratedExtension<MessageType, Type> extensionLite =
-          checkIsLite(extension);
-      
-      verifyExtensionContainingType(extensionLite);
-      return extensions.hasField(extensionLite.descriptor);
+      return instance.hasExtension(extension);
     }
 
     /** Get the number of elements in a repeated extension. */
     //@Override (Java 1.6 override semantics, but we must support 1.5)
     public final <Type> int getExtensionCount(
         final ExtensionLite<MessageType, List<Type>> extension) {
-      GeneratedExtension<MessageType, List<Type>> extensionLite =
-          checkIsLite(extension);
-      
-      verifyExtensionContainingType(extensionLite);
-      return extensions.getRepeatedFieldCount(extensionLite.descriptor);
+      return instance.getExtensionCount(extension);
     }
 
     /** Get the value of an extension. */
@@ -500,16 +554,7 @@
     @SuppressWarnings("unchecked")
     public final <Type> Type getExtension(
         final ExtensionLite<MessageType, Type> extension) {
-      GeneratedExtension<MessageType, Type> extensionLite =
-          checkIsLite(extension);
-      
-      verifyExtensionContainingType(extensionLite);
-      final Object value = extensions.getField(extensionLite.descriptor);
-      if (value == null) {
-        return extensionLite.defaultValue;
-      } else {
-        return (Type) extensionLite.fromFieldSetType(value);
-      }
+      return instance.getExtension(extension);
     }
 
     /** Get one element of a repeated extension. */
@@ -518,12 +563,7 @@
     public final <Type> Type getExtension(
         final ExtensionLite<MessageType, List<Type>> extension,
         final int index) {
-      GeneratedExtension<MessageType, List<Type>> extensionLite =
-          checkIsLite(extension);
-      
-      verifyExtensionContainingType(extensionLite);
-      return (Type) extensionLite.singularFromFieldSetType(
-          extensions.getRepeatedField(extensionLite.descriptor, index));
+      return instance.getExtension(extension, index);
     }
 
     // This is implemented here only to work around an apparent bug in the
@@ -542,9 +582,8 @@
           checkIsLite(extension);
       
       verifyExtensionContainingType(extensionLite);
-      ensureExtensionsIsMutable();
-      extensions.setField(extensionLite.descriptor,
-                          extensionLite.toFieldSetType(value));
+      copyOnWrite();
+      instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -556,9 +595,9 @@
           checkIsLite(extension);
       
       verifyExtensionContainingType(extensionLite);
-      ensureExtensionsIsMutable();
-      extensions.setRepeatedField(extensionLite.descriptor, index,
-                                  extensionLite.singularToFieldSetType(value));
+      copyOnWrite();
+      instance.extensions.setRepeatedField(
+          extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -570,9 +609,9 @@
           checkIsLite(extension);
       
       verifyExtensionContainingType(extensionLite);
-      ensureExtensionsIsMutable();
-      extensions.addRepeatedField(extensionLite.descriptor,
-                                  extensionLite.singularToFieldSetType(value));
+      copyOnWrite();
+      instance.extensions.addRepeatedField(
+          extensionLite.descriptor, extensionLite.singularToFieldSetType(value));
       return (BuilderType) this;
     }
 
@@ -582,20 +621,10 @@
       GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
       
       verifyExtensionContainingType(extensionLite);
-      ensureExtensionsIsMutable();
-      extensions.clearField(extensionLite.descriptor);
+      copyOnWrite();
+      instance.extensions.clearField(extensionLite.descriptor);
       return (BuilderType) this;
     }
-
-    /** Called by subclasses to check if all extensions are initialized. */
-    protected boolean extensionsAreInitialized() {
-      return extensions.isInitialized();
-    }
-
-    protected final void mergeExtensionFields(final MessageType other) {
-      ensureExtensionsIsMutable();
-      extensions.mergeFrom(((ExtendableMessage) other).extensions);
-    }
   }
 
   //-----------------------------------------------------------------
@@ -1113,4 +1142,133 @@
       return (BuilderType) defaultInstance.toBuilder();
     }
   }
+
+  /**
+   * A static helper method for checking if a message is initialized, optionally memoizing.
+   * <p>
+   * For use by generated code only.
+   */
+  protected static final <T extends GeneratedMessageLite<T, ?>> boolean isInitialized(
+      T message, boolean shouldMemoize) {
+    return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null;
+  }
+  
+  protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
+    message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+  }
+  
+  /**
+   * A static helper method for parsing a partial from input using the extension registry and the
+   * instance.
+   */
+  static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
+      T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws InvalidProtocolBufferException {
+    try {
+      return (T) instance.dynamicMethod(
+          MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry);
+    } catch (RuntimeException e) {
+      if (e.getCause() instanceof InvalidProtocolBufferException) {
+        throw (InvalidProtocolBufferException) e.getCause();
+      }
+      throw e;
+    }
+  }
+  
+  /**
+   * A {@link Parser} implementation that delegates to the default instance.
+   * <p>
+   * For use by generated code only.
+   */
+  protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
+      extends AbstractParser<T> {
+    
+    private T defaultInstance;
+    
+    public DefaultInstanceBasedParser(T defaultInstance) {
+      this.defaultInstance = defaultInstance;
+    }
+    
+    @Override
+    public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+        throws InvalidProtocolBufferException {
+      return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
+    }
+  }
+  
+  protected static IntList newIntList() {
+    return new IntArrayList();
+  }
+  
+  protected static IntList newIntList(List<Integer> toCopy) {
+    return new IntArrayList(toCopy);
+  }
+  
+  protected static IntList emptyIntList() {
+    return IntArrayList.emptyList();
+  }
+  
+  protected static LongList newLongList() {
+    return new LongArrayList();
+  }
+  
+  protected static LongList newLongList(List<Long> toCopy) {
+    return new LongArrayList(toCopy);
+  }
+  
+  protected static LongList emptyLongList() {
+    return LongArrayList.emptyList();
+  }
+  
+  protected static FloatList newFloatList() {
+    return new FloatArrayList();
+  }
+  
+  protected static FloatList newFloatList(List<Float> toCopy) {
+    return new FloatArrayList(toCopy);
+  }
+  
+  protected static FloatList emptyFloatList() {
+    return FloatArrayList.emptyList();
+  }
+  
+  protected static DoubleList newDoubleList() {
+    return new DoubleArrayList();
+  }
+  
+  protected static DoubleList newDoubleList(List<Double> toCopy) {
+    return new DoubleArrayList(toCopy);
+  }
+  
+  protected static DoubleList emptyDoubleList() {
+    return DoubleArrayList.emptyList();
+  }
+  
+  protected static BooleanList newBooleanList() {
+    return new BooleanArrayList();
+  }
+  
+  protected static BooleanList newBooleanList(List<Boolean> toCopy) {
+    return new BooleanArrayList(toCopy);
+  }
+  
+  protected static BooleanList emptyBooleanList() {
+    return BooleanArrayList.emptyList();
+  }
+  
+  protected static <E> ProtobufList<E> newProtobufList() {
+    return new ProtobufArrayList<E>();
+  }
+  
+  protected static <E> ProtobufList<E> newProtobufList(List<E> toCopy) {
+    return new ProtobufArrayList<E>(toCopy);
+  }
+  
+  protected static <E> ProtobufList<E> emptyProtobufList() {
+    return ProtobufArrayList.emptyList();
+  }
+  
+  protected static LazyStringArrayList emptyLazyStringArrayList() {
+    return LazyStringArrayList.emptyList();
+  }
 }
diff --git a/java/src/main/java/com/google/protobuf/IntArrayList.java b/java/src/main/java/com/google/protobuf/IntArrayList.java
new file mode 100644
index 0000000..f7609cc
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/IntArrayList.java
@@ -0,0 +1,242 @@
+// 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;
+
+import com.google.protobuf.Internal.IntList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link IntList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
+  
+  private static final int DEFAULT_CAPACITY = 10;
+  
+  private static final IntArrayList EMPTY_LIST = new IntArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static IntArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private int[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code IntArrayList}.
+   */
+  IntArrayList() {
+    array = new int[DEFAULT_CAPACITY];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
+   */
+  IntArrayList(List<Integer> other) {
+    if (other instanceof IntArrayList) {
+      IntArrayList list = (IntArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new int[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @Override
+  public Integer get(int index) {
+    return getInt(index);
+  }
+
+  @Override
+  public int getInt(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Integer set(int index, Integer element) {
+    return setInt(index, element);
+  }
+
+  @Override
+  public int setInt(int index, int element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    int previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Integer element) {
+    addInt(index, element);
+  }
+
+  /**
+   * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addInt(int element) {
+    addInt(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element.
+   */
+  private void addInt(int index, int element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      int[] newArray = new int[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Integer> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another IntArrayList to avoid boxing elements.
+    if (!(collection instanceof IntArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    IntArrayList list = (IntArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Integer remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    int value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java
index 74bf44c..20054b7 100644
--- a/java/src/main/java/com/google/protobuf/Internal.java
+++ b/java/src/main/java/com/google/protobuf/Internal.java
@@ -30,6 +30,7 @@
 
 package com.google.protobuf;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.util.AbstractList;
@@ -532,4 +533,132 @@
       }
     }
   }
+
+  /**
+   * Extends {@link List} to add the capability to make the list immutable and inspect if it is
+   * modifiable.
+   */
+  public static interface ProtobufList<E> extends List<E> {
+
+    /**
+     * Makes this list immutable. All subsequent modifications will throw an
+     * {@link UnsupportedOperationException}.
+     */
+    void makeImmutable();
+
+    /**
+     * Returns whether this list can be modified via the publicly accessible {@link List} methods.
+     */
+    boolean isModifiable();
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Integers if
+   * possible. Does not support null elements.
+   */
+  public static interface IntList extends ProtobufList<Integer> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    int getInt(int index);
+
+    /**
+     * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
+     */
+    void addInt(int element);
+
+    /**
+     * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element.
+     */
+    int setInt(int index, int element);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Booleans if
+   * possible. Does not support null elements.
+   */
+  public static interface BooleanList extends ProtobufList<Boolean> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    boolean getBoolean(int index);
+
+    /**
+     * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element.
+     */
+    void addBoolean(boolean element);
+
+    /**
+     * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element.
+     */
+    boolean setBoolean(int index, boolean element);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Longs if
+   * possible. Does not support null elements.
+   */
+  public static interface LongList extends ProtobufList<Long> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    long getLong(int index);
+
+    /**
+     * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
+     */
+    void addLong(long element);
+
+    /**
+     * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element.
+     */
+    long setLong(int index, long element);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Doubles if
+   * possible. Does not support null elements.
+   */
+  public static interface DoubleList extends ProtobufList<Double> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    double getDouble(int index);
+
+    /**
+     * Like {@link #add(Double)} but more efficient in that it doesn't box the element.
+     */
+    void addDouble(double element);
+
+    /**
+     * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element.
+     */
+    double setDouble(int index, double element);
+  }
+
+  /**
+   * A {@link java.util.List} implementation that avoids boxing the elements into Floats if
+   * possible. Does not support null elements.
+   */
+  public static interface FloatList extends ProtobufList<Float> {
+
+    /**
+     * Like {@link #get(int)} but more efficient in that it doesn't box the returned value.
+     */
+    float getFloat(int index);
+
+    /**
+     * Like {@link #add(Float)} but more efficient in that it doesn't box the element.
+     */
+    void addFloat(float element);
+
+    /**
+     * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element.
+     */
+    float setFloat(int index, float element);
+  }
 }
diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
index 2d40a51..a2997e1 100644
--- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -62,11 +62,20 @@
  *
  * @author jonp@google.com (Jon Perlow)
  */
-public class LazyStringArrayList extends AbstractList<String>
+public class LazyStringArrayList extends AbstractProtobufList<String>
     implements LazyStringList, RandomAccess {
+  
+  private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  static LazyStringArrayList emptyList() {
+    return EMPTY_LIST;
+  }
 
-  public static final LazyStringList EMPTY =
-      new LazyStringArrayList().getUnmodifiableView();
+  // For compatibility with older runtimes.
+  public static final LazyStringList EMPTY = EMPTY_LIST;
 
   private final List<Object> list;
 
@@ -116,12 +125,26 @@
 
   @Override
   public String set(int index, String s) {
+    ensureIsMutable();
     Object o = list.set(index, s);
     return asString(o);
   }
 
   @Override
   public void add(int index, String element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+  
+  private void add(int index, ByteString element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+  
+  private void add(int index, byte[] element) {
+    ensureIsMutable();
     list.add(index, element);
     modCount++;
   }
@@ -137,6 +160,7 @@
 
   @Override
   public boolean addAll(int index, Collection<? extends String> c) {
+    ensureIsMutable();
     // When copying from another LazyStringList, directly copy the underlying
     // elements rather than forcing each element to be decoded to a String.
     Collection<?> collection = c instanceof LazyStringList
@@ -148,6 +172,7 @@
 
   // @Override
   public boolean addAllByteString(Collection<? extends ByteString> values) {
+    ensureIsMutable();
     boolean ret = list.addAll(values);
     modCount++;
     return ret;
@@ -155,6 +180,7 @@
 
   // @Override
   public boolean addAllByteArray(Collection<byte[]> c) {
+    ensureIsMutable();
     boolean ret = list.addAll(c);
     modCount++;
     return ret;
@@ -162,6 +188,7 @@
 
   @Override
   public String remove(int index) {
+    ensureIsMutable();
     Object o = list.remove(index);
     modCount++;
     return asString(o);
@@ -169,18 +196,21 @@
 
   @Override
   public void clear() {
+    ensureIsMutable();
     list.clear();
     modCount++;
   }
 
   // @Override
   public void add(ByteString element) {
+    ensureIsMutable();
     list.add(element);
     modCount++;
   }
   
   // @Override
   public void add(byte[] element) {
+    ensureIsMutable();
     list.add(element);
     modCount++;
   }
@@ -207,14 +237,23 @@
 
   // @Override
   public void set(int index, ByteString s) {
-    list.set(index, s);
+    setAndReturn(index, s);
+  }
+  
+  private Object setAndReturn(int index, ByteString s) {
+    ensureIsMutable();
+    return list.set(index, s);
   }
 
   // @Override
   public void set(int index, byte[] s) {
-    list.set(index, s);
+    setAndReturn(index, s);
   }
-
+  
+  private Object setAndReturn(int index, byte[] s) {
+    ensureIsMutable();
+    return list.set(index, s);
+  }
 
   private static String asString(Object o) {
     if (o instanceof String) {
@@ -253,6 +292,7 @@
 
   // @Override
   public void mergeFrom(LazyStringList other) {
+    ensureIsMutable();
     for (Object o : other.getUnderlyingElements()) {
       if (o instanceof byte[]) {
         byte[] b = (byte[]) o;
@@ -267,20 +307,15 @@
 
   private static class ByteArrayListView extends AbstractList<byte[]>
       implements RandomAccess {
-    private final List<Object> list;
+    private final LazyStringArrayList list;
     
-    ByteArrayListView(List<Object> list) {
+    ByteArrayListView(LazyStringArrayList list) {
       this.list = list;
     }
     
     @Override
     public byte[] get(int index) {
-      Object o = list.get(index);
-      byte[] b = asByteArray(o);
-      if (b != o) {
-        list.set(index, b);
-      }
-      return b;
+      return list.getByteArray(index);
     }
 
     @Override
@@ -290,7 +325,7 @@
 
     @Override
     public byte[] set(int index, byte[] s) {
-      Object o = list.set(index, s);
+      Object o = list.setAndReturn(index, s);
       modCount++;
       return asByteArray(o);
     }
@@ -311,25 +346,20 @@
   
   // @Override
   public List<byte[]> asByteArrayList() {
-    return new ByteArrayListView(list);
+    return new ByteArrayListView(this);
   }
 
   private static class ByteStringListView extends AbstractList<ByteString>
       implements RandomAccess {
-    private final List<Object> list;
+    private final LazyStringArrayList list;
 
-    ByteStringListView(List<Object> list) {
+    ByteStringListView(LazyStringArrayList list) {
       this.list = list;
     }
 
     @Override
     public ByteString get(int index) {
-      Object o = list.get(index);
-      ByteString b = asByteString(o);
-      if (b != o) {
-        list.set(index, b);
-      }
-      return b;
+      return list.getByteString(index);
     }
 
     @Override
@@ -339,7 +369,7 @@
 
     @Override
     public ByteString set(int index, ByteString s) {
-      Object o = list.set(index, s);
+      Object o = list.setAndReturn(index, s);
       modCount++;
       return asByteString(o);
     }
@@ -360,12 +390,15 @@
 
   // @Override
   public List<ByteString> asByteStringList() {
-    return new ByteStringListView(list);
+    return new ByteStringListView(this);
   }
 
   // @Override
   public LazyStringList getUnmodifiableView() {
-    return new UnmodifiableLazyStringList(this);
+    if (isModifiable()) {
+      return new UnmodifiableLazyStringList(this);
+    }
+    return this;
   }
 
 }
diff --git a/java/src/main/java/com/google/protobuf/LongArrayList.java b/java/src/main/java/com/google/protobuf/LongArrayList.java
new file mode 100644
index 0000000..298617f
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/LongArrayList.java
@@ -0,0 +1,242 @@
+// 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;
+
+import com.google.protobuf.Internal.LongList;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * An implementation of {@link LongList} on top of a primitive array.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+final class LongArrayList extends AbstractProtobufList<Long> implements LongList, RandomAccess {
+  
+  private static final int DEFAULT_CAPACITY = 10;
+  
+  private static final LongArrayList EMPTY_LIST = new LongArrayList();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  public static LongArrayList emptyList() {
+    return EMPTY_LIST;
+  }
+  
+  /**
+   * The backing store for the list.
+   */
+  private long[] array;
+  
+  /**
+   * The size of the list distinct from the length of the array. That is, it is the number of
+   * elements set in the list.
+   */
+  private int size;
+
+  /**
+   * Constructs a new mutable {@code LongArrayList}.
+   */
+  LongArrayList() {
+    array = new long[DEFAULT_CAPACITY];
+    size = 0;
+  }
+
+  /**
+   * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
+   */
+  LongArrayList(List<Long> other) {
+    if (other instanceof LongArrayList) {
+      LongArrayList list = (LongArrayList) other;
+      array = list.array.clone();
+      size = list.size;
+    } else {
+      size = other.size();
+      array = new long[size];
+      for (int i = 0; i < size; i++) {
+        array[i] = other.get(i);
+      }
+    }
+  }
+  
+  @Override
+  public Long get(int index) {
+    return getLong(index);
+  }
+
+  @Override
+  public long getLong(int index) {
+    ensureIndexInRange(index);
+    return array[index];
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Long set(int index, Long element) {
+    return setLong(index, element);
+  }
+
+  @Override
+  public long setLong(int index, long element) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    long previousValue = array[index];
+    array[index] = element;
+    return previousValue;
+  }
+
+  @Override
+  public void add(int index, Long element) {
+    addLong(index, element);
+  }
+
+  /**
+   * Like {@link #add(Long)} but more efficient in that it doesn't box the element.
+   */
+  @Override
+  public void addLong(long element) {
+    addLong(size, element);
+  }
+
+  /**
+   * Like {@link #add(int, Long)} but more efficient in that it doesn't box the element.
+   */
+  private void addLong(int index, long element) {
+    ensureIsMutable();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+    
+    if (size < array.length) {
+      // Shift everything over to make room
+      System.arraycopy(array, index, array, index + 1, size - index);
+    } else {
+      // Resize to 1.5x the size
+      int length = ((size * 3) / 2) + 1;
+      long[] newArray = new long[length];
+      
+      // Copy the first part directly
+      System.arraycopy(array, 0, newArray, 0, index);
+      
+      // Copy the rest shifted over by one to make room
+      System.arraycopy(array, index, newArray, index + 1, size - index);
+      array = newArray;
+    }
+
+    array[index] = element;
+    size++;
+    modCount++;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Long> collection) {
+    ensureIsMutable();
+    
+    if (collection == null) {
+      throw new NullPointerException();
+    }
+    
+    // We specialize when adding another LongArrayList to avoid boxing elements.
+    if (!(collection instanceof LongArrayList)) {
+      return super.addAll(collection);
+    }
+    
+    LongArrayList list = (LongArrayList) collection;
+    if (list.size == 0) {
+      return false;
+    }
+    
+    int overflow = Integer.MAX_VALUE - size;
+    if (overflow < list.size) {
+      // We can't actually represent a list this large.
+      throw new OutOfMemoryError();
+    }
+    
+    int newSize = size + list.size;
+    if (newSize > array.length) {
+      array = Arrays.copyOf(array, newSize);
+    }
+    
+    System.arraycopy(list.array, 0, array, size, list.size);
+    size = newSize;
+    modCount++;
+    return true;
+  }
+  
+  @Override
+  public boolean remove(Object o) {
+    ensureIsMutable();
+    for (int i = 0; i < size; i++) {
+      if (o.equals(array[i])) {
+        System.arraycopy(array, i + 1, array, i, size - i);
+        size--;
+        modCount++;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public Long remove(int index) {
+    ensureIsMutable();
+    ensureIndexInRange(index);
+    long value = array[index];
+    System.arraycopy(array, index + 1, array, index, size - index);
+    size--;
+    modCount++;
+    return value;
+  }
+
+  /**
+   * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
+   * {@link IndexOutOfBoundsException} if it is not.
+   * 
+   * @param index the index to verify is in range
+   */
+  private void ensureIndexInRange(int index) {
+    if (index < 0 || index >= size) {
+      throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
+    }
+  }
+
+  private String makeOutOfBoundsExceptionMessage(int index) {
+    return "Index:" + index + ", Size:" + size;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/MapField.java b/java/src/main/java/com/google/protobuf/MapField.java
index 82906d3..b290993 100644
--- a/java/src/main/java/com/google/protobuf/MapField.java
+++ b/java/src/main/java/com/google/protobuf/MapField.java
@@ -30,9 +30,11 @@
 
 package com.google.protobuf;
 
+import com.google.protobuf.MapFieldLite.MutatabilityAwareMap;
+
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -51,7 +53,7 @@
  * and getList() concurrently in multiple threads. If write-access is needed,
  * all access must be synchronized.
  */
-public class MapField<K, V> {
+public class MapField<K, V> implements MutabilityOracle {
   /**
    * Indicates where the data of this map field is currently stored.
    * 
@@ -72,8 +74,9 @@
    */
   private enum StorageMode {MAP, LIST, BOTH}
 
+  private volatile boolean isMutable;
   private volatile StorageMode mode;
-  private Map<K, V> mapData;
+  private MutatabilityAwareMap<K, V> mapData;
   private List<Message> listData;
   
   // Convert between a map entry Message and a key-value pair.
@@ -110,20 +113,19 @@
   private MapField(
       Converter<K, V> converter,
       StorageMode mode,
-      Map<K, V> mapData,
-      List<Message> listData) {
+      Map<K, V> mapData) {
     this.converter = converter;
+    this.isMutable = true;
     this.mode = mode;
-    this.mapData = mapData;
-    this.listData = listData;
+    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+    this.listData = null;
   }
     
   private MapField(
       MapEntry<K, V> defaultEntry,
       StorageMode mode,
-      Map<K, V> mapData,
-      List<Message> listData) {
-    this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData, listData);
+      Map<K, V> mapData) {
+    this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
   }
   
   
@@ -131,14 +133,14 @@
   public static <K, V> MapField<K, V> emptyMapField(
       MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
-        defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap(), null);
+        defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
   }
   
   
   /** Creates a new mutable empty MapField. */
   public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
-        defaultEntry, StorageMode.MAP, new HashMap<K, V>(), null);
+        defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
   }
   
   
@@ -151,7 +153,7 @@
     converter.convertMessageToKeyAndValue(message, map);
   }
 
-  private List<Message> convertMapToList(Map<K, V> mapData) {
+  private List<Message> convertMapToList(MutatabilityAwareMap<K, V> mapData) {
     List<Message> listData = new ArrayList<Message>();
     for (Map.Entry<K, V> entry : mapData.entrySet()) {
       listData.add(
@@ -161,12 +163,12 @@
     return listData;
   }
 
-  private Map<K, V> convertListToMap(List<Message> listData) {
-    Map<K, V> mapData = new HashMap<K, V>();
+  private MutatabilityAwareMap<K, V> convertListToMap(List<Message> listData) {
+    Map<K, V> mapData = new LinkedHashMap<K, V>();
     for (Message item : listData) {
       convertMessageToKeyAndValue(item, mapData);
     }
-    return mapData;
+    return new MutatabilityAwareMap<K, V>(this, mapData);
   }
   
   /** Returns the content of this MapField as a read-only Map. */
@@ -199,7 +201,7 @@
   }
   
   public void clear() {
-    mapData = new HashMap<K, V>();
+    mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
     mode = StorageMode.MAP;
   }
   
@@ -221,7 +223,7 @@
   /** Returns a deep copy of this MapField. */
   public MapField<K, V> copy() {
     return new MapField<K, V>(
-        converter, StorageMode.MAP, MapFieldLite.copy(getMap()), null);
+        converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
   }
   
   /** Gets the content of this MapField as a read-only List. */
@@ -256,4 +258,29 @@
   Message getMapEntryMessageDefaultInstance() {
     return converter.getMessageDefaultInstance();
   }
+  
+  /**
+   * Makes this list immutable. All subsequent modifications will throw an
+   * {@link UnsupportedOperationException}.
+   */
+  public void makeImmutable() {
+    isMutable = false;
+  }
+  
+  /**
+   * Returns whether this field can be modified.
+   */
+  public boolean isMutable() {
+    return isMutable;
+  }
+  
+  /* (non-Javadoc)
+   * @see com.google.protobuf.MutabilityOracle#ensureMutable()
+   */
+  @Override
+  public void ensureMutable() {
+    if (!isMutable()) {
+      throw new UnsupportedOperationException();
+    }
+  }
 }
diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/src/main/java/com/google/protobuf/MapFieldLite.java
index 7f94c69..c17fa7b 100644
--- a/java/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -31,9 +31,12 @@
 package com.google.protobuf;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Internal representation of map fields in generated lite-runtime messages.
@@ -41,16 +44,21 @@
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
  */
-public class MapFieldLite<K, V> {
-  private Map<K, V> mapData;
+public class MapFieldLite<K, V> implements MutabilityOracle {
+  private MutatabilityAwareMap<K, V> mapData;
+  private boolean isMutable;
   
   private MapFieldLite(Map<K, V> mapData) {
-    this.mapData = mapData;
+    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+    this.isMutable = true;
   }
   
   @SuppressWarnings({"rawtypes", "unchecked"})
   private static final MapFieldLite EMPTY_MAP_FIELD =
       new MapFieldLite(Collections.emptyMap());
+  static {
+    EMPTY_MAP_FIELD.makeImmutable();
+  }
   
   /** Returns an singleton immutable empty MapFieldLite instance. */
   @SuppressWarnings({"unchecked", "cast"})
@@ -60,7 +68,7 @@
   
   /** Creates a new MapFieldLite instance. */
   public static <K, V> MapFieldLite<K, V> newMapField() {
-    return new MapFieldLite<K, V>(new HashMap<K, V>());
+    return new MapFieldLite<K, V>(new LinkedHashMap<K, V>());
   }
   
   /** Gets the content of this MapField as a read-only Map. */
@@ -168,7 +176,7 @@
    */
   @SuppressWarnings("unchecked")
   static <K, V> Map<K, V> copy(Map<K, V> map) {
-    Map<K, V> result = new HashMap<K, V>();
+    Map<K, V> result = new LinkedHashMap<K, V>();
     for (Map.Entry<K, V> entry : map.entrySet()) {
       result.put(entry.getKey(), (V) copy(entry.getValue()));
     }
@@ -179,4 +187,360 @@
   public MapFieldLite<K, V> copy() {
     return new MapFieldLite<K, V>(copy(mapData));
   }
+  
+  /**
+   * Makes this field immutable. All subsequent modifications will throw an
+   * {@link UnsupportedOperationException}.
+   */
+  public void makeImmutable() {
+    isMutable = false;
+  }
+  
+  /**
+   * Returns whether this field can be modified.
+   */
+  public boolean isMutable() {
+    return isMutable;
+  }
+  
+  @Override
+  public void ensureMutable() {
+    if (!isMutable()) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  /**
+   * An internal map that checks for mutability before delegating.
+   */
+  static class MutatabilityAwareMap<K, V> implements Map<K, V> {    
+    private final MutabilityOracle mutabilityOracle;
+    private final Map<K, V> delegate;
+    
+    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+      return delegate.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+      return delegate.containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+      return delegate.get(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      mutabilityOracle.ensureMutable();
+      return delegate.put(key, value);
+    }
+
+    @Override
+    public V remove(Object key) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+      mutabilityOracle.ensureMutable();
+      delegate.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+
+  /**
+   * An internal collection that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareCollection<E> implements Collection<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Collection<E> delegate;
+    
+    MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      return delegate.contains(o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+    }
+
+    @Override
+    public Object[] toArray() {
+      return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+      return delegate.toArray(a);
+    }
+
+    @Override
+    public boolean add(E e) {
+      // Unsupported operation in the delegate.
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean remove(Object o) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(o);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+      return delegate.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+      // Unsupported operation in the delegate.
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.removeAll(c);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.retainAll(c);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+    
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+
+  /**
+   * An internal set that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareSet<E> implements Set<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Set<E> delegate;
+    
+    MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      return delegate.contains(o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+    }
+
+    @Override
+    public Object[] toArray() {
+      return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+      return delegate.toArray(a);
+    }
+
+    @Override
+    public boolean add(E e) {
+      mutabilityOracle.ensureMutable();
+      return delegate.add(e);
+    }
+
+    @Override
+    public boolean remove(Object o) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(o);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+      return delegate.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.addAll(c);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.retainAll(c);
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+      mutabilityOracle.ensureMutable();
+      return delegate.removeAll(c);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
+  
+  /**
+   * An internal iterator that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareIterator<E> implements Iterator<E> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Iterator<E> delegate;
+    
+    MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public boolean hasNext() {
+      return delegate.hasNext();
+    }
+
+    @Override
+    public E next() {
+      return delegate.next();
+    }
+
+    @Override
+    public void remove() {
+      mutabilityOracle.ensureMutable();
+      delegate.remove();
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+      return delegate.equals(obj);
+    }
+    
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+  }
 }
diff --git a/java/src/main/java/com/google/protobuf/MutabilityOracle.java b/java/src/main/java/com/google/protobuf/MutabilityOracle.java
new file mode 100644
index 0000000..82b723c
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/MutabilityOracle.java
@@ -0,0 +1,48 @@
+// 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;
+
+/**
+ * Verifies that an object is mutable, throwing if not.
+ */
+interface MutabilityOracle {
+  static final MutabilityOracle IMMUTABLE = new MutabilityOracle() {
+    @Override
+    public void ensureMutable() {
+      throw new UnsupportedOperationException();
+    }
+  };
+
+  /**
+   * Throws an {@link UnsupportedOperationException} if not mutable.
+   */
+  void ensureMutable();
+}
diff --git a/java/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/src/main/java/com/google/protobuf/ProtobufArrayList.java
new file mode 100644
index 0000000..759368c
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -0,0 +1,95 @@
+// 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;
+
+import com.google.protobuf.Internal.ProtobufList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements {@link ProtobufList} for non-primitive and {@link String} types.
+ */
+class ProtobufArrayList<E> extends AbstractProtobufList<E> {
+
+  private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
+  static {
+    EMPTY_LIST.makeImmutable();
+  }
+  
+  @SuppressWarnings("unchecked") // Guaranteed safe by runtime.
+  public static <E> ProtobufArrayList<E> emptyList() {
+    return (ProtobufArrayList<E>) EMPTY_LIST;
+  }
+  
+  private final List<E> list;
+  
+  ProtobufArrayList() {
+    list = new ArrayList<E>();
+  }
+  
+  ProtobufArrayList(List<E> toCopy) {
+    list = new ArrayList<E>(toCopy);
+  }
+  
+  @Override
+  public void add(int index, E element) {
+    ensureIsMutable();
+    list.add(index, element);
+    modCount++;
+  }
+
+  @Override
+  public E get(int index) {
+    return list.get(index);
+  }
+  
+  @Override
+  public E remove(int index) {
+    ensureIsMutable();
+    E toReturn = list.remove(index);
+    modCount++;
+    return toReturn;
+  }
+  
+  @Override
+  public E set(int index, E element) {
+    ensureIsMutable();
+    E toReturn = list.set(index, element);
+    modCount++;
+    return toReturn;
+  }
+
+  @Override
+  public int size() {
+    return list.size();
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index dd2b460..a79ce55 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -1725,7 +1725,7 @@
    * {@link #escapeBytes(ByteString)}.  Two-digit hex escapes (starting with
    * "\x") are also recognized.
    */
-  static ByteString unescapeBytes(final CharSequence charString)
+  public static ByteString unescapeBytes(final CharSequence charString)
       throws InvalidEscapeSequenceException {
     // First convert the Java character sequence to UTF-8 bytes.
     ByteString input = ByteString.copyFromUtf8(charString.toString());
@@ -1808,7 +1808,7 @@
    * Thrown by {@link TextFormat#unescapeBytes} and
    * {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
    */
-  static class InvalidEscapeSequenceException extends IOException {
+  public static class InvalidEscapeSequenceException extends IOException {
     private static final long serialVersionUID = -8164033650142593304L;
 
     InvalidEscapeSequenceException(final String description) {
diff --git a/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java
new file mode 100644
index 0000000..df89c26
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -0,0 +1,473 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link BooleanArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class BooleanArrayListTest extends TestCase {
+  
+  private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
+  private static final BooleanArrayList TERTIARY_LIST =
+      newImmutableBooleanArrayList(true, true, false);
+  
+  private BooleanArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new BooleanArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(BooleanArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addBoolean(true);
+    list.addBoolean(false);
+    list.addBoolean(true);
+    list.addBoolean(true);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testCopyConstructor() {
+    BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new BooleanArrayList(BooleanArrayList.emptyList());
+    assertEquals(BooleanArrayList.emptyList(), copy);
+    
+    copy = new BooleanArrayList(asList(false, false, true));
+    assertEquals(asList(false, false, true), copy);
+
+    copy = new BooleanArrayList(Collections.<Boolean>emptyList());
+    assertEquals(BooleanArrayList.emptyList(), copy);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(true, false, false, true));
+    Iterator<Boolean> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, (boolean) iterator.next());
+    list.set(0, true);
+    assertEquals(false, (boolean) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, false);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(true, (boolean) TERTIARY_LIST.get(0));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(1));
+    assertEquals(false, (boolean) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(true, TERTIARY_LIST.getBoolean(0));
+    assertEquals(true, TERTIARY_LIST.getBoolean(1));
+    assertEquals(false, TERTIARY_LIST.getBoolean(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, BooleanArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addBoolean(true);
+    list.addBoolean(false);
+    list.addBoolean(false);
+    list.addBoolean(false);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(true);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addBoolean(false);
+    list.addBoolean(false);
+    
+    assertEquals(false, (boolean) list.set(0, true));
+    assertEquals(true, list.getBoolean(0));
+
+    assertEquals(false, (boolean) list.set(1, false));
+    assertEquals(false, list.getBoolean(1));
+    
+    try {
+      list.set(-1, true);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, false);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addBoolean(true);
+    list.addBoolean(true);
+    
+    assertEquals(true, list.setBoolean(0, false));
+    assertEquals(false, list.getBoolean(0));
+
+    assertEquals(true, list.setBoolean(1, false));
+    assertEquals(false, list.getBoolean(1));
+    
+    try {
+      list.setBoolean(-1, false);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setBoolean(2, true);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(true));
+    assertEquals(asList(true), list);
+
+    assertTrue(list.add(false));
+    list.add(0, false);
+    assertEquals(asList(false, true, false), list);
+    
+    list.add(0, false);
+    list.add(0, true);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(true);
+    }
+    assertEquals(asList(true, false, false, true, false, true, true, true, true, true, true), list);
+    
+    try {
+      list.add(-1, false);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, true);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addBoolean(true);
+    assertEquals(asList(true), list);
+
+    list.addBoolean(false);
+    assertEquals(asList(true, false), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(false)));
+    assertEquals(1, list.size());
+    assertEquals(false, (boolean) list.get(0));
+    assertEquals(false, list.getBoolean(0));
+    
+    assertTrue(list.addAll(asList(true, false, false, false, true)));
+    assertEquals(asList(false, true, false, false, false, true), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(false, true, false, false, false, true, true, true, false), list);
+
+    assertFalse(list.addAll(Collections.<Boolean>emptyList()));
+    assertFalse(list.addAll(BooleanArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(true, (boolean) list.remove(0));
+    assertEquals(asList(true, false), list);
+
+    assertTrue(list.remove(Boolean.TRUE));
+    assertEquals(asList(false), list);
+
+    assertFalse(list.remove(Boolean.TRUE));
+    assertEquals(asList(false), list);
+
+    assertEquals(false, (boolean) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(BooleanArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(false);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(false));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new BooleanArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(true));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addBoolean(true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Boolean>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, true);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setBoolean(0, false);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static BooleanArrayList newImmutableBooleanArrayList(boolean... elements) {
+    BooleanArrayList list = new BooleanArrayList();
+    for (boolean element : elements) {
+      list.addBoolean(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
index 6cfa18d..edd7fc4 100644
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -56,6 +56,7 @@
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
 import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
 import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestReservedFields;
 import protobuf_unittest.UnittestProto.TestService;
 
 import junit.framework.TestCase;
@@ -687,6 +688,9 @@
 
     assertEquals(4, oneofDescriptor.getFieldCount());
     assertSame(oneofDescriptor.getField(1), field);
+
+    assertEquals(4, oneofDescriptor.getFields().size());
+    assertEquals(oneofDescriptor.getFields().get(1), field);
   }
 
   public void testMessageDescriptorExtensions() throws Exception {
@@ -702,6 +706,19 @@
     assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
   }
 
+  public void testReservedFields() {
+    Descriptor d = TestReservedFields.getDescriptor();
+    assertTrue(d.isReservedNumber(2));
+    assertFalse(d.isReservedNumber(8));
+    assertTrue(d.isReservedNumber(9));
+    assertTrue(d.isReservedNumber(10));
+    assertTrue(d.isReservedNumber(11));
+    assertFalse(d.isReservedNumber(12));
+    assertFalse(d.isReservedName("foo"));
+    assertTrue(d.isReservedName("bar"));
+    assertTrue(d.isReservedName("baz"));
+  }
+
   public void testToString() {
     assertEquals("protobuf_unittest.TestAllTypes.optional_uint64",
         UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber(
diff --git a/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java
new file mode 100644
index 0000000..e7a73d7
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -0,0 +1,473 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link DoubleArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class DoubleArrayListTest extends TestCase {
+  
+  private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
+  private static final DoubleArrayList TERTIARY_LIST =
+      newImmutableDoubleArrayList(1, 2, 3);
+  
+  private DoubleArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new DoubleArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(DoubleArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addDouble(2);
+    list.addDouble(4);
+    list.addDouble(6);
+    list.addDouble(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testCopyConstructor() {
+    DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new DoubleArrayList(DoubleArrayList.emptyList());
+    assertEquals(DoubleArrayList.emptyList(), copy);
+    
+    copy = new DoubleArrayList(asList(1D, 2D, 3D));
+    assertEquals(asList(1D, 2D, 3D), copy);
+
+    copy = new DoubleArrayList(Collections.<Double>emptyList());
+    assertEquals(DoubleArrayList.emptyList(), copy);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1D, 2D, 3D, 4D));
+    Iterator<Double> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1D, (double) list.get(0));
+    assertEquals(1D, (double) iterator.next());
+    list.set(0, 1D);
+    assertEquals(2D, (double) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0D);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1D, (double) TERTIARY_LIST.get(0));
+    assertEquals(2D, (double) TERTIARY_LIST.get(1));
+    assertEquals(3D, (double) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(1D, TERTIARY_LIST.getDouble(0));
+    assertEquals(2D, TERTIARY_LIST.getDouble(1));
+    assertEquals(3D, TERTIARY_LIST.getDouble(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, DoubleArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addDouble(2);
+    list.addDouble(4);
+    list.addDouble(6);
+    list.addDouble(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16D);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addDouble(2);
+    list.addDouble(4);
+    
+    assertEquals(2D, (double) list.set(0, 0D));
+    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(4D, (double) list.set(1, 0D));
+    assertEquals(0D, list.getDouble(1));
+    
+    try {
+      list.set(-1, 0D);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0D);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addDouble(2);
+    list.addDouble(4);
+    
+    assertEquals(2D, list.setDouble(0, 0));
+    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(4D, list.setDouble(1, 0));
+    assertEquals(0D, list.getDouble(1));
+    
+    try {
+      list.setDouble(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setDouble(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2D));
+    assertEquals(asList(2D), list);
+
+    assertTrue(list.add(3D));
+    list.add(0, 4D);
+    assertEquals(asList(4D, 2D, 3D), list);
+    
+    list.add(0, 1D);
+    list.add(0, 0D);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Double.valueOf(5 + i));
+    }
+    assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list);
+    
+    try {
+      list.add(-1, 5D);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5D);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addDouble(2);
+    assertEquals(asList(2D), list);
+
+    list.addDouble(3);
+    assertEquals(asList(2D, 3D), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1D)));
+    assertEquals(1, list.size());
+    assertEquals(1D, (double) list.get(0));
+    assertEquals(1D, list.getDouble(0));
+    
+    assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
+    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list);
+
+    assertFalse(list.addAll(Collections.<Double>emptyList()));
+    assertFalse(list.addAll(DoubleArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1D, (double) list.remove(0));
+    assertEquals(asList(2D, 3D), list);
+
+    assertTrue(list.remove(Double.valueOf(3)));
+    assertEquals(asList(2D), list);
+
+    assertFalse(list.remove(Double.valueOf(3)));
+    assertEquals(asList(2D), list);
+
+    assertEquals(2D, (double) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(DoubleArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new DoubleArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1D));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addDouble(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.retainAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0D);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setDouble(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static DoubleArrayList newImmutableDoubleArrayList(double... elements) {
+    DoubleArrayList list = new DoubleArrayList();
+    for (double element : elements) {
+      list.addDouble(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/src/test/java/com/google/protobuf/FloatArrayListTest.java
new file mode 100644
index 0000000..8f3e93d
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -0,0 +1,473 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link FloatArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class FloatArrayListTest extends TestCase {
+  
+  private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
+  private static final FloatArrayList TERTIARY_LIST =
+      newImmutableFloatArrayList(1, 2, 3);
+  
+  private FloatArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new FloatArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(FloatArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addFloat(2);
+    list.addFloat(4);
+    list.addFloat(6);
+    list.addFloat(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testCopyConstructor() {
+    FloatArrayList copy = new FloatArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new FloatArrayList(FloatArrayList.emptyList());
+    assertEquals(FloatArrayList.emptyList(), copy);
+    
+    copy = new FloatArrayList(asList(1F, 2F, 3F));
+    assertEquals(asList(1F, 2F, 3F), copy);
+
+    copy = new FloatArrayList(Collections.<Float>emptyList());
+    assertEquals(FloatArrayList.emptyList(), copy);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1F, 2F, 3F, 4F));
+    Iterator<Float> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1F, (float) list.get(0));
+    assertEquals(1F, (float) iterator.next());
+    list.set(0, 1F);
+    assertEquals(2F, (float) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0F);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1F, (float) TERTIARY_LIST.get(0));
+    assertEquals(2F, (float) TERTIARY_LIST.get(1));
+    assertEquals(3F, (float) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetFloat() {
+    assertEquals(1F, TERTIARY_LIST.getFloat(0));
+    assertEquals(2F, TERTIARY_LIST.getFloat(1));
+    assertEquals(3F, TERTIARY_LIST.getFloat(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, FloatArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addFloat(2);
+    list.addFloat(4);
+    list.addFloat(6);
+    list.addFloat(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16F);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addFloat(2);
+    list.addFloat(4);
+    
+    assertEquals(2F, (float) list.set(0, 0F));
+    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(4F, (float) list.set(1, 0F));
+    assertEquals(0F, list.getFloat(1));
+    
+    try {
+      list.set(-1, 0F);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0F);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetFloat() {
+    list.addFloat(2);
+    list.addFloat(4);
+    
+    assertEquals(2F, list.setFloat(0, 0));
+    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(4F, list.setFloat(1, 0));
+    assertEquals(0F, list.getFloat(1));
+    
+    try {
+      list.setFloat(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setFloat(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2F));
+    assertEquals(asList(2F), list);
+
+    assertTrue(list.add(3F));
+    list.add(0, 4F);
+    assertEquals(asList(4F, 2F, 3F), list);
+    
+    list.add(0, 1F);
+    list.add(0, 0F);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Float.valueOf(5 + i));
+    }
+    assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list);
+    
+    try {
+      list.add(-1, 5F);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5F);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddFloat() {
+    assertEquals(0, list.size());
+
+    list.addFloat(2);
+    assertEquals(asList(2F), list);
+
+    list.addFloat(3);
+    assertEquals(asList(2F, 3F), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1F)));
+    assertEquals(1, list.size());
+    assertEquals(1F, (float) list.get(0));
+    assertEquals(1F, list.getFloat(0));
+    
+    assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
+    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list);
+
+    assertFalse(list.addAll(Collections.<Float>emptyList()));
+    assertFalse(list.addAll(FloatArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1F, (float) list.remove(0));
+    assertEquals(asList(2F, 3F), list);
+
+    assertTrue(list.remove(Float.valueOf(3)));
+    assertEquals(asList(2F), list);
+
+    assertFalse(list.remove(Float.valueOf(3)));
+    assertEquals(asList(2F), list);
+
+    assertEquals(2F, (float) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(FloatArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new FloatArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1F));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addFloat(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Float>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0F);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setFloat(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static FloatArrayList newImmutableFloatArrayList(int... elements) {
+    FloatArrayList list = new FloatArrayList();
+    for (int element : elements) {
+      list.addFloat(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/src/test/java/com/google/protobuf/IntArrayListTest.java
new file mode 100644
index 0000000..3733eb3
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -0,0 +1,473 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link IntArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class IntArrayListTest extends TestCase {
+  
+  private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
+  private static final IntArrayList TERTIARY_LIST =
+      newImmutableIntArrayList(1, 2, 3);
+  
+  private IntArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new IntArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(IntArrayList.emptyList(), IntArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(IntArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addInt(2);
+    list.addInt(4);
+    list.addInt(6);
+    list.addInt(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testCopyConstructor() {
+    IntArrayList copy = new IntArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new IntArrayList(IntArrayList.emptyList());
+    assertEquals(IntArrayList.emptyList(), copy);
+    
+    copy = new IntArrayList(asList(1, 2, 3));
+    assertEquals(asList(1, 2, 3), copy);
+
+    copy = new IntArrayList(Collections.<Integer>emptyList());
+    assertEquals(IntArrayList.emptyList(), copy);
+  }
+
+  public void testModificationWithIteration() {
+    list.addAll(asList(1, 2, 3, 4));
+    Iterator<Integer> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, (int) iterator.next());
+    list.set(0, 1);
+    assertEquals(2, (int) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+
+    iterator = list.iterator();
+    list.add(0, 0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1, (int) TERTIARY_LIST.get(0));
+    assertEquals(2, (int) TERTIARY_LIST.get(1));
+    assertEquals(3, (int) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetInt() {
+    assertEquals(1, TERTIARY_LIST.getInt(0));
+    assertEquals(2, TERTIARY_LIST.getInt(1));
+    assertEquals(3, TERTIARY_LIST.getInt(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, IntArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addInt(2);
+    list.addInt(4);
+    list.addInt(6);
+    list.addInt(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addInt(2);
+    list.addInt(4);
+    
+    assertEquals(2, (int) list.set(0, 0));
+    assertEquals(0, list.getInt(0));
+
+    assertEquals(4, (int) list.set(1, 0));
+    assertEquals(0, list.getInt(1));
+    
+    try {
+      list.set(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetInt() {
+    list.addInt(2);
+    list.addInt(4);
+    
+    assertEquals(2, list.setInt(0, 0));
+    assertEquals(0, list.getInt(0));
+
+    assertEquals(4, list.setInt(1, 0));
+    assertEquals(0, list.getInt(1));
+    
+    try {
+      list.setInt(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setInt(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2));
+    assertEquals(asList(2), list);
+
+    assertTrue(list.add(3));
+    list.add(0, 4);
+    assertEquals(asList(4, 2, 3), list);
+    
+    list.add(0, 1);
+    list.add(0, 0);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(5 + i);
+    }
+    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
+    
+    try {
+      list.add(-1, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddInt() {
+    assertEquals(0, list.size());
+
+    list.addInt(2);
+    assertEquals(asList(2), list);
+
+    list.addInt(3);
+    assertEquals(asList(2, 3), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1)));
+    assertEquals(1, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, list.getInt(0));
+    
+    assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
+    assertEquals(asList(1, 2, 3, 4, 5, 6), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
+
+    assertFalse(list.addAll(Collections.<Integer>emptyList()));
+    assertFalse(list.addAll(IntArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1, (int) list.remove(0));
+    assertEquals(asList(2, 3), list);
+
+    assertTrue(list.remove(Integer.valueOf(3)));
+    assertEquals(asList(2), list);
+
+    assertFalse(list.remove(Integer.valueOf(3)));
+    assertEquals(asList(2), list);
+
+    assertEquals(2, (int) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(IntArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new IntArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addInt(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setInt(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static IntArrayList newImmutableIntArrayList(int... elements) {
+    IntArrayList list = new IntArrayList();
+    for (int element : elements) {
+      list.addInt(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
index f3012b9..0f42ac5 100644
--- a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
+++ b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java
@@ -30,9 +30,13 @@
 
 package com.google.protobuf;
 
+import static java.util.Arrays.asList;
+
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -171,4 +175,188 @@
     assertSame(BYTE_STRING_B, list2.getByteString(1));
     assertSame(BYTE_STRING_C, list2.getByteString(2));
   }
+  
+  public void testModificationWithIteration() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.addAll(asList(STRING_A, STRING_B, STRING_C));
+    Iterator<String> iterator = list.iterator();
+    assertEquals(3, list.size());
+    assertEquals(STRING_A, list.get(0));
+    assertEquals(STRING_A, iterator.next());
+    
+    // Does not structurally modify.
+    iterator = list.iterator();
+    list.set(0, STRING_B);
+    iterator.next();
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, STRING_C);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testMakeImmutable() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.add(STRING_B);
+    list.add(STRING_C);
+    list.makeImmutable();
+    assertGenericListImmutable(list, STRING_A);
+    
+    // LazyStringArrayList has extra methods not covered in the generic
+    // assertion.
+    
+    try {
+      list.add(BYTE_STRING_A.toByteArray());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(BYTE_STRING_A);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAllByteArray(asList(BYTE_STRING_A.toByteArray()));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAllByteString(asList(BYTE_STRING_A));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.mergeFrom(new LazyStringArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, BYTE_STRING_A.toByteArray());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, BYTE_STRING_A);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  public void testImmutabilityPropagation() {
+    LazyStringArrayList list = new LazyStringArrayList();
+    list.add(STRING_A);
+    list.makeImmutable();
+
+    assertGenericListImmutable(list.asByteStringList(), BYTE_STRING_A);
+    
+    // Arrays use reference equality so need to retrieve the underlying value
+    // to properly test deep immutability.
+    List<byte[]> byteArrayList = list.asByteArrayList();
+    assertGenericListImmutable(byteArrayList, byteArrayList.get(0));
+  }
+  
+  private static <T> void assertGenericListImmutable(List<T> list, T value) {
+    try {
+      list.add(value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(asList(value));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(asList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(asList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
 }
diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java
index 4d8037f..8c3b5e5 100644
--- a/java/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/src/test/java/com/google/protobuf/LiteTest.java
@@ -30,9 +30,18 @@
 
 package com.google.protobuf;
 
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+
 import com.google.protobuf.UnittestLite;
-import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
 import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
+import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
 import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
 
 import junit.framework.TestCase;
@@ -149,13 +158,1302 @@
   public void testClone() {
     TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder()
         .setOptionalInt32(123);
-   assertEquals(
-       expected.getOptionalInt32(), expected.clone().getOptionalInt32());
+    assertEquals(
+        expected.getOptionalInt32(), expected.clone().getOptionalInt32());
    
-   TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
-       .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
-   assertEquals(
-       expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
-       expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
+    TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalInt32ExtensionLite, 123);
+    assertEquals(
+        expected2.getExtension(UnittestLite.optionalInt32ExtensionLite),
+        expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite));
+  }
+  
+  public void testAddAll() {
+    try {
+      TestAllTypesLite.newBuilder()
+          .addAllRepeatedBytes(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+  }
+  
+  public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
+    // Since builders are implemented as a thin wrapper around a message
+    // instance, we attempt to verify that we can't cause the builder to modify
+    // a produced message.
+
+    TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
+    TestAllTypesLite message = builder.build();
+    TestAllTypesLite messageAfterBuild;
+    builder.setOptionalBool(true);
+    assertEquals(false, message.getOptionalBool());
+    assertEquals(true, builder.getOptionalBool());
+    messageAfterBuild = builder.build();
+    assertEquals(true, messageAfterBuild.getOptionalBool());
+    assertEquals(false, message.getOptionalBool());
+    builder.clearOptionalBool();
+    assertEquals(false, builder.getOptionalBool());
+    assertEquals(true, messageAfterBuild.getOptionalBool());
+
+    message = builder.build();
+    builder.setOptionalBytes(ByteString.copyFromUtf8("hi"));
+    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+    builder.clearOptionalBytes();
+    assertEquals(ByteString.EMPTY, builder.getOptionalBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes());
+
+    message = builder.build();
+    builder.setOptionalCord("hi");
+    assertEquals("", message.getOptionalCord());
+    assertEquals("hi", builder.getOptionalCord());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalCord());
+    assertEquals("", message.getOptionalCord());
+    builder.clearOptionalCord();
+    assertEquals("", builder.getOptionalCord());
+    assertEquals("hi", messageAfterBuild.getOptionalCord());
+
+    message = builder.build();
+    builder.setOptionalCordBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
+    assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalCordBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalCordBytes());
+    builder.clearOptionalCord();
+    assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalCordBytes());
+    
+    message = builder.build();
+    builder.setOptionalDouble(1);
+    assertEquals(0D, message.getOptionalDouble());
+    assertEquals(1D, builder.getOptionalDouble());
+    messageAfterBuild = builder.build();
+    assertEquals(1D, messageAfterBuild.getOptionalDouble());
+    assertEquals(0D, message.getOptionalDouble());
+    builder.clearOptionalDouble();
+    assertEquals(0D, builder.getOptionalDouble());
+    assertEquals(1D, messageAfterBuild.getOptionalDouble());
+    
+    message = builder.build();
+    builder.setOptionalFixed32(1);
+    assertEquals(0, message.getOptionalFixed32());
+    assertEquals(1, builder.getOptionalFixed32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalFixed32());
+    assertEquals(0, message.getOptionalFixed32());
+    builder.clearOptionalFixed32();
+    assertEquals(0, builder.getOptionalFixed32());
+    assertEquals(1, messageAfterBuild.getOptionalFixed32());
+    
+    message = builder.build();
+    builder.setOptionalFixed64(1);
+    assertEquals(0L, message.getOptionalFixed64());
+    assertEquals(1L, builder.getOptionalFixed64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
+    assertEquals(0L, message.getOptionalFixed64());
+    builder.clearOptionalFixed64();
+    assertEquals(0L, builder.getOptionalFixed64());
+    assertEquals(1L, messageAfterBuild.getOptionalFixed64());
+
+    message = builder.build();
+    builder.setOptionalFloat(1);
+    assertEquals(0F, message.getOptionalFloat());
+    assertEquals(1F, builder.getOptionalFloat());
+    messageAfterBuild = builder.build();
+    assertEquals(1F, messageAfterBuild.getOptionalFloat());
+    assertEquals(0F, message.getOptionalFloat());
+    builder.clearOptionalFloat();
+    assertEquals(0F, builder.getOptionalFloat());
+    assertEquals(1F, messageAfterBuild.getOptionalFloat());
+
+    message = builder.build();
+    builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum());
+    builder.clearOptionalForeignEnum();
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum());
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getOptionalForeignEnum());
+
+    message = builder.build();
+    ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder()
+        .setC(1)
+        .build();
+    builder.setOptionalForeignMessage(foreignMessage);
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    assertEquals(foreignMessage, builder.getOptionalForeignMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    builder.clearOptionalForeignMessage();
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getOptionalForeignMessage());
+    assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage());
+
+    message = builder.build();
+    ForeignMessageLite.Builder foreignMessageBuilder =
+        ForeignMessageLite.newBuilder()
+            .setC(3);
+    builder.setOptionalForeignMessage(foreignMessageBuilder);
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on foreignMessage.
+    assertEquals(3, builder.getOptionalForeignMessage().getC());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        message.getOptionalForeignMessage());
+    builder.clearOptionalForeignMessage();
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getOptionalForeignMessage());
+    assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC());
+
+    message = builder.build();
+    OptionalGroup optionalGroup = OptionalGroup.newBuilder()
+        .setA(1)
+        .build();
+    builder.setOptionalGroup(optionalGroup);
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    assertEquals(optionalGroup, builder.getOptionalGroup());
+    messageAfterBuild = builder.build();
+    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    builder.clearOptionalGroup();
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup());
+
+    message = builder.build();
+    OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder()
+        .setA(3);
+    builder.setOptionalGroup(optionalGroupBuilder);
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on optionalGroup.
+    assertEquals(3, builder.getOptionalGroup().getA());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), message.getOptionalGroup());
+    builder.clearOptionalGroup();
+    assertEquals(
+        OptionalGroup.getDefaultInstance(), builder.getOptionalGroup());
+    assertEquals(3, messageAfterBuild.getOptionalGroup().getA());
+
+    message = builder.build();
+    builder.setOptionalInt32(1);
+    assertEquals(0, message.getOptionalInt32());
+    assertEquals(1, builder.getOptionalInt32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalInt32());
+    assertEquals(0, message.getOptionalInt32());
+    builder.clearOptionalInt32();
+    assertEquals(0, builder.getOptionalInt32());
+    assertEquals(1, messageAfterBuild.getOptionalInt32());
+
+    message = builder.build();
+    builder.setOptionalInt64(1);
+    assertEquals(0L, message.getOptionalInt64());
+    assertEquals(1L, builder.getOptionalInt64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalInt64());
+    assertEquals(0L, message.getOptionalInt64());
+    builder.clearOptionalInt64();
+    assertEquals(0L, builder.getOptionalInt64());
+    assertEquals(1L, messageAfterBuild.getOptionalInt64());
+    
+    message = builder.build();
+    NestedMessage nestedMessage = NestedMessage.newBuilder()
+        .setBb(1)
+        .build();
+    builder.setOptionalLazyMessage(nestedMessage);
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    assertEquals(nestedMessage, builder.getOptionalLazyMessage());
+    messageAfterBuild = builder.build();
+    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    builder.clearOptionalLazyMessage();
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage());
+
+    message = builder.build();
+    NestedMessage.Builder nestedMessageBuilder =
+        NestedMessage.newBuilder()
+            .setBb(3);
+    builder.setOptionalLazyMessage(nestedMessageBuilder);
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, builder.getOptionalLazyMessage().getBb());
+    messageAfterBuild = builder.build();
+    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+    assertEquals(
+        NestedMessage.getDefaultInstance(),
+        message.getOptionalLazyMessage());
+    builder.clearOptionalLazyMessage();
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage());
+    assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb());
+
+    message = builder.build();
+    builder.setOptionalSfixed32(1);
+    assertEquals(0, message.getOptionalSfixed32());
+    assertEquals(1, builder.getOptionalSfixed32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
+    assertEquals(0, message.getOptionalSfixed32());
+    builder.clearOptionalSfixed32();
+    assertEquals(0, builder.getOptionalSfixed32());
+    assertEquals(1, messageAfterBuild.getOptionalSfixed32());
+
+    message = builder.build();
+    builder.setOptionalSfixed64(1);
+    assertEquals(0L, message.getOptionalSfixed64());
+    assertEquals(1L, builder.getOptionalSfixed64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
+    assertEquals(0L, message.getOptionalSfixed64());
+    builder.clearOptionalSfixed64();
+    assertEquals(0L, builder.getOptionalSfixed64());
+    assertEquals(1L, messageAfterBuild.getOptionalSfixed64());
+
+    message = builder.build();
+    builder.setOptionalSint32(1);
+    assertEquals(0, message.getOptionalSint32());
+    assertEquals(1, builder.getOptionalSint32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalSint32());
+    builder.clearOptionalSint32();
+    assertEquals(0, builder.getOptionalSint32());
+    assertEquals(1, messageAfterBuild.getOptionalSint32());
+
+    message = builder.build();
+    builder.setOptionalSint64(1);
+    assertEquals(0L, message.getOptionalSint64());
+    assertEquals(1L, builder.getOptionalSint64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalSint64());
+    assertEquals(0L, message.getOptionalSint64());
+    builder.clearOptionalSint64();
+    assertEquals(0L, builder.getOptionalSint64());
+    assertEquals(1L, messageAfterBuild.getOptionalSint64());
+
+    message = builder.build();
+    builder.setOptionalString("hi");
+    assertEquals("", message.getOptionalString());
+    assertEquals("hi", builder.getOptionalString());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalString());
+    assertEquals("", message.getOptionalString());
+    builder.clearOptionalString();
+    assertEquals("", builder.getOptionalString());
+    assertEquals("hi", messageAfterBuild.getOptionalString());
+
+    message = builder.build();
+    builder.setOptionalStringBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalStringBytes());
+    builder.clearOptionalString();
+    assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringBytes());
+    
+    message = builder.build();
+    builder.setOptionalStringPiece("hi");
+    assertEquals("", message.getOptionalStringPiece());
+    assertEquals("hi", builder.getOptionalStringPiece());
+    messageAfterBuild = builder.build();
+    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
+    assertEquals("", message.getOptionalStringPiece());
+    builder.clearOptionalStringPiece();
+    assertEquals("", builder.getOptionalStringPiece());
+    assertEquals("hi", messageAfterBuild.getOptionalStringPiece());
+
+    message = builder.build();
+    builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no"));
+    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringPieceBytes());
+    assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes());
+    builder.clearOptionalStringPiece();
+    assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes());
+    assertEquals(
+        ByteString.copyFromUtf8("no"),
+        messageAfterBuild.getOptionalStringPieceBytes());
+
+    message = builder.build();
+    builder.setOptionalUint32(1);
+    assertEquals(0, message.getOptionalUint32());
+    assertEquals(1, builder.getOptionalUint32());
+    messageAfterBuild = builder.build();
+    assertEquals(1, messageAfterBuild.getOptionalUint32());
+    assertEquals(0, message.getOptionalUint32());
+    builder.clearOptionalUint32();
+    assertEquals(0, builder.getOptionalUint32());
+    assertEquals(1, messageAfterBuild.getOptionalUint32());
+
+    message = builder.build();
+    builder.setOptionalUint64(1);
+    assertEquals(0L, message.getOptionalUint64());
+    assertEquals(1L, builder.getOptionalUint64());
+    messageAfterBuild = builder.build();
+    assertEquals(1L, messageAfterBuild.getOptionalUint64());
+    assertEquals(0L, message.getOptionalUint64());
+    builder.clearOptionalUint64();
+    assertEquals(0L, builder.getOptionalUint64());
+    assertEquals(1L, messageAfterBuild.getOptionalUint64());
+
+    message = builder.build();
+    builder.addAllRepeatedBool(singletonList(true));
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertEquals(singletonList(true), builder.getRepeatedBoolList());
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBool();
+    assertEquals(emptyList(), builder.getRepeatedBoolList());
+    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+
+    message = builder.build();
+    builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi")));
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        builder.getRepeatedBytesList());
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBytes();
+    assertEquals(emptyList(), builder.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        messageAfterBuild.getRepeatedBytesList());
+
+    message = builder.build();
+    builder.addAllRepeatedCord(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedCord();
+    assertEquals(emptyList(), builder.getRepeatedCordList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+
+    message = builder.build();
+    builder.addAllRepeatedDouble(singletonList(1D));
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedDouble();
+    assertEquals(emptyList(), builder.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+
+    message = builder.build();
+    builder.addAllRepeatedFixed32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed32();
+    assertEquals(emptyList(), builder.getRepeatedFixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+
+    message = builder.build();
+    builder.addAllRepeatedFixed64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed64();
+    assertEquals(emptyList(), builder.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+
+    message = builder.build();
+    builder.addAllRepeatedFloat(singletonList(1F));
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFloat();
+    assertEquals(emptyList(), builder.getRepeatedFloatList());
+    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+
+    message = builder.build();
+    builder.addAllRepeatedForeignEnum(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR));
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        builder.getRepeatedForeignEnumList());
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignEnum();
+    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        messageAfterBuild.getRepeatedForeignEnumList());
+
+    message = builder.build();
+    builder.addAllRepeatedForeignMessage(singletonList(foreignMessage));
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignMessage();
+    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage),
+        messageAfterBuild.getRepeatedForeignMessageList());
+
+    message = builder.build();
+    builder.addAllRepeatedGroup(
+        singletonList(RepeatedGroup.getDefaultInstance()));
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        builder.getRepeatedGroupList());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedGroup();
+    assertEquals(emptyList(), builder.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        messageAfterBuild.getRepeatedGroupList());
+
+    message = builder.build();
+    builder.addAllRepeatedInt32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertEquals(singletonList(1), builder.getRepeatedInt32List());
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt32();
+    assertEquals(emptyList(), builder.getRepeatedInt32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+
+    message = builder.build();
+    builder.addAllRepeatedInt64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt64();
+    assertEquals(emptyList(), builder.getRepeatedInt64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+
+    message = builder.build();
+    builder.addAllRepeatedLazyMessage(singletonList(nestedMessage));
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedLazyMessage();
+    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage),
+        messageAfterBuild.getRepeatedLazyMessageList());
+
+    message = builder.build();
+    builder.addAllRepeatedSfixed32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed32();
+    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+
+    message = builder.build();
+    builder.addAllRepeatedSfixed64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed64();
+    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
+    assertEquals(
+        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+
+    message = builder.build();
+    builder.addAllRepeatedSint32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertEquals(singletonList(1), builder.getRepeatedSint32List());
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint32();
+    assertEquals(emptyList(), builder.getRepeatedSint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+
+    message = builder.build();
+    builder.addAllRepeatedSint64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint64();
+    assertEquals(emptyList(), builder.getRepeatedSint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+
+    message = builder.build();
+    builder.addAllRepeatedString(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedString();
+    assertEquals(emptyList(), builder.getRepeatedStringList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+
+    message = builder.build();
+    builder.addAllRepeatedStringPiece(singletonList("hi"));
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedStringPiece();
+    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+
+    message = builder.build();
+    builder.addAllRepeatedUint32(singletonList(1));
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertEquals(singletonList(1), builder.getRepeatedUint32List());
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint32();
+    assertEquals(emptyList(), builder.getRepeatedUint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+
+    message = builder.build();
+    builder.addAllRepeatedUint64(singletonList(1L));
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint64();
+    assertEquals(emptyList(), builder.getRepeatedUint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+
+    message = builder.build();
+    builder.addRepeatedBool(true);
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    assertEquals(singletonList(true), builder.getRepeatedBoolList());
+    assertEquals(emptyList(), message.getRepeatedBoolList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBool();
+    assertEquals(emptyList(), builder.getRepeatedBoolList());
+    assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList());
+
+    message = builder.build();
+    builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        builder.getRepeatedBytesList());
+    assertEquals(emptyList(), message.getRepeatedBytesList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedBytes();
+    assertEquals(emptyList(), builder.getRepeatedBytesList());
+    assertEquals(
+        singletonList(ByteString.copyFromUtf8("hi")),
+        messageAfterBuild.getRepeatedBytesList());
+
+    message = builder.build();
+    builder.addRepeatedCord("hi");
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    assertEquals(singletonList("hi"), builder.getRepeatedCordList());
+    assertEquals(emptyList(), message.getRepeatedCordList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedCord();
+    assertEquals(emptyList(), builder.getRepeatedCordList());
+    assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList());
+
+    message = builder.build();
+    builder.addRepeatedDouble(1D);
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), builder.getRepeatedDoubleList());
+    assertEquals(emptyList(), message.getRepeatedDoubleList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedDouble();
+    assertEquals(emptyList(), builder.getRepeatedDoubleList());
+    assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList());
+
+    message = builder.build();
+    builder.addRepeatedFixed32(1);
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedFixed32List());
+    assertEquals(emptyList(), message.getRepeatedFixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed32();
+    assertEquals(emptyList(), builder.getRepeatedFixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List());
+
+    message = builder.build();
+    builder.addRepeatedFixed64(1L);
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedFixed64List());
+    assertEquals(emptyList(), message.getRepeatedFixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFixed64();
+    assertEquals(emptyList(), builder.getRepeatedFixed64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List());
+
+    message = builder.build();
+    builder.addRepeatedFloat(1F);
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    assertEquals(singletonList(1F), builder.getRepeatedFloatList());
+    assertEquals(emptyList(), message.getRepeatedFloatList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedFloat();
+    assertEquals(emptyList(), builder.getRepeatedFloatList());
+    assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList());
+
+    message = builder.build();
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        builder.getRepeatedForeignEnumList());
+    assertEquals(emptyList(), message.getRepeatedForeignEnumList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedForeignEnum();
+    assertEquals(emptyList(), builder.getRepeatedForeignEnumList());
+    assertEquals(
+        singletonList(ForeignEnumLite.FOREIGN_LITE_BAR),
+        messageAfterBuild.getRepeatedForeignEnumList());
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessage);
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage), builder.getRepeatedForeignMessageList());
+    assertEquals(emptyList(), message.getRepeatedForeignMessageList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedForeignMessage(0);
+    assertEquals(emptyList(), builder.getRepeatedForeignMessageList());
+    assertEquals(
+        singletonList(foreignMessage),
+        messageAfterBuild.getRepeatedForeignMessageList());
+
+    message = builder.build();
+    builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        builder.getRepeatedGroupList());
+    assertEquals(emptyList(), message.getRepeatedGroupList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedGroup(0);
+    assertEquals(emptyList(), builder.getRepeatedGroupList());
+    assertEquals(
+        singletonList(RepeatedGroup.getDefaultInstance()),
+        messageAfterBuild.getRepeatedGroupList());
+
+    message = builder.build();
+    builder.addRepeatedInt32(1);
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    assertEquals(singletonList(1), builder.getRepeatedInt32List());
+    assertEquals(emptyList(), message.getRepeatedInt32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt32();
+    assertEquals(emptyList(), builder.getRepeatedInt32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List());
+
+    message = builder.build();
+    builder.addRepeatedInt64(1L);
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    assertEquals(singletonList(1L), builder.getRepeatedInt64List());
+    assertEquals(emptyList(), message.getRepeatedInt64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedInt64();
+    assertEquals(emptyList(), builder.getRepeatedInt64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List());
+
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessage);
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage), builder.getRepeatedLazyMessageList());
+    assertEquals(emptyList(), message.getRepeatedLazyMessageList());
+    messageAfterBuild = builder.build();
+    builder.removeRepeatedLazyMessage(0);
+    assertEquals(emptyList(), builder.getRepeatedLazyMessageList());
+    assertEquals(
+        singletonList(nestedMessage),
+        messageAfterBuild.getRepeatedLazyMessageList());
+
+    message = builder.build();
+    builder.addRepeatedSfixed32(1);
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), builder.getRepeatedSfixed32List());
+    assertEquals(emptyList(), message.getRepeatedSfixed32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed32();
+    assertEquals(emptyList(), builder.getRepeatedSfixed32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List());
+
+    message = builder.build();
+    builder.addRepeatedSfixed64(1L);
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSfixed64List());
+    assertEquals(emptyList(), message.getRepeatedSfixed64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSfixed64();
+    assertEquals(emptyList(), builder.getRepeatedSfixed64List());
+    assertEquals(
+        singletonList(1L), messageAfterBuild.getRepeatedSfixed64List());
+
+    message = builder.build();
+    builder.addRepeatedSint32(1);
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    assertEquals(singletonList(1), builder.getRepeatedSint32List());
+    assertEquals(emptyList(), message.getRepeatedSint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint32();
+    assertEquals(emptyList(), builder.getRepeatedSint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List());
+
+    message = builder.build();
+    builder.addRepeatedSint64(1L);
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedSint64List());
+    assertEquals(emptyList(), message.getRepeatedSint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedSint64();
+    assertEquals(emptyList(), builder.getRepeatedSint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List());
+
+    message = builder.build();
+    builder.addRepeatedString("hi");
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringList());
+    assertEquals(emptyList(), message.getRepeatedStringList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedString();
+    assertEquals(emptyList(), builder.getRepeatedStringList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringList());
+
+    message = builder.build();
+    builder.addRepeatedStringPiece("hi");
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList());
+    assertEquals(emptyList(), message.getRepeatedStringPieceList());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedStringPiece();
+    assertEquals(emptyList(), builder.getRepeatedStringPieceList());
+    assertEquals(
+        singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList());
+
+    message = builder.build();
+    builder.addRepeatedUint32(1);
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    assertEquals(singletonList(1), builder.getRepeatedUint32List());
+    assertEquals(emptyList(), message.getRepeatedUint32List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint32();
+    assertEquals(emptyList(), builder.getRepeatedUint32List());
+    assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List());
+
+    message = builder.build();
+    builder.addRepeatedUint64(1L);
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    assertEquals(singletonList(1L), builder.getRepeatedUint64List());
+    assertEquals(emptyList(), message.getRepeatedUint64List());
+    messageAfterBuild = builder.build();
+    builder.clearRepeatedUint64();
+    assertEquals(emptyList(), builder.getRepeatedUint64List());
+    assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List());
+    
+    message = builder.build();
+    builder.addRepeatedBool(true);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedBoolCount());
+    builder.setRepeatedBool(0, false);
+    assertEquals(true, messageAfterBuild.getRepeatedBool(0));
+    assertEquals(false, builder.getRepeatedBool(0));
+    builder.clearRepeatedBool();
+    
+    message = builder.build();
+    builder.addRepeatedBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedBytesCount());
+    builder.setRepeatedBytes(0, ByteString.EMPTY);
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0));
+    builder.clearRepeatedBytes();
+
+    message = builder.build();
+    builder.addRepeatedCord("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedCordCount());
+    builder.setRepeatedCord(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedCord(0));
+    assertEquals("", builder.getRepeatedCord(0));
+    builder.clearRepeatedCord();
+    message = builder.build();
+
+    builder.addRepeatedCordBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedCordCount());
+    builder.setRepeatedCord(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0));
+    builder.clearRepeatedCord();
+
+    message = builder.build();
+    builder.addRepeatedDouble(1D);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedDoubleCount());
+    builder.setRepeatedDouble(0, 0D);
+    assertEquals(1D, messageAfterBuild.getRepeatedDouble(0));
+    assertEquals(0D, builder.getRepeatedDouble(0));
+    builder.clearRepeatedDouble();
+
+    message = builder.build();
+    builder.addRepeatedFixed32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFixed32Count());
+    builder.setRepeatedFixed32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedFixed32(0));
+    assertEquals(0, builder.getRepeatedFixed32(0));
+    builder.clearRepeatedFixed32();
+
+    message = builder.build();
+    builder.addRepeatedFixed64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFixed64Count());
+    builder.setRepeatedFixed64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedFixed64(0));
+    assertEquals(0L, builder.getRepeatedFixed64(0));
+    builder.clearRepeatedFixed64();
+
+    message = builder.build();
+    builder.addRepeatedFloat(1F);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedFloatCount());
+    builder.setRepeatedFloat(0, 0F);
+    assertEquals(1F, messageAfterBuild.getRepeatedFloat(0));
+    assertEquals(0F, builder.getRepeatedFloat(0));
+    builder.clearRepeatedFloat();
+
+    message = builder.build();
+    builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignEnumCount());
+    builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO);
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_BAR,
+        messageAfterBuild.getRepeatedForeignEnum(0));
+    assertEquals(
+        ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0));
+    builder.clearRepeatedForeignEnum();
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(
+        0, ForeignMessageLite.getDefaultInstance());
+    assertEquals(
+        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getRepeatedForeignMessage(0));
+    builder.clearRepeatedForeignMessage();
+    
+    message = builder.build();
+    builder.addRepeatedForeignMessage(foreignMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(
+        0, ForeignMessageLite.getDefaultInstance());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC());
+    assertEquals(
+        ForeignMessageLite.getDefaultInstance(),
+        builder.getRepeatedForeignMessage(0));
+    builder.clearRepeatedForeignMessage();
+
+    message = builder.build();
+    builder.addRepeatedForeignMessage(0, foreignMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedForeignMessageCount());
+    builder.setRepeatedForeignMessage(0, foreignMessageBuilder);
+    assertEquals(
+        foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0));
+    // LITE_RUNTIME doesn't implement equals so we compare on a property.
+    assertEquals(3, builder.getRepeatedForeignMessage(0).getC());
+    builder.clearRepeatedForeignMessage();
+
+    message = builder.build();
+    RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder()
+        .setA(1)
+        .build();
+    builder.addRepeatedGroup(repeatedGroup);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    builder.addRepeatedGroup(0, repeatedGroup);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0));
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder()
+        .setA(3);
+    builder.addRepeatedGroup(repeatedGroupBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+    
+    message = builder.build();
+    builder.addRepeatedGroup(0, repeatedGroupBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedGroupCount());
+    builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA());
+    assertEquals(
+        RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0));
+    builder.clearRepeatedGroup();
+
+    message = builder.build();
+    builder.addRepeatedInt32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedInt32Count());
+    builder.setRepeatedInt32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedInt32(0));
+    assertEquals(0, builder.getRepeatedInt32(0));
+    builder.clearRepeatedInt32();
+
+    message = builder.build();
+    builder.addRepeatedInt64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedInt64Count());
+    builder.setRepeatedInt64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedInt64(0));
+    assertEquals(0L, builder.getRepeatedInt64(0));
+    builder.clearRepeatedInt64();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(0, nestedMessage);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0));
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(nestedMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+    
+    message = builder.build();
+    builder.addRepeatedLazyMessage(0, nestedMessageBuilder);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedLazyMessageCount());
+    builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance());
+    // LITE_RUNTIME doesn't implement equals so we compare on a property and
+    // ensure the property isn't set on repeatedGroup.
+    assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb());
+    assertEquals(
+        NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0));
+    builder.clearRepeatedLazyMessage();
+
+    message = builder.build();
+    builder.addRepeatedSfixed32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedSfixed32Count());
+    builder.setRepeatedSfixed32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedSfixed32(0));
+    assertEquals(0, builder.getRepeatedSfixed32(0));
+    builder.clearRepeatedSfixed32();
+
+    message = builder.build();
+    builder.addRepeatedSfixed64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedSfixed64Count());
+    builder.setRepeatedSfixed64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedSfixed64(0));
+    assertEquals(0L, builder.getRepeatedSfixed64(0));
+    builder.clearRepeatedSfixed64();
+
+    message = builder.build();
+    builder.addRepeatedSint32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedSint32Count());
+    builder.setRepeatedSint32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedSint32(0));
+    assertEquals(0, builder.getRepeatedSint32(0));
+    builder.clearRepeatedSint32();
+
+    message = builder.build();
+    builder.addRepeatedSint64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedSint64Count());
+    builder.setRepeatedSint64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedSint64(0));
+    assertEquals(0L, builder.getRepeatedSint64(0));
+    builder.clearRepeatedSint64();
+
+    message = builder.build();
+    builder.addRepeatedString("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringCount());
+    builder.setRepeatedString(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedString(0));
+    assertEquals("", builder.getRepeatedString(0));
+    builder.clearRepeatedString();
+
+    message = builder.build();
+    builder.addRepeatedStringBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringCount());
+    builder.setRepeatedString(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"),
+        messageAfterBuild.getRepeatedStringBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0));
+    builder.clearRepeatedString();
+
+    message = builder.build();
+    builder.addRepeatedStringPiece("hi");
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringPieceCount());
+    builder.setRepeatedStringPiece(0, "");
+    assertEquals("hi", messageAfterBuild.getRepeatedStringPiece(0));
+    assertEquals("", builder.getRepeatedStringPiece(0));
+    builder.clearRepeatedStringPiece();
+
+    message = builder.build();
+    builder.addRepeatedStringPieceBytes(ByteString.copyFromUtf8("hi"));
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedStringPieceCount());
+    builder.setRepeatedStringPiece(0, "");
+    assertEquals(
+        ByteString.copyFromUtf8("hi"),
+        messageAfterBuild.getRepeatedStringPieceBytes(0));
+    assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0));
+    builder.clearRepeatedStringPiece();
+
+    message = builder.build();
+    builder.addRepeatedUint32(1);
+    messageAfterBuild = builder.build();
+    assertEquals(0, message.getRepeatedUint32Count());
+    builder.setRepeatedUint32(0, 0);
+    assertEquals(1, messageAfterBuild.getRepeatedUint32(0));
+    assertEquals(0, builder.getRepeatedUint32(0));
+    builder.clearRepeatedUint32();
+
+    message = builder.build();
+    builder.addRepeatedUint64(1L);
+    messageAfterBuild = builder.build();
+    assertEquals(0L, message.getRepeatedUint64Count());
+    builder.setRepeatedUint64(0, 0L);
+    assertEquals(1L, messageAfterBuild.getRepeatedUint64(0));
+    assertEquals(0L, builder.getRepeatedUint64(0));
+    builder.clearRepeatedUint64();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeFrom(TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .build());
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(true, builder.build().getOptionalBool());
+    builder.clearOptionalBool();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeFrom(TestAllTypesLite.newBuilder()
+        .setOptionalBool(true)
+        .build());
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(true, builder.build().getOptionalBool());
+    builder.clear();
+    assertEquals(0, builder.build().getSerializedSize());
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeOptionalForeignMessage(foreignMessage);
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(
+        foreignMessage.getC(),
+        builder.build().getOptionalForeignMessage().getC());
+    builder.clearOptionalForeignMessage();
+
+    message = builder.build();
+    assertEquals(0, message.getSerializedSize());
+    builder.mergeOptionalLazyMessage(nestedMessage);
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(
+        nestedMessage.getBb(),
+        builder.build().getOptionalLazyMessage().getBb());
+    builder.clearOptionalLazyMessage();
+    
+    message = builder.build();
+    builder.setOneofString("hi");
+    assertEquals(
+        OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase());
+    assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase());
+    assertEquals("hi", builder.getOneofString());
+    messageAfterBuild = builder.build();
+    assertEquals(
+        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals("hi", messageAfterBuild.getOneofString());
+    builder.setOneofUint32(1);
+    assertEquals(
+        OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase());
+    assertEquals("hi", messageAfterBuild.getOneofString());
+    assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
+    assertEquals(1, builder.getOneofUint32());
+    
+    TestAllExtensionsLite.Builder extendableMessageBuilder =
+        TestAllExtensionsLite.newBuilder();
+    TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build();
+    extendableMessageBuilder.setExtension(
+        UnittestLite.optionalInt32ExtensionLite, 1);
+    assertFalse(extendableMessage.hasExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    extendableMessage = extendableMessageBuilder.build();
+    assertEquals(
+        1, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    extendableMessageBuilder.setExtension(
+        UnittestLite.optionalInt32ExtensionLite, 3);
+    assertEquals(
+        3, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        1, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    extendableMessage = extendableMessageBuilder.build();
+    assertEquals(
+        3, (int) extendableMessageBuilder.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        3, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    
+    // No extension registry, so it should be in unknown fields.
+    extendableMessage =
+        TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray());
+    assertFalse(extendableMessage.hasExtension(
+        UnittestLite.optionalInt32ExtensionLite));
+    
+    extendableMessageBuilder = extendableMessage.toBuilder();
+    extendableMessageBuilder.mergeFrom(TestAllExtensionsLite.newBuilder()
+        .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11)
+        .build());
+    
+    extendableMessage = extendableMessageBuilder.build();
+    ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+    UnittestLite.registerAllExtensions(registry);
+    extendableMessage = TestAllExtensionsLite.parseFrom(
+        extendableMessage.toByteArray(), registry);
+    
+    // The unknown field was preserved.
+    assertEquals(
+        3, (int) extendableMessage.getExtension(
+            UnittestLite.optionalInt32ExtensionLite));
+    assertEquals(
+        11, (int) extendableMessage.getExtension(
+            UnittestLite.optionalFixed32ExtensionLite));
   }
 }
diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
index 7b201a9..958b6a7 100644
--- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
+++ b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
@@ -307,7 +307,8 @@
 
   public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{
     assertSame(classUnderTest + " must be the same string references",
-        ByteString.EMPTY.toString(Internal.UTF_8), new LiteralByteString(new byte[]{}).toString(Internal.UTF_8));
+        ByteString.EMPTY.toString(Internal.UTF_8),
+        new LiteralByteString(new byte[]{}).toString(Internal.UTF_8));
   }
 
   public void testToString_raisesException() throws UnsupportedEncodingException{
diff --git a/java/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/src/test/java/com/google/protobuf/LongArrayListTest.java
new file mode 100644
index 0000000..3a52ec7
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -0,0 +1,473 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+
+/**
+ * Tests for {@link LongArrayList}.
+ * 
+ * @author dweis@google.com (Daniel Weis)
+ */
+public class LongArrayListTest extends TestCase {
+  
+  private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1);
+  private static final LongArrayList TERTIARY_LIST =
+      newImmutableLongArrayList(1, 2, 3);
+  
+  private LongArrayList list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new LongArrayList();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(LongArrayList.emptyList(), LongArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(LongArrayList.emptyList());
+  }
+  
+  public void testMakeImmutable() {
+    list.addLong(2);
+    list.addLong(4);
+    list.addLong(6);
+    list.addLong(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testCopyConstructor() {
+    LongArrayList copy = new LongArrayList(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new LongArrayList(LongArrayList.emptyList());
+    assertEquals(LongArrayList.emptyList(), copy);
+    
+    copy = new LongArrayList(asList(1L, 2L, 3L));
+    assertEquals(asList(1L, 2L, 3L), copy);
+
+    copy = new LongArrayList(Collections.<Long>emptyList());
+    assertEquals(LongArrayList.emptyList(), copy);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1L, 2L, 3L, 4L));
+    Iterator<Long> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (long) list.get(0));
+    assertEquals(1, (long) iterator.next());
+    list.set(0, 1L);
+    assertEquals(2, (long) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0L);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testGet() {
+    assertEquals(1, (long) TERTIARY_LIST.get(0));
+    assertEquals(2, (long) TERTIARY_LIST.get(1));
+    assertEquals(3, (long) TERTIARY_LIST.get(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testGetLong() {
+    assertEquals(1, TERTIARY_LIST.getLong(0));
+    assertEquals(2, TERTIARY_LIST.getLong(1));
+    assertEquals(3, TERTIARY_LIST.getLong(2));
+    
+    try {
+      TERTIARY_LIST.get(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      TERTIARY_LIST.get(3);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSize() {
+    assertEquals(0, LongArrayList.emptyList().size());
+    assertEquals(1, UNARY_LIST.size());
+    assertEquals(3, TERTIARY_LIST.size());
+
+    list.addLong(2);
+    list.addLong(4);
+    list.addLong(6);
+    list.addLong(8);
+    assertEquals(4, list.size());
+    
+    list.remove(0);
+    assertEquals(3, list.size());
+    
+    list.add(16L);
+    assertEquals(4, list.size());
+  }
+  
+  public void testSet() {
+    list.addLong(2);
+    list.addLong(4);
+    
+    assertEquals(2, (long) list.set(0, 0L));
+    assertEquals(0, list.getLong(0));
+
+    assertEquals(4, (long) list.set(1, 0L));
+    assertEquals(0, list.getLong(1));
+    
+    try {
+      list.set(-1, 0L);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.set(2, 0L);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testSetLong() {
+    list.addLong(2);
+    list.addLong(4);
+    
+    assertEquals(2, list.setLong(0, 0));
+    assertEquals(0, list.getLong(0));
+
+    assertEquals(4, list.setLong(1, 0));
+    assertEquals(0, list.getLong(1));
+    
+    try {
+      list.setLong(-1, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+
+    try {
+      list.setLong(2, 0);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAdd() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.add(2L));
+    assertEquals(asList(2L), list);
+
+    assertTrue(list.add(3L));
+    list.add(0, 4L);
+    assertEquals(asList(4L, 2L, 3L), list);
+    
+    list.add(0, 1L);
+    list.add(0, 0L);
+    // Force a resize by getting up to 11 elements.
+    for (int i = 0; i < 6; i++) {
+      list.add(Long.valueOf(5 + i));
+    }
+    assertEquals(asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L), list);
+    
+    try {
+      list.add(-1, 5L);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.add(4, 5L);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  public void testAddLong() {
+    assertEquals(0, list.size());
+
+    list.addLong(2);
+    assertEquals(asList(2L), list);
+
+    list.addLong(3);
+    assertEquals(asList(2L, 3L), list);
+  }
+  
+  public void testAddAll() {
+    assertEquals(0, list.size());
+
+    assertTrue(list.addAll(Collections.singleton(1L)));
+    assertEquals(1, list.size());
+    assertEquals(1, (long) list.get(0));
+    assertEquals(1, list.getLong(0));
+    
+    assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L)));
+    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list);
+    
+    assertTrue(list.addAll(TERTIARY_LIST));
+    assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list);
+
+    assertFalse(list.addAll(Collections.<Long>emptyList()));
+    assertFalse(list.addAll(LongArrayList.emptyList()));
+  }
+  
+  public void testRemove() {
+    list.addAll(TERTIARY_LIST);
+    assertEquals(1, (long) list.remove(0));
+    assertEquals(asList(2L, 3L), list);
+
+    assertTrue(list.remove(3L));
+    assertEquals(asList(2L), list);
+
+    assertFalse(list.remove(3L));
+    assertEquals(asList(2L), list);
+
+    assertEquals(2, (long) list.remove(0));
+    assertEquals(asList(), list);
+    
+    try {
+      list.remove(-1);
+      fail();
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(0);
+    } catch (IndexOutOfBoundsException e) {
+      // expected
+    }
+  }
+  
+  private void assertImmutable(LongArrayList list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new LongArrayList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1L));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addLong(0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Long>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0L);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.setLong(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static LongArrayList newImmutableLongArrayList(long... elements) {
+    LongArrayList list = new LongArrayList();
+    for (long element : elements) {
+      list.addLong(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index 22dbeb7..6cff689 100644
--- a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -36,6 +36,11 @@
 
 import junit.framework.TestCase;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Unit tests for map fields.
  */
@@ -170,6 +175,140 @@
     assertEquals(0, message.getStringToInt32Field().size());
   }
 
+  public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
+    // Since builders are implemented as a thin wrapper around a message
+    // instance, we attempt to verify that we can't cause the builder to modify
+    // a produced message.
+    
+    TestMap.Builder builder = TestMap.newBuilder();
+    TestMap message = builder.build();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertTrue(message.getInt32ToInt32Field().isEmpty());
+    message = builder.build();
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+  }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -274,4 +413,26 @@
     assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue());
   }
   
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
 }
diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/src/test/java/com/google/protobuf/MapForProto2Test.java
index 78cba1b..7e98404 100644
--- a/java/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -40,6 +40,7 @@
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -177,6 +178,116 @@
     assertEquals(0, message.getInt32ToMessageField().size());
     assertEquals(0, message.getStringToInt32Field().size());
   }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
+
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
 
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
@@ -513,4 +624,41 @@
     assertEquals(2, message.getRecursiveMapField().get(1).getValue());
     assertEquals(4, message.getRecursiveMapField().get(3).getValue());
   }
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+
+  // Regression test for b/20494788
+  public void testMapInitializationOrder() throws Exception {
+    assertEquals("RedactAllTypes", map_test.RedactAllTypes
+        .getDefaultInstance().getDescriptorForType().getName());
+
+    map_test.Message1.Builder builder =
+        map_test.Message1.newBuilder();
+    builder.getMutableMapField().put("key", true);
+    map_test.Message1 message = builder.build();
+    Message mapEntry = (Message) message.getRepeatedField(
+        message.getDescriptorForType().findFieldByName("map_field"), 0);
+    assertEquals(2, mapEntry.getAllFields().size());
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
 }
+
diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java
index b8e67b7..0509be1 100644
--- a/java/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/src/test/java/com/google/protobuf/MapTest.java
@@ -41,6 +41,7 @@
 import junit.framework.TestCase;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -178,7 +179,117 @@
     assertEquals(0, message.getInt32ToMessageField().size());
     assertEquals(0, message.getStringToInt32Field().size());
   }
+  
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.put(2, 3);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    builder.getMutableInt32ToInt32Field().put(2, 3);
+    assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
 
+    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
+    enumMap.put(1, TestMap.EnumValue.BAR);
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
+    try {
+      enumMap.put(2, TestMap.EnumValue.FOO);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
+    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    assertEquals(
+        newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
+        builder.getInt32ToEnumField());
+    
+    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
+    stringMap.put(1, "1");
+    assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
+    try {
+      stringMap.put(2, "2");
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
+    builder.getMutableInt32ToStringField().put(2, "2");
+    assertEquals(
+        newMap(1, "1", 2, "2"),
+        builder.getInt32ToStringField());
+    
+    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
+    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.build().getInt32ToMessageField());
+    try {
+      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    assertEquals(
+        newMap(1, TestMap.MessageValue.getDefaultInstance(),
+            2, TestMap.MessageValue.getDefaultInstance()),
+        builder.getInt32ToMessageField());
+  }
+
+  public void testMutableMapLifecycle_collections() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
+    intMap.put(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    try {
+      intMap.remove(2);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.entrySet().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.keySet().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    try {
+      intMap.values().iterator().remove();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    assertEquals(newMap(1, 2), intMap);
+    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+  }
+  
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
@@ -611,4 +722,26 @@
       assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue());
     }
   }
+
+  public void testIterationOrder() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+
+    assertEquals(Arrays.asList("1", "2", "3"),
+        new ArrayList<String>(message.getStringToInt32Field().keySet()));
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    return map;
+  }
+  
+  private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
+    Map<K, V> map = new HashMap<K, V>();
+    map.put(key1, value1);
+    map.put(key2, value2);
+    return map;
+  }
 }
diff --git a/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
new file mode 100644
index 0000000..f9f5e9c
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java
@@ -0,0 +1,303 @@
+// 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;
+
+import static java.util.Arrays.asList;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Tests for {@link ProtobufArrayList}.
+ */
+public class ProtobufArrayListTest extends TestCase {
+  
+  private static final ProtobufArrayList<Integer> UNARY_LIST = newImmutableProtoArrayList(1);
+  private static final ProtobufArrayList<Integer> TERTIARY_LIST =
+      newImmutableProtoArrayList(1, 2, 3);
+  
+  private ProtobufArrayList<Integer> list;
+  
+  @Override
+  protected void setUp() throws Exception {
+    list = new ProtobufArrayList<Integer>();
+  }
+  
+  public void testEmptyListReturnsSameInstance() {
+    assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList());
+  }
+  
+  public void testEmptyListIsImmutable() {
+    assertImmutable(ProtobufArrayList.<Integer>emptyList());
+  }
+  
+  public void testCopyConstructor() {
+    ProtobufArrayList<Integer> copy = new ProtobufArrayList<Integer>(TERTIARY_LIST);
+    assertEquals(TERTIARY_LIST, copy);
+
+    copy = new ProtobufArrayList<Integer>(IntArrayList.emptyList());
+    assertEquals(ProtobufArrayList.emptyList(), copy);
+    
+    copy = new ProtobufArrayList<Integer>(asList(1, 2, 3));
+    assertEquals(asList(1, 2, 3), copy);
+
+    copy = new ProtobufArrayList<Integer>(Collections.<Integer>emptyList());
+    assertEquals(ProtobufArrayList.emptyList(), copy);
+  }
+  
+  public void testModificationWithIteration() {
+    list.addAll(asList(1, 2, 3, 4));
+    Iterator<Integer> iterator = list.iterator();
+    assertEquals(4, list.size());
+    assertEquals(1, (int) list.get(0));
+    assertEquals(1, (int) iterator.next());
+    
+    list.remove(0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.set(0, 1);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+    
+    iterator = list.iterator();
+    list.add(0, 0);
+    try {
+      iterator.next();
+      fail();
+    } catch (ConcurrentModificationException e) {
+      // expected
+    }
+  }
+  
+  public void testMakeImmutable() {
+    list.add(2);
+    list.add(4);
+    list.add(6);
+    list.add(8);
+    list.makeImmutable();
+    assertImmutable(list);
+  }
+  
+  public void testRemove() {
+    list.add(2);
+    list.add(4);
+    list.add(6);
+
+    list.remove(1);
+    assertEquals(asList(2, 6), list);
+
+    list.remove(1);
+    assertEquals(asList(2), list);
+
+    list.remove(0);
+    assertEquals(asList(), list);
+  }
+  
+  public void testGet() {
+    list.add(2);
+    list.add(6);
+    
+    assertEquals(2, (int) list.get(0));
+    assertEquals(6, (int) list.get(1));
+  }
+  
+  public void testSet() {
+    list.add(2);
+    list.add(6);
+    
+    list.set(0, 1);
+    assertEquals(1, (int) list.get(0));
+    list.set(1, 2);
+    assertEquals(2, (int) list.get(1));
+  }
+
+  private void assertImmutable(List<Integer> list) {
+    if (list.contains(1)) {
+      throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
+    }
+    
+    try {
+      list.add(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.add(0, 1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(Collections.singletonList(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(new ProtobufArrayList<Integer>());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.addAll(0, Collections.<Integer>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    } 
+
+    try {
+      list.clear();
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+
+    try {
+      list.remove(1);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.remove(new Object());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.removeAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.<Double>emptyList());
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(Collections.singleton(1));
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.retainAll(UNARY_LIST);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+    
+    try {
+      list.set(0, 0);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+  
+  private static ProtobufArrayList<Integer> newImmutableProtoArrayList(int... elements) {
+    ProtobufArrayList<Integer> list = new ProtobufArrayList<Integer>();
+    for (int element : elements) {
+      list.add(element);
+    }
+    list.makeImmutable();
+    return list;
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/field_presence_test.proto b/java/src/test/java/com/google/protobuf/field_presence_test.proto
index 8d8ea8e..8f3ca8c 100644
--- a/java/src/test/java/com/google/protobuf/field_presence_test.proto
+++ b/java/src/test/java/com/google/protobuf/field_presence_test.proto
@@ -45,15 +45,15 @@
     BAZ = 2;
   }
   message NestedMessage {
-    optional int32 value = 1;
+    int32 value = 1;
   }
 
-  optional int32 optional_int32 = 1;
-  optional string optional_string = 2;
-  optional bytes optional_bytes = 3;
-  optional NestedEnum optional_nested_enum = 4;
-  optional NestedMessage optional_nested_message = 5;
-  optional protobuf_unittest.TestRequired optional_proto2_message = 6;
+  int32 optional_int32 = 1;
+  string optional_string = 2;
+  bytes optional_bytes = 3;
+  NestedEnum optional_nested_enum = 4;
+  NestedMessage optional_nested_message = 5;
+  protobuf_unittest.TestRequired optional_proto2_message = 6;
 
   oneof oneof_field {
     int32 oneof_int32 = 11;
@@ -75,12 +75,12 @@
 }
 
 message TestOptionalFieldsOnly {
-  optional int32 optional_int32 = 1;
-  optional string optional_string = 2;
-  optional bytes optional_bytes = 3;
-  optional TestAllTypes.NestedEnum optional_nested_enum = 4;
-  optional TestAllTypes.NestedMessage optional_nested_message = 5;
-  optional protobuf_unittest.TestRequired optional_proto2_message = 6;
+  int32 optional_int32 = 1;
+  string optional_string = 2;
+  bytes optional_bytes = 3;
+  TestAllTypes.NestedEnum optional_nested_enum = 4;
+  TestAllTypes.NestedMessage optional_nested_message = 5;
+  protobuf_unittest.TestRequired optional_proto2_message = 6;
 }
 
 message TestRepeatedFieldsOnly {
diff --git a/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto b/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto
new file mode 100644
index 0000000..b02ac59
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto
@@ -0,0 +1,61 @@
+// 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.
+
+// Regression test for a map initilaization order bug. The bug only manifests
+// when:
+//   1. A message contains map fields and is also extendable.
+//   2. There is a file-level extension defined in the same file referencing
+//      the above message as the extension type.
+//   3. The program executes in the following order:
+//        a. getDescriptor() is called on another message in the same file.
+//        b. use protobuf reflection to access the map field.
+// The symptom is a NullPointerException being thrown.
+syntax = "proto2";
+
+package map_test;
+
+option java_package = "map_test";
+option java_outer_classname = "MapInitializationOrderTest";
+option java_multiple_files = true;
+
+// Mirrors the structure of
+// javatests/com/google/cloud/common/logging/logging_test.proto.
+
+message Message1 {
+  map<string, bool> map_field = 1;
+  extensions 1000 to max;
+}
+
+extend Message1 {
+  optional Message1 recursive_extension = 1001;
+}
+
+message RedactAllTypes {
+}
diff --git a/java/src/test/java/com/google/protobuf/map_test.proto b/java/src/test/java/com/google/protobuf/map_test.proto
index bf692c2..2f7709b 100644
--- a/java/src/test/java/com/google/protobuf/map_test.proto
+++ b/java/src/test/java/com/google/protobuf/map_test.proto
@@ -39,7 +39,7 @@
 
 message TestMap {
   message MessageValue {
-    optional int32 value = 1;
+    int32 value = 1;
   }
   enum EnumValue {
     FOO = 0;
@@ -60,5 +60,5 @@
 // propagate the onChange event and mark its parent dirty when a change
 // is made to a map field.
 message TestOnChangeEventPropagation {
-  optional TestMap optional_message = 1;
+  TestMap optional_message = 1;
 }
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index f7a58ca..970b1a8 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -245,9 +245,6 @@
 
     is_extendable:  Does this type define any extension ranges?
 
-    options: (descriptor_pb2.MessageOptions) Protocol message options or None
-      to use default message options.
-
     oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields
       in this message.
     oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|,
@@ -265,7 +262,7 @@
                 file=None, serialized_start=None, serialized_end=None,
                 syntax=None):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetMessageDescriptor(full_name)
+      return _message.default_pool.FindMessageTypeByName(full_name)
 
   # NOTE(tmarek): The file argument redefining a builtin is nothing we can
   # fix right now since we don't know how many clients already rely on the
@@ -495,9 +492,9 @@
                 has_default_value=True, containing_oneof=None):
       _message.Message._CheckCalledFromGeneratedFile()
       if is_extension:
-        return _message.Message._GetExtensionDescriptor(full_name)
+        return _message.default_pool.FindExtensionByName(full_name)
       else:
-        return _message.Message._GetFieldDescriptor(full_name)
+        return _message.default_pool.FindFieldByName(full_name)
 
   def __init__(self, name, full_name, index, number, type, cpp_type, label,
                default_value, message_type, enum_type, containing_type,
@@ -528,14 +525,9 @@
     self.containing_oneof = containing_oneof
     if api_implementation.Type() == 'cpp':
       if is_extension:
-        # pylint: disable=protected-access
-        self._cdescriptor = (
-            _message.Message._GetExtensionDescriptor(full_name))
-        # pylint: enable=protected-access
+        self._cdescriptor = _message.default_pool.FindExtensionByName(full_name)
       else:
-        # pylint: disable=protected-access
-        self._cdescriptor = _message.Message._GetFieldDescriptor(full_name)
-        # pylint: enable=protected-access
+        self._cdescriptor = _message.default_pool.FindFieldByName(full_name)
     else:
       self._cdescriptor = None
 
@@ -592,7 +584,7 @@
                 containing_type=None, options=None, file=None,
                 serialized_start=None, serialized_end=None):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetEnumDescriptor(full_name)
+      return _message.default_pool.FindEnumTypeByName(full_name)
 
   def __init__(self, name, full_name, filename, values,
                containing_type=None, options=None, file=None,
@@ -677,7 +669,7 @@
 
     def __new__(cls, name, full_name, index, containing_type, fields):
       _message.Message._CheckCalledFromGeneratedFile()
-      return _message.Message._GetOneofDescriptor(full_name)
+      return _message.default_pool.FindOneofByName(full_name)
 
   def __init__(self, name, full_name, index, containing_type, fields):
     """Arguments are as described in the attribute description above."""
@@ -788,12 +780,8 @@
                 dependencies=None, syntax=None):
       # FileDescriptor() is called from various places, not only from generated
       # files, to register dynamic proto files and messages.
-      # TODO(amauryfa): Expose BuildFile() as a public function and make this
-      # constructor an implementation detail.
       if serialized_pb:
-        # pylint: disable=protected-access2
-        return _message.Message._BuildFile(serialized_pb)
-        # pylint: enable=protected-access
+        return _message.default_pool.AddSerializedFile(serialized_pb)
       else:
         return super(FileDescriptor, cls).__new__(cls)
 
@@ -814,9 +802,7 @@
 
     if (api_implementation.Type() == 'cpp' and
         self.serialized_pb is not None):
-      # pylint: disable=protected-access
-      _message.Message._BuildFile(self.serialized_pb)
-      # pylint: enable=protected-access
+      _message.default_pool.AddSerializedFile(self.serialized_pb)
 
   def CopyToProto(self, proto):
     """Copies this to a descriptor_pb2.FileDescriptorProto.
@@ -864,10 +850,10 @@
     file_descriptor_proto = descriptor_pb2.FileDescriptorProto()
     file_descriptor_proto.message_type.add().MergeFrom(desc_proto)
 
-    # Generate a random name for this proto file to prevent conflicts with
-    # any imported ones. We need to specify a file name so BuildFile accepts
-    # our FileDescriptorProto, but it is not important what that file name
-    # is actually set to.
+    # Generate a random name for this proto file to prevent conflicts with any
+    # imported ones. We need to specify a file name so the descriptor pool
+    # accepts our FileDescriptorProto, but it is not important what that file
+    # name is actually set to.
     proto_name = str(uuid.uuid4())
 
     if package:
@@ -877,10 +863,8 @@
     else:
       file_descriptor_proto.name = proto_name + '.proto'
 
-    # pylint: disable=protected-access
-    result = _message.Message._BuildFile(
-        file_descriptor_proto.SerializeToString())
-    # pylint: enable=protected-access
+    _message.default_pool.Add(file_descriptor_proto)
+    result = _message.default_pool.FindFileByName(file_descriptor_proto.name)
 
     if _USE_C_DESCRIPTORS:
       return result.message_types_by_name[desc_proto.name]
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 7e7701f..1244ba7 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -113,6 +113,20 @@
 
     self._internal_db.Add(file_desc_proto)
 
+  def AddSerializedFile(self, serialized_file_desc_proto):
+    """Adds the FileDescriptorProto and its types to this pool.
+
+    Args:
+      serialized_file_desc_proto: A bytes string, serialization of the
+        FileDescriptorProto to add.
+    """
+
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf import descriptor_pb2
+    file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
+        serialized_file_desc_proto)
+    self.Add(file_desc_proto)
+
   def AddDescriptor(self, desc):
     """Adds a Descriptor to the pool, non-recursively.
 
@@ -320,17 +334,17 @@
                                           file_descriptor, None, scope))
 
         for index, extension_proto in enumerate(file_proto.extension):
-          extension_desc = self.MakeFieldDescriptor(
+          extension_desc = self._MakeFieldDescriptor(
               extension_proto, file_proto.package, index, is_extension=True)
           extension_desc.containing_type = self._GetTypeFromScope(
               file_descriptor.package, extension_proto.extendee, scope)
-          self.SetFieldType(extension_proto, extension_desc,
+          self._SetFieldType(extension_proto, extension_desc,
                             file_descriptor.package, scope)
           file_descriptor.extensions_by_name[extension_desc.name] = (
               extension_desc)
 
         for desc_proto in file_proto.message_type:
-          self.SetAllFieldTypes(file_proto.package, desc_proto, scope)
+          self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
 
         if file_proto.package:
           desc_proto_prefix = _PrefixWithDot(file_proto.package)
@@ -381,10 +395,11 @@
     enums = [
         self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
         for enum in desc_proto.enum_type]
-    fields = [self.MakeFieldDescriptor(field, desc_name, index)
+    fields = [self._MakeFieldDescriptor(field, desc_name, index)
               for index, field in enumerate(desc_proto.field)]
     extensions = [
-        self.MakeFieldDescriptor(extension, desc_name, index, is_extension=True)
+        self._MakeFieldDescriptor(extension, desc_name, index,
+                                  is_extension=True)
         for index, extension in enumerate(desc_proto.extension)]
     oneofs = [
         descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
@@ -464,8 +479,8 @@
     self._enum_descriptors[enum_name] = desc
     return desc
 
-  def MakeFieldDescriptor(self, field_proto, message_name, index,
-                          is_extension=False):
+  def _MakeFieldDescriptor(self, field_proto, message_name, index,
+                           is_extension=False):
     """Creates a field descriptor from a FieldDescriptorProto.
 
     For message and enum type fields, this method will do a look up
@@ -506,7 +521,7 @@
         extension_scope=None,
         options=field_proto.options)
 
-  def SetAllFieldTypes(self, package, desc_proto, scope):
+  def _SetAllFieldTypes(self, package, desc_proto, scope):
     """Sets all the descriptor's fields's types.
 
     This method also sets the containing types on any extensions.
@@ -527,18 +542,18 @@
       nested_package = '.'.join([package, desc_proto.name])
 
     for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
-      self.SetFieldType(field_proto, field_desc, nested_package, scope)
+      self._SetFieldType(field_proto, field_desc, nested_package, scope)
 
     for extension_proto, extension_desc in (
         zip(desc_proto.extension, main_desc.extensions)):
       extension_desc.containing_type = self._GetTypeFromScope(
           nested_package, extension_proto.extendee, scope)
-      self.SetFieldType(extension_proto, extension_desc, nested_package, scope)
+      self._SetFieldType(extension_proto, extension_desc, nested_package, scope)
 
     for nested_type in desc_proto.nested_type:
-      self.SetAllFieldTypes(nested_package, nested_type, scope)
+      self._SetAllFieldTypes(nested_package, nested_type, scope)
 
-  def SetFieldType(self, field_proto, field_desc, package, scope):
+  def _SetFieldType(self, field_proto, field_desc, package, scope):
     """Sets the field's type, cpp_type, message_type and enum_type.
 
     Args:
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index d976f9e..72c2fa0 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -41,6 +41,146 @@
 
 __author__ = 'petar@google.com (Petar Petrov)'
 
+import sys
+
+if sys.version_info[0] < 3:
+  # We would use collections.MutableMapping all the time, but in Python 2 it
+  # doesn't define __slots__.  This causes two significant problems:
+  #
+  # 1. we can't disallow arbitrary attribute assignment, even if our derived
+  #    classes *do* define __slots__.
+  #
+  # 2. we can't safely derive a C type from it without __slots__ defined (the
+  #    interpreter expects to find a dict at tp_dictoffset, which we can't
+  #    robustly provide.  And we don't want an instance dict anyway.
+  #
+  # So this is the Python 2.7 definition of Mapping/MutableMapping functions
+  # verbatim, except that:
+  # 1. We declare __slots__.
+  # 2. We don't declare this as a virtual base class.  The classes defined
+  #    in collections are the interesting base classes, not us.
+  #
+  # Note: deriving from object is critical.  It is the only thing that makes
+  # this a true type, allowing us to derive from it in C++ cleanly and making
+  # __slots__ properly disallow arbitrary element assignment.
+  from collections import Mapping as _Mapping
+
+  class Mapping(object):
+    __slots__ = ()
+
+    def get(self, key, default=None):
+      try:
+        return self[key]
+      except KeyError:
+        return default
+
+    def __contains__(self, key):
+      try:
+        self[key]
+      except KeyError:
+        return False
+      else:
+        return True
+
+    def iterkeys(self):
+      return iter(self)
+
+    def itervalues(self):
+      for key in self:
+        yield self[key]
+
+    def iteritems(self):
+      for key in self:
+        yield (key, self[key])
+
+    def keys(self):
+      return list(self)
+
+    def items(self):
+      return [(key, self[key]) for key in self]
+
+    def values(self):
+      return [self[key] for key in self]
+
+    # Mappings are not hashable by default, but subclasses can change this
+    __hash__ = None
+
+    def __eq__(self, other):
+      if not isinstance(other, _Mapping):
+        return NotImplemented
+      return dict(self.items()) == dict(other.items())
+
+    def __ne__(self, other):
+      return not (self == other)
+
+  class MutableMapping(Mapping):
+    __slots__ = ()
+
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+      try:
+        value = self[key]
+      except KeyError:
+        if default is self.__marker:
+          raise
+        return default
+      else:
+        del self[key]
+        return value
+
+    def popitem(self):
+      try:
+        key = next(iter(self))
+      except StopIteration:
+        raise KeyError
+      value = self[key]
+      del self[key]
+      return key, value
+
+    def clear(self):
+      try:
+        while True:
+          self.popitem()
+      except KeyError:
+        pass
+
+    def update(*args, **kwds):
+      if len(args) > 2:
+        raise TypeError("update() takes at most 2 positional "
+                        "arguments ({} given)".format(len(args)))
+      elif not args:
+        raise TypeError("update() takes at least 1 argument (0 given)")
+      self = args[0]
+      other = args[1] if len(args) >= 2 else ()
+
+      if isinstance(other, Mapping):
+        for key in other:
+          self[key] = other[key]
+      elif hasattr(other, "keys"):
+        for key in other.keys():
+          self[key] = other[key]
+      else:
+        for key, value in other:
+          self[key] = value
+      for key, value in kwds.items():
+        self[key] = value
+
+    def setdefault(self, key, default=None):
+      try:
+        return self[key]
+      except KeyError:
+        self[key] = default
+      return default
+
+  _Mapping.register(Mapping)
+
+else:
+  # In Python 3 we can just use MutableMapping directly, because it defines
+  # __slots__.
+  from collections import MutableMapping
+
+
 class BaseContainer(object):
 
   """Base container class."""
@@ -286,3 +426,160 @@
       raise TypeError('Can only compare repeated composite fields against '
                       'other repeated composite fields.')
     return self._values == other._values
+
+
+class ScalarMap(MutableMapping):
+
+  """Simple, type-checked, dict-like container for holding repeated scalars."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener']
+
+  def __init__(self, message_listener, key_checker, value_checker):
+    """
+    Args:
+      message_listener: A MessageListener implementation.
+        The ScalarMap will call this object's Modified() method when it
+        is modified.
+      key_checker: A type_checkers.ValueChecker instance to run on keys
+        inserted into this container.
+      value_checker: A type_checkers.ValueChecker instance to run on values
+        inserted into this container.
+    """
+    self._message_listener = message_listener
+    self._key_checker = key_checker
+    self._value_checker = value_checker
+    self._values = {}
+
+  def __getitem__(self, key):
+    try:
+      return self._values[key]
+    except KeyError:
+      key = self._key_checker.CheckValue(key)
+      val = self._value_checker.DefaultValue()
+      self._values[key] = val
+      return val
+
+  def __contains__(self, item):
+    return item in self._values
+
+  # We need to override this explicitly, because our defaultdict-like behavior
+  # will make the default implementation (from our base class) always insert
+  # the key.
+  def get(self, key, default=None):
+    if key in self:
+      return self[key]
+    else:
+      return default
+
+  def __setitem__(self, key, value):
+    checked_key = self._key_checker.CheckValue(key)
+    checked_value = self._value_checker.CheckValue(value)
+    self._values[checked_key] = checked_value
+    self._message_listener.Modified()
+
+  def __delitem__(self, key):
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self):
+    return len(self._values)
+
+  def __iter__(self):
+    return iter(self._values)
+
+  def MergeFrom(self, other):
+    self._values.update(other._values)
+    self._message_listener.Modified()
+
+  # This is defined in the abstract base, but we can do it much more cheaply.
+  def clear(self):
+    self._values.clear()
+    self._message_listener.Modified()
+
+
+class MessageMap(MutableMapping):
+
+  """Simple, type-checked, dict-like container for with submessage values."""
+
+  # Disallows assignment to other attributes.
+  __slots__ = ['_key_checker', '_values', '_message_listener',
+               '_message_descriptor']
+
+  def __init__(self, message_listener, message_descriptor, key_checker):
+    """
+    Args:
+      message_listener: A MessageListener implementation.
+        The ScalarMap will call this object's Modified() method when it
+        is modified.
+      key_checker: A type_checkers.ValueChecker instance to run on keys
+        inserted into this container.
+      value_checker: A type_checkers.ValueChecker instance to run on values
+        inserted into this container.
+    """
+    self._message_listener = message_listener
+    self._message_descriptor = message_descriptor
+    self._key_checker = key_checker
+    self._values = {}
+
+  def __getitem__(self, key):
+    try:
+      return self._values[key]
+    except KeyError:
+      key = self._key_checker.CheckValue(key)
+      new_element = self._message_descriptor._concrete_class()
+      new_element._SetListener(self._message_listener)
+      self._values[key] = new_element
+      self._message_listener.Modified()
+
+      return new_element
+
+  def get_or_create(self, key):
+    """get_or_create() is an alias for getitem (ie. map[key]).
+
+    Args:
+      key: The key to get or create in the map.
+
+    This is useful in cases where you want to be explicit that the call is
+    mutating the map.  This can avoid lint errors for statements like this
+    that otherwise would appear to be pointless statements:
+
+      msg.my_map[key]
+    """
+    return self[key]
+
+  # We need to override this explicitly, because our defaultdict-like behavior
+  # will make the default implementation (from our base class) always insert
+  # the key.
+  def get(self, key, default=None):
+    if key in self:
+      return self[key]
+    else:
+      return default
+
+  def __contains__(self, item):
+    return item in self._values
+
+  def __setitem__(self, key, value):
+    raise ValueError('May not set values directly, call my_map[key].foo = 5')
+
+  def __delitem__(self, key):
+    del self._values[key]
+    self._message_listener.Modified()
+
+  def __len__(self):
+    return len(self._values)
+
+  def __iter__(self):
+    return iter(self._values)
+
+  def MergeFrom(self, other):
+    for key in other:
+      self[key].MergeFrom(other[key])
+    # self._message_listener.Modified() not required here, because
+    # mutations to submessages already propagate.
+
+  # This is defined in the abstract base, but we can do it much more cheaply.
+  def clear(self):
+    self._values.clear()
+    self._message_listener.Modified()
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index 0f50060..3837eae 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -733,6 +733,50 @@
   return DecodeItem
 
 # --------------------------------------------------------------------
+
+def MapDecoder(field_descriptor, new_default, is_message_map):
+  """Returns a decoder for a map field."""
+
+  key = field_descriptor
+  tag_bytes = encoder.TagBytes(field_descriptor.number,
+                               wire_format.WIRETYPE_LENGTH_DELIMITED)
+  tag_len = len(tag_bytes)
+  local_DecodeVarint = _DecodeVarint
+  # Can't read _concrete_class yet; might not be initialized.
+  message_type = field_descriptor.message_type
+
+  def DecodeMap(buffer, pos, end, message, field_dict):
+    submsg = message_type._concrete_class()
+    value = field_dict.get(key)
+    if value is None:
+      value = field_dict.setdefault(key, new_default(message))
+    while 1:
+      # Read length.
+      (size, pos) = local_DecodeVarint(buffer, pos)
+      new_pos = pos + size
+      if new_pos > end:
+        raise _DecodeError('Truncated message.')
+      # Read sub-message.
+      submsg.Clear()
+      if submsg._InternalParse(buffer, pos, new_pos) != new_pos:
+        # The only reason _InternalParse would return early is if it
+        # encountered an end-group tag.
+        raise _DecodeError('Unexpected end-group tag.')
+
+      if is_message_map:
+        value[submsg.key].MergeFrom(submsg.value)
+      else:
+        value[submsg.key] = submsg.value
+
+      # Predict that the next tag is another copy of the same repeated field.
+      pos = new_pos + tag_len
+      if buffer[new_pos:pos] != tag_bytes or new_pos == end:
+        # Prediction failed.  Return.
+        return new_pos
+
+  return DecodeMap
+
+# --------------------------------------------------------------------
 # Optimization is not as heavy here because calls to SkipField() are rare,
 # except for handling end-group tags.
 
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
index 56fe14e..8416e15 100644
--- a/python/google/protobuf/internal/descriptor_database_test.py
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -35,7 +35,6 @@
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 import unittest
-
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test2_pb2
 from google.protobuf import descriptor_database
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 7d145f4..d159cc6 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -37,6 +37,7 @@
 import os
 import unittest
 
+import unittest
 from google.protobuf import unittest_pb2
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import api_implementation
@@ -226,6 +227,13 @@
     db.Add(self.factory_test2_fd)
     self.testFindMessageTypeByName()
 
+  def testAddSerializedFile(self):
+    db = descriptor_database.DescriptorDatabase()
+    self.pool = descriptor_pool.DescriptorPool(db)
+    self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString())
+    self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString())
+    self.testFindMessageTypeByName()
+
   def testComplexNesting(self):
     test1_desc = descriptor_pb2.FileDescriptorProto.FromString(
         descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb)
@@ -510,6 +518,43 @@
           'protobuf_unittest.TestAllTypes')
 
 
+@unittest.skipIf(
+    api_implementation.Type() != 'cpp',
+    'default_pool is only supported by the C++ implementation')
+class DefaultPoolTest(unittest.TestCase):
+
+  def testFindMethods(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    self.assertIs(
+        pool.FindFileByName('google/protobuf/unittest.proto'),
+        unittest_pb2.DESCRIPTOR)
+    self.assertIs(
+        pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR)
+    self.assertIs(
+        pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32'])
+    self.assertIs(
+        pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'),
+        unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension'])
+    self.assertIs(
+        pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'),
+        unittest_pb2.ForeignEnum.DESCRIPTOR)
+    self.assertIs(
+        pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'),
+        unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field'])
+
+  def testAddFileDescriptor(self):
+    # pylint: disable=g-import-not-at-top
+    from google.protobuf.pyext import _message
+    pool = _message.default_pool
+    file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto')
+    pool.Add(file_desc)
+    pool.AddSerializedFile(file_desc.SerializeToString())
+
+
 TEST1_FILE = ProtoFile(
     'google/protobuf/internal/descriptor_pool_test1.proto',
     'google.protobuf.python.internal',
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index 335caee..26866f3 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -35,8 +35,8 @@
 __author__ = 'robinson@google.com (Will Robinson)'
 
 import sys
-import unittest
 
+import unittest
 from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_pb2
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index 38a5138..752f4ea 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -314,7 +314,7 @@
 
 
 # --------------------------------------------------------------------
-# MessageSet is special.
+# MessageSet is special: it needs custom logic to compute its size properly.
 
 
 def MessageSetItemSizer(field_number):
@@ -339,6 +339,32 @@
   return FieldSize
 
 
+# --------------------------------------------------------------------
+# Map is special: it needs custom logic to compute its size properly.
+
+
+def MapSizer(field_descriptor):
+  """Returns a sizer for a map field."""
+
+  # Can't look at field_descriptor.message_type._concrete_class because it may
+  # not have been initialized yet.
+  message_type = field_descriptor.message_type
+  message_sizer = MessageSizer(field_descriptor.number, False, False)
+
+  def FieldSize(map_value):
+    total = 0
+    for key in map_value:
+      value = map_value[key]
+      # It's wasteful to create the messages and throw them away one second
+      # later since we'll do the same for the actual encode.  But there's not an
+      # obvious way to avoid this within the current design without tons of code
+      # duplication.
+      entry_msg = message_type._concrete_class(key=key, value=value)
+      total += message_sizer(entry_msg)
+    return total
+
+  return FieldSize
+
 # ====================================================================
 # Encoders!
 
@@ -786,3 +812,30 @@
     return write(end_bytes)
 
   return EncodeField
+
+
+# --------------------------------------------------------------------
+# As before, Map is special.
+
+
+def MapEncoder(field_descriptor):
+  """Encoder for extensions of MessageSet.
+
+  Maps always have a wire format like this:
+    message MapEntry {
+      key_type key = 1;
+      value_type value = 2;
+    }
+    repeated MapEntry map = N;
+  """
+  # Can't look at field_descriptor.message_type._concrete_class because it may
+  # not have been initialized yet.
+  message_type = field_descriptor.message_type
+  encode_message = MessageEncoder(field_descriptor.number, False, False)
+
+  def EncodeField(write, value):
+    for key in value:
+      entry_msg = message_type._concrete_class(key=key, value=value[key])
+      encode_message(write, entry_msg)
+
+  return EncodeField
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
index ccc5860..5c07cbe 100755
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -42,7 +42,6 @@
 __author__ = 'robinson@google.com (Will Robinson)'
 
 import unittest
-
 from google.protobuf.internal import test_bad_identifiers_pb2
 from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index 626c3fc..b8694f9 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -35,7 +35,6 @@
 __author__ = 'matthewtoia@google.com (Matt Toia)'
 
 import unittest
-
 from google.protobuf import descriptor_pb2
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 4ecaa1c..320ff0d 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -50,7 +50,9 @@
 import sys
 import unittest
 
+import unittest
 from google.protobuf.internal import _parameterized
+from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
@@ -125,10 +127,17 @@
     self.assertEqual(unpickled_message, golden_message)
 
   def testPositiveInfinity(self, message_module):
-    golden_data = (b'\x5D\x00\x00\x80\x7F'
-                   b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
-                   b'\xCD\x02\x00\x00\x80\x7F'
-                   b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCD\x02\x00\x00\x80\x7F'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\x7F'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F'
+                     b'\xCA\x02\x04\x00\x00\x80\x7F'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\x7F')
+
     golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsPosInf(golden_message.optional_float))
@@ -138,10 +147,17 @@
     self.assertEqual(golden_data, golden_message.SerializeToString())
 
   def testNegativeInfinity(self, message_module):
-    golden_data = (b'\x5D\x00\x00\x80\xFF'
-                   b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
-                   b'\xCD\x02\x00\x00\x80\xFF'
-                   b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
+    if message_module is unittest_pb2:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCD\x02\x00\x00\x80\xFF'
+                     b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF')
+    else:
+      golden_data = (b'\x5D\x00\x00\x80\xFF'
+                     b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF'
+                     b'\xCA\x02\x04\x00\x00\x80\xFF'
+                     b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\xFF')
+
     golden_message = message_module.TestAllTypes()
     golden_message.ParseFromString(golden_data)
     self.assertTrue(IsNegInf(golden_message.optional_float))
@@ -1034,64 +1050,132 @@
     self.assertEqual(len(parsing_merge.Extensions[
         unittest_pb2.TestParsingMerge.repeated_ext]), 3)
 
+  def testPythonicInit(self):
+    message = unittest_pb2.TestAllTypes(
+        optional_int32=100,
+        optional_fixed32=200,
+        optional_float=300.5,
+        optional_bytes=b'x',
+        optionalgroup={'a': 400},
+        optional_nested_message={'bb': 500},
+        optional_nested_enum='BAZ',
+        repeatedgroup=[{'a': 600},
+                       {'a': 700}],
+        repeated_nested_enum=['FOO', unittest_pb2.TestAllTypes.BAR],
+        default_int32=800,
+        oneof_string='y')
+    self.assertTrue(isinstance(message, unittest_pb2.TestAllTypes))
+    self.assertEqual(100, message.optional_int32)
+    self.assertEqual(200, message.optional_fixed32)
+    self.assertEqual(300.5, message.optional_float)
+    self.assertEqual(b'x', message.optional_bytes)
+    self.assertEqual(400, message.optionalgroup.a)
+    self.assertTrue(isinstance(message.optional_nested_message,
+                               unittest_pb2.TestAllTypes.NestedMessage))
+    self.assertEqual(500, message.optional_nested_message.bb)
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
+    self.assertEqual(2, len(message.repeatedgroup))
+    self.assertEqual(600, message.repeatedgroup[0].a)
+    self.assertEqual(700, message.repeatedgroup[1].a)
+    self.assertEqual(2, len(message.repeated_nested_enum))
+    self.assertEqual(unittest_pb2.TestAllTypes.FOO,
+                     message.repeated_nested_enum[0])
+    self.assertEqual(unittest_pb2.TestAllTypes.BAR,
+                     message.repeated_nested_enum[1])
+    self.assertEqual(800, message.default_int32)
+    self.assertEqual('y', message.oneof_string)
+    self.assertFalse(message.HasField('optional_int64'))
+    self.assertEqual(0, len(message.repeated_float))
+    self.assertEqual(42, message.default_int64)
+
+    message = unittest_pb2.TestAllTypes(optional_nested_enum=u'BAZ')
+    self.assertEqual(unittest_pb2.TestAllTypes.BAZ,
+                     message.optional_nested_enum)
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'INVALID_NESTED_FIELD': 17})
+
+    with self.assertRaises(TypeError):
+      unittest_pb2.TestAllTypes(
+          optional_nested_message={'bb': 'INVALID_VALUE_TYPE'})
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(optional_nested_enum='INVALID_LABEL')
+
+    with self.assertRaises(ValueError):
+      unittest_pb2.TestAllTypes(repeated_nested_enum='FOO')
+
 
 # Class to test proto3-only features/behavior (updated field presence & enums)
 class Proto3Test(unittest.TestCase):
 
+  # Utility method for comparing equality with a map.
+  def assertMapIterEquals(self, map_iter, dict_value):
+    # Avoid mutating caller's copy.
+    dict_value = dict(dict_value)
+
+    for k, v in map_iter:
+      self.assertEqual(v, dict_value[k])
+      del dict_value[k]
+
+    self.assertEqual({}, dict_value)
+
   def testFieldPresence(self):
     message = unittest_proto3_arena_pb2.TestAllTypes()
 
     # We can't test presence of non-repeated, non-submessage fields.
     with self.assertRaises(ValueError):
-      message.HasField("optional_int32")
+      message.HasField('optional_int32')
     with self.assertRaises(ValueError):
-      message.HasField("optional_float")
+      message.HasField('optional_float')
     with self.assertRaises(ValueError):
-      message.HasField("optional_string")
+      message.HasField('optional_string')
     with self.assertRaises(ValueError):
-      message.HasField("optional_bool")
+      message.HasField('optional_bool')
 
     # But we can still test presence of submessage fields.
-    self.assertFalse(message.HasField("optional_nested_message"))
+    self.assertFalse(message.HasField('optional_nested_message'))
 
     # As with proto2, we can't test presence of fields that don't exist, or
     # repeated fields.
     with self.assertRaises(ValueError):
-      message.HasField("field_doesnt_exist")
+      message.HasField('field_doesnt_exist')
 
     with self.assertRaises(ValueError):
-      message.HasField("repeated_int32")
+      message.HasField('repeated_int32')
     with self.assertRaises(ValueError):
-      message.HasField("repeated_nested_message")
+      message.HasField('repeated_nested_message')
 
     # Fields should default to their type-specific default.
     self.assertEqual(0, message.optional_int32)
     self.assertEqual(0, message.optional_float)
-    self.assertEqual("", message.optional_string)
+    self.assertEqual('', message.optional_string)
     self.assertEqual(False, message.optional_bool)
     self.assertEqual(0, message.optional_nested_message.bb)
 
     # Setting a submessage should still return proper presence information.
     message.optional_nested_message.bb = 0
-    self.assertTrue(message.HasField("optional_nested_message"))
+    self.assertTrue(message.HasField('optional_nested_message'))
 
     # Set the fields to non-default values.
     message.optional_int32 = 5
     message.optional_float = 1.1
-    message.optional_string = "abc"
+    message.optional_string = 'abc'
     message.optional_bool = True
     message.optional_nested_message.bb = 15
 
     # Clearing the fields unsets them and resets their value to default.
-    message.ClearField("optional_int32")
-    message.ClearField("optional_float")
-    message.ClearField("optional_string")
-    message.ClearField("optional_bool")
-    message.ClearField("optional_nested_message")
+    message.ClearField('optional_int32')
+    message.ClearField('optional_float')
+    message.ClearField('optional_string')
+    message.ClearField('optional_bool')
+    message.ClearField('optional_nested_message')
 
     self.assertEqual(0, message.optional_int32)
     self.assertEqual(0, message.optional_float)
-    self.assertEqual("", message.optional_string)
+    self.assertEqual('', message.optional_string)
     self.assertEqual(False, message.optional_bool)
     self.assertEqual(0, message.optional_nested_message.bb)
 
@@ -1113,6 +1197,393 @@
     self.assertEqual(1234567, m2.optional_nested_enum)
     self.assertEqual(7654321, m2.repeated_nested_enum[0])
 
+  # Map isn't really a proto3-only feature. But there is no proto2 equivalent
+  # of google/protobuf/map_unittest.proto right now, so it's not easy to
+  # test both with the same test like we do for the other proto2/proto3 tests.
+  # (google/protobuf/map_protobuf_unittest.proto is very different in the set
+  # of messages and fields it contains).
+  def testScalarMapDefaults(self):
+    msg = map_unittest_pb2.TestMap()
+
+    # Scalars start out unset.
+    self.assertFalse(-123 in msg.map_int32_int32)
+    self.assertFalse(-2**33 in msg.map_int64_int64)
+    self.assertFalse(123 in msg.map_uint32_uint32)
+    self.assertFalse(2**33 in msg.map_uint64_uint64)
+    self.assertFalse('abc' in msg.map_string_string)
+    self.assertFalse(888 in msg.map_int32_enum)
+
+    # Accessing an unset key returns the default.
+    self.assertEqual(0, msg.map_int32_int32[-123])
+    self.assertEqual(0, msg.map_int64_int64[-2**33])
+    self.assertEqual(0, msg.map_uint32_uint32[123])
+    self.assertEqual(0, msg.map_uint64_uint64[2**33])
+    self.assertEqual('', msg.map_string_string['abc'])
+    self.assertEqual(0, msg.map_int32_enum[888])
+
+    # It also sets the value in the map
+    self.assertTrue(-123 in msg.map_int32_int32)
+    self.assertTrue(-2**33 in msg.map_int64_int64)
+    self.assertTrue(123 in msg.map_uint32_uint32)
+    self.assertTrue(2**33 in msg.map_uint64_uint64)
+    self.assertTrue('abc' in msg.map_string_string)
+    self.assertTrue(888 in msg.map_int32_enum)
+
+    self.assertTrue(isinstance(msg.map_string_string['abc'], unicode))
+
+    # Accessing an unset key still throws TypeError of the type of the key
+    # is incorrect.
+    with self.assertRaises(TypeError):
+      msg.map_string_string[123]
+
+    self.assertFalse(123 in msg.map_string_string)
+
+  def testMapGet(self):
+    # Need to test that get() properly returns the default, even though the dict
+    # has defaultdict-like semantics.
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertIsNone(msg.map_int32_int32.get(5))
+    self.assertEquals(10, msg.map_int32_int32.get(5, 10))
+    self.assertIsNone(msg.map_int32_int32.get(5))
+
+    msg.map_int32_int32[5] = 15
+    self.assertEquals(15, msg.map_int32_int32.get(5))
+
+    self.assertIsNone(msg.map_int32_foreign_message.get(5))
+    self.assertEquals(10, msg.map_int32_foreign_message.get(5, 10))
+
+    submsg = msg.map_int32_foreign_message[5]
+    self.assertIs(submsg, msg.map_int32_foreign_message.get(5))
+
+  def testScalarMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_int32))
+    self.assertFalse(5 in msg.map_int32_int32)
+
+    msg.map_int32_int32[-123] = -456
+    msg.map_int64_int64[-2**33] = -2**34
+    msg.map_uint32_uint32[123] = 456
+    msg.map_uint64_uint64[2**33] = 2**34
+    msg.map_string_string['abc'] = '123'
+    msg.map_int32_enum[888] = 2
+
+    self.assertEqual([], msg.FindInitializationErrors())
+
+    self.assertEqual(1, len(msg.map_string_string))
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg.map_string_string[123] = '123'
+
+    # Verify that trying to assign a bad key doesn't actually add a member to
+    # the map.
+    self.assertEqual(1, len(msg.map_string_string))
+
+    # Bad value.
+    with self.assertRaises(TypeError):
+      msg.map_string_string['123'] = 123
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg2.map_string_string[123] = '123'
+
+    # Bad value.
+    with self.assertRaises(TypeError):
+      msg2.map_string_string['123'] = 123
+
+    self.assertEqual(-456, msg2.map_int32_int32[-123])
+    self.assertEqual(-2**34, msg2.map_int64_int64[-2**33])
+    self.assertEqual(456, msg2.map_uint32_uint32[123])
+    self.assertEqual(2**34, msg2.map_uint64_uint64[2**33])
+    self.assertEqual('123', msg2.map_string_string['abc'])
+    self.assertEqual(2, msg2.map_int32_enum[888])
+
+  def testStringUnicodeConversionInMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    unicode_obj = u'\u1234'
+    bytes_obj = unicode_obj.encode('utf8') 
+
+    msg.map_string_string[bytes_obj] = bytes_obj
+
+    (key, value) = msg.map_string_string.items()[0]
+
+    self.assertEqual(key, unicode_obj)
+    self.assertEqual(value, unicode_obj)
+
+    self.assertTrue(isinstance(key, unicode))
+    self.assertTrue(isinstance(value, unicode))
+
+  def testMessageMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_foreign_message))
+    self.assertFalse(5 in msg.map_int32_foreign_message)
+
+    msg.map_int32_foreign_message[123]
+    # get_or_create() is an alias for getitem.
+    msg.map_int32_foreign_message.get_or_create(-456)
+
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+    self.assertIn(123, msg.map_int32_foreign_message)
+    self.assertIn(-456, msg.map_int32_foreign_message)
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+
+    # Bad key.
+    with self.assertRaises(TypeError):
+      msg.map_int32_foreign_message['123']
+
+    # Can't assign directly to submessage.
+    with self.assertRaises(ValueError):
+      msg.map_int32_foreign_message[999] = msg.map_int32_foreign_message[123]
+
+    # Verify that trying to assign a bad key doesn't actually add a member to
+    # the map.
+    self.assertEqual(2, len(msg.map_int32_foreign_message))
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(2, len(msg2.map_int32_foreign_message))
+    self.assertIn(123, msg2.map_int32_foreign_message)
+    self.assertIn(-456, msg2.map_int32_foreign_message)
+    self.assertEqual(2, len(msg2.map_int32_foreign_message))
+
+  def testMergeFrom(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[12] = 34
+    msg.map_int32_int32[56] = 78
+    msg.map_int64_int64[22] = 33
+    msg.map_int32_foreign_message[111].c = 5
+    msg.map_int32_foreign_message[222].c = 10
+
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.map_int32_int32[12] = 55
+    msg2.map_int64_int64[88] = 99
+    msg2.map_int32_foreign_message[222].c = 15
+
+    msg2.MergeFrom(msg)
+
+    self.assertEqual(34, msg2.map_int32_int32[12])
+    self.assertEqual(78, msg2.map_int32_int32[56])
+    self.assertEqual(33, msg2.map_int64_int64[22])
+    self.assertEqual(99, msg2.map_int64_int64[88])
+    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
+    self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
+
+    # Verify that there is only one entry per key, even though the MergeFrom
+    # may have internally created multiple entries for a single key in the
+    # list representation.
+    as_dict = {}
+    for key in msg2.map_int32_foreign_message:
+      self.assertFalse(key in as_dict)
+      as_dict[key] = msg2.map_int32_foreign_message[key].c
+
+    self.assertEqual({111: 5, 222: 10}, as_dict)
+
+    # Special case: test that delete of item really removes the item, even if
+    # there might have physically been duplicate keys due to the previous merge.
+    # This is only a special case for the C++ implementation which stores the
+    # map as an array.
+    del msg2.map_int32_int32[12]
+    self.assertFalse(12 in msg2.map_int32_int32)
+
+    del msg2.map_int32_foreign_message[222]
+    self.assertFalse(222 in msg2.map_int32_foreign_message)
+
+  def testIntegerMapWithLongs(self):
+    msg = map_unittest_pb2.TestMap()
+    msg.map_int32_int32[long(-123)] = long(-456)
+    msg.map_int64_int64[long(-2**33)] = long(-2**34)
+    msg.map_uint32_uint32[long(123)] = long(456)
+    msg.map_uint64_uint64[long(2**33)] = long(2**34)
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(-456, msg2.map_int32_int32[-123])
+    self.assertEqual(-2**34, msg2.map_int64_int64[-2**33])
+    self.assertEqual(456, msg2.map_uint32_uint32[123])
+    self.assertEqual(2**34, msg2.map_uint64_uint64[2**33])
+
+  def testMapAssignmentCausesPresence(self):
+    msg = map_unittest_pb2.TestMapSubmessage()
+    msg.test_map.map_int32_int32[123] = 456
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMapSubmessage()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(msg, msg2)
+
+    # Now test that various mutations of the map properly invalidate the
+    # cached size of the submessage.
+    msg.test_map.map_int32_int32[888] = 999
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_int32.clear()
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+  def testMapAssignmentCausesPresenceForSubmessages(self):
+    msg = map_unittest_pb2.TestMapSubmessage()
+    msg.test_map.map_int32_foreign_message[123].c = 5
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMapSubmessage()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(msg, msg2)
+
+    # Now test that various mutations of the map properly invalidate the
+    # cached size of the submessage.
+    msg.test_map.map_int32_foreign_message[888].c = 7
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_foreign_message[888].MergeFrom(
+        msg.test_map.map_int32_foreign_message[123])
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+    msg.test_map.map_int32_foreign_message.clear()
+    serialized = msg.SerializeToString()
+    msg2.ParseFromString(serialized)
+    self.assertEqual(msg, msg2)
+
+  def testModifyMapWhileIterating(self):
+    msg = map_unittest_pb2.TestMap()
+
+    string_string_iter = iter(msg.map_string_string)
+    int32_foreign_iter = iter(msg.map_int32_foreign_message)
+
+    msg.map_string_string['abc'] = '123'
+    msg.map_int32_foreign_message[5].c = 5
+
+    with self.assertRaises(RuntimeError):
+      for key in string_string_iter:
+        pass
+
+    with self.assertRaises(RuntimeError):
+      for key in int32_foreign_iter:
+        pass
+
+  def testSubmessageMap(self):
+    msg = map_unittest_pb2.TestMap()
+
+    submsg = msg.map_int32_foreign_message[111]
+    self.assertIs(submsg, msg.map_int32_foreign_message[111])
+    self.assertTrue(isinstance(submsg, unittest_pb2.ForeignMessage))
+
+    submsg.c = 5
+
+    serialized = msg.SerializeToString()
+    msg2 = map_unittest_pb2.TestMap()
+    msg2.ParseFromString(serialized)
+
+    self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
+
+    # Doesn't allow direct submessage assignment.
+    with self.assertRaises(ValueError):
+      msg.map_int32_foreign_message[88] = unittest_pb2.ForeignMessage()
+
+  def testMapIteration(self):
+    msg = map_unittest_pb2.TestMap()
+
+    for k, v in msg.map_int32_int32.iteritems():
+      # Should not be reached.
+      self.assertTrue(False)
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+    self.assertEqual(3, len(msg.map_int32_int32))
+
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(msg.map_int32_int32.iteritems(), matching_dict)
+
+  def testMapIterationClearMessage(self):
+    # Iterator needs to work even if message and map are deleted.
+    msg = map_unittest_pb2.TestMap()
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+
+    it = msg.map_int32_int32.iteritems()
+    del msg
+
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(it, matching_dict)
+
+  def testMapConstruction(self):
+    msg = map_unittest_pb2.TestMap(map_int32_int32={1: 2, 3: 4})
+    self.assertEqual(2, msg.map_int32_int32[1])
+    self.assertEqual(4, msg.map_int32_int32[3])
+
+    msg = map_unittest_pb2.TestMap(
+        map_int32_foreign_message={3: unittest_pb2.ForeignMessage(c=5)})
+    self.assertEqual(5, msg.map_int32_foreign_message[3].c)
+
+  def testMapValidAfterFieldCleared(self):
+    # Map needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+    map = msg.map_int32_int32
+
+    map[2] = 4
+    map[3] = 6
+    map[4] = 8
+
+    msg.ClearField('map_int32_int32')
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(map.iteritems(), matching_dict)
+
+  def testMapIterValidAfterFieldCleared(self):
+    # Map iterator needs to work even if field is cleared.
+    # For the C++ implementation this tests the correctness of
+    # ScalarMapContainer::Release()
+    msg = map_unittest_pb2.TestMap()
+
+    msg.map_int32_int32[2] = 4
+    msg.map_int32_int32[3] = 6
+    msg.map_int32_int32[4] = 8
+
+    it = msg.map_int32_int32.iteritems()
+
+    msg.ClearField('map_int32_int32')
+    matching_dict = {2: 4, 3: 6, 4: 8}
+    self.assertMapIterEquals(it, matching_dict)
+
+  def testMapDelete(self):
+    msg = map_unittest_pb2.TestMap()
+
+    self.assertEqual(0, len(msg.map_int32_int32))
+
+    msg.map_int32_int32[4] = 6
+    self.assertEqual(1, len(msg.map_int32_int32))
+
+    with self.assertRaises(KeyError):
+      del msg.map_int32_int32[88]
+
+    del msg.map_int32_int32[4]
+    self.assertEqual(0, len(msg.map_int32_int32))
+
+
 
 class ValidTypeNamesTest(unittest.TestCase):
 
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
index b1e57f3..edaf3fa 100644
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -32,6 +32,7 @@
 
 """Tests for google.protobuf.proto_builder."""
 
+import collections
 import unittest
 
 from google.protobuf import descriptor_pb2
@@ -43,10 +44,11 @@
 class ProtoBuilderTest(unittest.TestCase):
 
   def setUp(self):
-    self._fields = {
-        'foo': descriptor_pb2.FieldDescriptorProto.TYPE_INT64,
-        'bar': descriptor_pb2.FieldDescriptorProto.TYPE_STRING,
-        }
+    self.ordered_fields = collections.OrderedDict([
+        ('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64),
+        ('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING),
+        ])
+    self._fields = dict(self.ordered_fields)
 
   def testMakeSimpleProtoClass(self):
     """Test that we can create a proto class."""
@@ -59,6 +61,17 @@
     self.assertMultiLineEqual(
         'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto))
 
+  def testOrderedFields(self):
+    """Test that the field order is maintained when given an OrderedDict."""
+    proto_cls = proto_builder.MakeSimpleProtoClass(
+        self.ordered_fields,
+        full_name='net.proto2.python.public.proto_builder_test.OrderedTest')
+    proto = proto_cls()
+    proto.foo = 12345
+    proto.bar = 'asdf'
+    self.assertMultiLineEqual(
+        'foo: 12345\nbar: "asdf"\n', text_format.MessageToString(proto))
+
   def testMakeSameProtoClassTwice(self):
     """Test that the DescriptorPool is used."""
     pool = descriptor_pool.DescriptorPool()
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 54f584a..ca9f767 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -61,9 +61,11 @@
   except ImportError:
     from StringIO import StringIO as BytesIO
   import copy_reg as copyreg
+  _basestring = basestring
 else:
   from io import BytesIO
   import copyreg
+  _basestring = str
 import struct
 import weakref
 
@@ -77,6 +79,7 @@
 from google.protobuf.internal import wire_format
 from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message as message_mod
+from google.protobuf import symbol_database
 from google.protobuf import text_format
 
 _FieldDescriptor = descriptor_mod.FieldDescriptor
@@ -101,6 +104,7 @@
   for field in descriptor.fields:
     _AttachFieldHelpers(cls, field)
 
+  descriptor._concrete_class = cls  # pylint: disable=protected-access
   _AddEnumValues(descriptor, cls)
   _AddInitMethod(descriptor, cls)
   _AddPropertiesForFields(descriptor, cls)
@@ -198,12 +202,37 @@
           field.label == _FieldDescriptor.LABEL_OPTIONAL)
 
 
+def _IsMapField(field):
+  return (field.type == _FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
+
+
+def _IsMessageMapField(field):
+  value_type = field.message_type.fields_by_name["value"]
+  return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE
+
+
 def _AttachFieldHelpers(cls, field_descriptor):
   is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED)
-  is_packed = (field_descriptor.has_options and
-               field_descriptor.GetOptions().packed)
+  is_packable = (is_repeated and
+                 wire_format.IsTypePackable(field_descriptor.type))
+  if not is_packable:
+    is_packed = False
+  elif field_descriptor.containing_type.syntax == "proto2":
+    is_packed = (field_descriptor.has_options and
+                field_descriptor.GetOptions().packed)
+  else:
+    has_packed_false = (field_descriptor.has_options and
+                        field_descriptor.GetOptions().HasField("packed") and
+                        field_descriptor.GetOptions().packed == False)
+    is_packed = not has_packed_false
+  is_map_entry = _IsMapField(field_descriptor)
 
-  if _IsMessageSetExtension(field_descriptor):
+  if is_map_entry:
+    field_encoder = encoder.MapEncoder(field_descriptor)
+    sizer = encoder.MapSizer(field_descriptor)
+  elif _IsMessageSetExtension(field_descriptor):
     field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number)
     sizer = encoder.MessageSetItemSizer(field_descriptor.number)
   else:
@@ -228,9 +257,16 @@
     if field_descriptor.containing_oneof is not None:
       oneof_descriptor = field_descriptor
 
-    field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
-        field_descriptor.number, is_repeated, is_packed,
-        field_descriptor, field_descriptor._default_constructor)
+    if is_map_entry:
+      is_message_map = _IsMessageMapField(field_descriptor)
+
+      field_decoder = decoder.MapDecoder(
+          field_descriptor, _GetInitializeDefaultForMap(field_descriptor),
+          is_message_map)
+    else:
+      field_decoder = type_checkers.TYPE_TO_DECODER[decode_type](
+              field_descriptor.number, is_repeated, is_packed,
+              field_descriptor, field_descriptor._default_constructor)
 
     cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor)
 
@@ -265,6 +301,26 @@
       setattr(cls, enum_value.name, enum_value.number)
 
 
+def _GetInitializeDefaultForMap(field):
+  if field.label != _FieldDescriptor.LABEL_REPEATED:
+    raise ValueError('map_entry set on non-repeated field %s' % (
+        field.name))
+  fields_by_name = field.message_type.fields_by_name
+  key_checker = type_checkers.GetTypeChecker(fields_by_name['key'])
+
+  value_field = fields_by_name['value']
+  if _IsMessageMapField(field):
+    def MakeMessageMapDefault(message):
+      return containers.MessageMap(
+          message._listener_for_children, value_field.message_type, key_checker)
+    return MakeMessageMapDefault
+  else:
+    value_checker = type_checkers.GetTypeChecker(value_field)
+    def MakePrimitiveMapDefault(message):
+      return containers.ScalarMap(
+          message._listener_for_children, key_checker, value_checker)
+    return MakePrimitiveMapDefault
+
 def _DefaultValueConstructorForField(field):
   """Returns a function which returns a default value for a field.
 
@@ -279,6 +335,9 @@
     value may refer back to |message| via a weak reference.
   """
 
+  if _IsMapField(field):
+    return _GetInitializeDefaultForMap(field)
+
   if field.label == _FieldDescriptor.LABEL_REPEATED:
     if field.has_default_value and field.default_value != []:
       raise ValueError('Repeated field default value not empty list: %s' % (
@@ -329,7 +388,22 @@
 
 def _AddInitMethod(message_descriptor, cls):
   """Adds an __init__ method to cls."""
-  fields = message_descriptor.fields
+
+  def _GetIntegerEnumValue(enum_type, value):
+    """Convert a string or integer enum value to an integer.
+
+    If the value is a string, it is converted to the enum value in
+    enum_type with the same name.  If the value is not a string, it's
+    returned as-is.  (No conversion or bounds-checking is done.)
+    """
+    if isinstance(value, _basestring):
+      try:
+        return enum_type.values_by_name[value].number
+      except KeyError:
+        raise ValueError('Enum type %s: unknown label "%s"' % (
+            enum_type.full_name, value))
+    return value
+
   def init(self, **kwargs):
     self._cached_byte_size = 0
     self._cached_byte_size_dirty = len(kwargs) > 0
@@ -352,19 +426,37 @@
       if field.label == _FieldDescriptor.LABEL_REPEATED:
         copy = field._default_constructor(self)
         if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:  # Composite
-          for val in field_value:
-            copy.add().MergeFrom(val)
+          if _IsMapField(field):
+            if _IsMessageMapField(field):
+              for key in field_value:
+                copy[key].MergeFrom(field_value[key])
+            else:
+              copy.update(field_value)
+          else:
+            for val in field_value:
+              if isinstance(val, dict):
+                copy.add(**val)
+              else:
+                copy.add().MergeFrom(val)
         else:  # Scalar
+          if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+            field_value = [_GetIntegerEnumValue(field.enum_type, val)
+                           for val in field_value]
           copy.extend(field_value)
         self._fields[field] = copy
       elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
         copy = field._default_constructor(self)
+        new_val = field_value
+        if isinstance(field_value, dict):
+          new_val = field.message_type._concrete_class(**field_value)
         try:
-          copy.MergeFrom(field_value)
+          copy.MergeFrom(new_val)
         except TypeError:
           _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name)
         self._fields[field] = copy
       else:
+        if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM:
+          field_value = _GetIntegerEnumValue(field.enum_type, field_value)
         try:
           setattr(self, field_name, field_value)
         except TypeError:
@@ -758,6 +850,26 @@
       return extension_handle in self._fields
   cls.HasExtension = HasExtension
 
+def _UnpackAny(msg):
+  type_url = msg.type_url
+  db = symbol_database.Default()
+
+  if not type_url:
+    return None
+
+  # TODO(haberman): For now we just strip the hostname.  Better logic will be
+  # required.
+  type_name = type_url.split("/")[-1]
+  descriptor = db.pool.FindMessageTypeByName(type_name)
+
+  if descriptor is None:
+    return None
+
+  message_class = db.GetPrototype(descriptor)
+  message = message_class()
+
+  message.ParseFromString(msg.value)
+  return message
 
 def _AddEqualsMethod(message_descriptor, cls):
   """Helper for _AddMessageMethods()."""
@@ -769,6 +881,12 @@
     if self is other:
       return True
 
+    if self.DESCRIPTOR.full_name == "google.protobuf.Any":
+      any_a = _UnpackAny(self)
+      any_b = _UnpackAny(other)
+      if any_a and any_b:
+        return any_a == any_b
+
     if not self.ListFields() == other.ListFields():
       return False
 
@@ -961,6 +1079,9 @@
     for field, value in list(self._fields.items()):  # dict can change size!
       if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
         if field.label == _FieldDescriptor.LABEL_REPEATED:
+          if (field.message_type.has_options and
+              field.message_type.GetOptions().map_entry):
+            continue
           for element in value:
             if not element.IsInitialized():
               if errors is not None:
@@ -996,16 +1117,26 @@
         else:
           name = field.name
 
-        if field.label == _FieldDescriptor.LABEL_REPEATED:
+        if _IsMapField(field):
+          if _IsMessageMapField(field):
+            for key in value:
+              element = value[key]
+              prefix = "%s[%d]." % (name, key)
+              sub_errors = element.FindInitializationErrors()
+              errors += [prefix + error for error in sub_errors]
+          else:
+            # ScalarMaps can't have any initialization errors.
+            pass
+        elif field.label == _FieldDescriptor.LABEL_REPEATED:
           for i in xrange(len(value)):
             element = value[i]
             prefix = "%s[%d]." % (name, i)
             sub_errors = element.FindInitializationErrors()
-            errors += [ prefix + error for error in sub_errors ]
+            errors += [prefix + error for error in sub_errors]
         else:
           prefix = name + "."
           sub_errors = value.FindInitializationErrors()
-          errors += [ prefix + error for error in sub_errors ]
+          errors += [prefix + error for error in sub_errors]
 
     return errors
 
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index ae79c78..4eca498 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -39,8 +39,8 @@
 import gc
 import operator
 import struct
-import unittest
 
+import unittest
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
@@ -1798,8 +1798,8 @@
   def testBadArguments(self):
     # Some of these assertions used to segfault.
     from google.protobuf.pyext import _message
-    self.assertRaises(TypeError, _message.Message._GetFieldDescriptor, 3)
-    self.assertRaises(TypeError, _message.Message._GetExtensionDescriptor, 42)
+    self.assertRaises(TypeError, _message.default_pool.FindFieldByName, 3)
+    self.assertRaises(TypeError, _message.default_pool.FindExtensionByName, 42)
     self.assertRaises(TypeError,
                       unittest_pb2.TestAllTypes().__getattribute__, 42)
 
diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py
index de46212..9967255 100755
--- a/python/google/protobuf/internal/service_reflection_test.py
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -35,7 +35,6 @@
 __author__ = 'petar@google.com (Petar Petrov)'
 
 import unittest
-
 from google.protobuf import unittest_pb2
 from google.protobuf import service_reflection
 from google.protobuf import service
@@ -81,7 +80,7 @@
     self.assertEqual('Method Bar not implemented.',
                      rpc_controller.failure_message)
     self.assertEqual(None, self.callback_response)
-
+    
     class MyServiceImpl(unittest_pb2.TestService):
       def Foo(self, rpc_controller, request, done):
         self.foo_called = True
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
index c888aff..80b83bc 100644
--- a/python/google/protobuf/internal/symbol_database_test.py
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -33,7 +33,6 @@
 """Tests for google.protobuf.symbol_database."""
 
 import unittest
-
 from google.protobuf import unittest_pb2
 from google.protobuf import symbol_database
 
diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py
index d84e383..0cbdbad 100755
--- a/python/google/protobuf/internal/test_util.py
+++ b/python/google/protobuf/internal/test_util.py
@@ -75,7 +75,8 @@
   message.optional_string   = u'115'
   message.optional_bytes    = b'116'
 
-  message.optionalgroup.a = 117
+  if IsProto2(message):
+    message.optionalgroup.a = 117
   message.optional_nested_message.bb = 118
   message.optional_foreign_message.c = 119
   message.optional_import_message.d = 120
@@ -109,7 +110,8 @@
   message.repeated_string.append(u'215')
   message.repeated_bytes.append(b'216')
 
-  message.repeatedgroup.add().a = 217
+  if IsProto2(message):
+    message.repeatedgroup.add().a = 217
   message.repeated_nested_message.add().bb = 218
   message.repeated_foreign_message.add().c = 219
   message.repeated_import_message.add().d = 220
@@ -140,7 +142,8 @@
   message.repeated_string.append(u'315')
   message.repeated_bytes.append(b'316')
 
-  message.repeatedgroup.add().a = 317
+  if IsProto2(message):
+    message.repeatedgroup.add().a = 317
   message.repeated_nested_message.add().bb = 318
   message.repeated_foreign_message.add().c = 319
   message.repeated_import_message.add().d = 320
@@ -396,7 +399,8 @@
   test_case.assertTrue(message.HasField('optional_string'))
   test_case.assertTrue(message.HasField('optional_bytes'))
 
-  test_case.assertTrue(message.HasField('optionalgroup'))
+  if IsProto2(message):
+    test_case.assertTrue(message.HasField('optionalgroup'))
   test_case.assertTrue(message.HasField('optional_nested_message'))
   test_case.assertTrue(message.HasField('optional_foreign_message'))
   test_case.assertTrue(message.HasField('optional_import_message'))
@@ -430,7 +434,8 @@
   test_case.assertEqual('115', message.optional_string)
   test_case.assertEqual(b'116', message.optional_bytes)
 
-  test_case.assertEqual(117, message.optionalgroup.a)
+  if IsProto2(message):
+    test_case.assertEqual(117, message.optionalgroup.a)
   test_case.assertEqual(118, message.optional_nested_message.bb)
   test_case.assertEqual(119, message.optional_foreign_message.c)
   test_case.assertEqual(120, message.optional_import_message.d)
@@ -463,7 +468,8 @@
   test_case.assertEqual(2, len(message.repeated_string))
   test_case.assertEqual(2, len(message.repeated_bytes))
 
-  test_case.assertEqual(2, len(message.repeatedgroup))
+  if IsProto2(message):
+    test_case.assertEqual(2, len(message.repeatedgroup))
   test_case.assertEqual(2, len(message.repeated_nested_message))
   test_case.assertEqual(2, len(message.repeated_foreign_message))
   test_case.assertEqual(2, len(message.repeated_import_message))
@@ -491,7 +497,8 @@
   test_case.assertEqual('215', message.repeated_string[0])
   test_case.assertEqual(b'216', message.repeated_bytes[0])
 
-  test_case.assertEqual(217, message.repeatedgroup[0].a)
+  if IsProto2(message):
+    test_case.assertEqual(217, message.repeatedgroup[0].a)
   test_case.assertEqual(218, message.repeated_nested_message[0].bb)
   test_case.assertEqual(219, message.repeated_foreign_message[0].c)
   test_case.assertEqual(220, message.repeated_import_message[0].d)
@@ -521,7 +528,8 @@
   test_case.assertEqual('315', message.repeated_string[1])
   test_case.assertEqual(b'316', message.repeated_bytes[1])
 
-  test_case.assertEqual(317, message.repeatedgroup[1].a)
+  if IsProto2(message):
+    test_case.assertEqual(317, message.repeatedgroup[1].a)
   test_case.assertEqual(318, message.repeated_nested_message[1].bb)
   test_case.assertEqual(319, message.repeated_foreign_message[1].c)
   test_case.assertEqual(320, message.repeated_import_message[1].d)
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
index 27896b9..5df13b7 100755
--- a/python/google/protobuf/internal/text_encoding_test.py
+++ b/python/google/protobuf/internal/text_encoding_test.py
@@ -33,7 +33,6 @@
 """Tests for google.protobuf.text_encoding."""
 
 import unittest
-
 from google.protobuf import text_encoding
 
 TEST_VALUES = [
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index bf7e06e..06bd1ee 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -37,8 +37,10 @@
 import re
 import unittest
 
+import unittest
 from google.protobuf.internal import _parameterized
 
+from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
@@ -309,31 +311,6 @@
          r'"unknown_field".'),
         text_format.Parse, text, message)
 
-  def testParseGroupNotClosed(self, message_module):
-    message = message_module.TestAllTypes()
-    text = 'RepeatedGroup: <'
-    self.assertRaisesRegexp(
-        text_format.ParseError, '1:16 : Expected ">".',
-        text_format.Parse, text, message)
-
-    text = 'RepeatedGroup: {'
-    self.assertRaisesRegexp(
-        text_format.ParseError, '1:16 : Expected "}".',
-        text_format.Parse, text, message)
-
-  def testParseEmptyGroup(self, message_module):
-    message = message_module.TestAllTypes()
-    text = 'OptionalGroup: {}'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
-    message.Clear()
-
-    message = message_module.TestAllTypes()
-    text = 'OptionalGroup: <>'
-    text_format.Parse(text, message)
-    self.assertTrue(message.HasField('optionalgroup'))
-
   def testParseBadEnumValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
@@ -408,6 +385,14 @@
 # Ideally the schemas would be made more similar so these tests could pass.
 class OnlyWorksWithProto2RightNowTests(TextFormatBase):
 
+  def testPrintAllFieldsPointy(self, message_module):
+    message = unittest_pb2.TestAllTypes()
+    test_util.SetAllFields(message)
+    self.CompareToGoldenFile(
+        self.RemoveRedundantZeros(
+            text_format.MessageToString(message, pointy_brackets=True)),
+        'text_format_unittest_data_pointy_oneof.txt')
+
   def testParseGolden(self):
     golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt'))
     parsed_message = unittest_pb2.TestAllTypes()
@@ -471,8 +456,49 @@
     test_util.SetAllFields(message)
     self.assertEquals(message, parsed_message)
 
+  def testPrintMap(self):
+    message = map_unittest_pb2.TestMap()
 
-# Tests of proto2-only features (MessageSet and extensions).
+    message.map_int32_int32[-123] = -456
+    message.map_int64_int64[-2**33] = -2**34
+    message.map_uint32_uint32[123] = 456
+    message.map_uint64_uint64[2**33] = 2**34
+    message.map_string_string["abc"] = "123"
+    message.map_int32_foreign_message[111].c = 5
+
+    # Maps are serialized to text format using their underlying repeated
+    # representation.
+    self.CompareToGoldenText(
+        text_format.MessageToString(message),
+        'map_int32_int32 {\n'
+        '  key: -123\n'
+        '  value: -456\n'
+        '}\n'
+        'map_int64_int64 {\n'
+        '  key: -8589934592\n'
+        '  value: -17179869184\n'
+        '}\n'
+        'map_uint32_uint32 {\n'
+        '  key: 123\n'
+        '  value: 456\n'
+        '}\n'
+        'map_uint64_uint64 {\n'
+        '  key: 8589934592\n'
+        '  value: 17179869184\n'
+        '}\n'
+        'map_string_string {\n'
+        '  key: "abc"\n'
+        '  value: "123"\n'
+        '}\n'
+        'map_int32_foreign_message {\n'
+        '  key: 111\n'
+        '  value {\n'
+        '    c: 5\n'
+        '  }\n'
+        '}\n')
+
+
+# Tests of proto2-only features (MessageSet, extensions, etc.).
 class Proto2Tests(TextFormatBase):
 
   def testPrintMessageSet(self):
@@ -620,6 +646,69 @@
          'have multiple "optional_int32" fields.'),
         text_format.Parse, text, message)
 
+  def testParseGroupNotClosed(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'RepeatedGroup: <'
+    self.assertRaisesRegexp(
+        text_format.ParseError, '1:16 : Expected ">".',
+        text_format.Parse, text, message)
+    text = 'RepeatedGroup: {'
+    self.assertRaisesRegexp(
+        text_format.ParseError, '1:16 : Expected "}".',
+        text_format.Parse, text, message)
+
+  def testParseEmptyGroup(self):
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: {}'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+    message.Clear()
+
+    message = unittest_pb2.TestAllTypes()
+    text = 'OptionalGroup: <>'
+    text_format.Parse(text, message)
+    self.assertTrue(message.HasField('optionalgroup'))
+
+  # Maps aren't really proto2-only, but our test schema only has maps for
+  # proto2.
+  def testParseMap(self):
+    text = ('map_int32_int32 {\n'
+            '  key: -123\n'
+            '  value: -456\n'
+            '}\n'
+            'map_int64_int64 {\n'
+            '  key: -8589934592\n'
+            '  value: -17179869184\n'
+            '}\n'
+            'map_uint32_uint32 {\n'
+            '  key: 123\n'
+            '  value: 456\n'
+            '}\n'
+            'map_uint64_uint64 {\n'
+            '  key: 8589934592\n'
+            '  value: 17179869184\n'
+            '}\n'
+            'map_string_string {\n'
+            '  key: "abc"\n'
+            '  value: "123"\n'
+            '}\n'
+            'map_int32_foreign_message {\n'
+            '  key: 111\n'
+            '  value {\n'
+            '    c: 5\n'
+            '  }\n'
+            '}\n')
+    message = map_unittest_pb2.TestMap()
+    text_format.Parse(text, message)
+
+    self.assertEqual(-456, message.map_int32_int32[-123])
+    self.assertEqual(-2**34, message.map_int64_int64[-2**33])
+    self.assertEqual(456, message.map_uint32_uint32[123])
+    self.assertEqual(2**34, message.map_uint64_uint64[2**33])
+    self.assertEqual("123", message.map_string_string["abc"])
+    self.assertEqual(5, message.map_int32_foreign_message[111].c)
+
 
 class TokenizerTest(unittest.TestCase):
 
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 76c056c..f20e526 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -129,6 +129,9 @@
     proposed_value = self._TYPE(proposed_value)
     return proposed_value
 
+  def DefaultValue(self):
+    return 0
+
 
 class EnumValueChecker(object):
 
@@ -146,6 +149,9 @@
       raise ValueError('Unknown enum value: %d' % proposed_value)
     return proposed_value
 
+  def DefaultValue(self):
+    return self._enum_type.values[0].number
+
 
 class UnicodeValueChecker(object):
 
@@ -171,6 +177,9 @@
                          (proposed_value))
     return proposed_value
 
+  def DefaultValue(self):
+    return u""
+
 
 class Int32ValueChecker(IntValueChecker):
   # We're sure to use ints instead of longs here since comparison may be more
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 9337ae8..1b81ae7 100755
--- a/python/google/protobuf/internal/unknown_fields_test.py
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -36,7 +36,6 @@
 __author__ = 'bohdank@google.com (Bohdan Koval)'
 
 import unittest
-
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
index 5cd7fcb..78dc116 100755
--- a/python/google/protobuf/internal/wire_format_test.py
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -35,7 +35,6 @@
 __author__ = 'robinson@google.com (Will Robinson)'
 
 import unittest
-
 from google.protobuf import message
 from google.protobuf.internal import wire_format
 
diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py
index 1fa28f1..7489cf6 100644
--- a/python/google/protobuf/proto_builder.py
+++ b/python/google/protobuf/proto_builder.py
@@ -30,6 +30,7 @@
 
 """Dynamic Protobuf class creator."""
 
+import collections
 import hashlib
 import os
 
@@ -59,7 +60,9 @@
   Note: this doesn't validate field names!
 
   Args:
-    fields: dict of {name: field_type} mappings for each field in the proto.
+    fields: dict of {name: field_type} mappings for each field in the proto. If
+        this is an OrderedDict the order will be maintained, otherwise the
+        fields will be sorted by name.
     full_name: str, the fully-qualified name of the proto type.
     pool: optional DescriptorPool instance.
   Returns:
@@ -73,12 +76,19 @@
     # The factory's DescriptorPool doesn't know about this class yet.
     pass
 
+  # Get a list of (name, field_type) tuples from the fields dict. If fields was
+  # an OrderedDict we keep the order, but otherwise we sort the field to ensure
+  # consistent ordering.
+  field_items = fields.items()
+  if not isinstance(fields, collections.OrderedDict):
+    field_items = sorted(field_items)
+
   # Use a consistent file name that is unlikely to conflict with any imported
   # proto files.
   fields_hash = hashlib.sha1()
-  for f_name, f_type in sorted(fields.items()):
-    fields_hash.update(f_name.encode('utf8'))
-    fields_hash.update(str(f_type).encode('utf8'))
+  for f_name, f_type in field_items:
+    fields_hash.update(f_name.encode('utf-8'))
+    fields_hash.update(str(f_type).encode('utf-8'))
   proto_file_name = fields_hash.hexdigest() + '.proto'
 
   package, name = full_name.rsplit('.', 1)
@@ -87,7 +97,7 @@
   file_proto.package = package
   desc_proto = file_proto.message_type.add()
   desc_proto.name = name
-  for f_number, (f_name, f_type) in enumerate(sorted(fields.items()), 1):
+  for f_number, (f_name, f_type) in enumerate(field_items, 1):
     field_proto = desc_proto.field.add()
     field_proto.name = f_name
     field_proto.number = f_number
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index e77d0bb..2160757 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -43,8 +43,6 @@
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define C(str) const_cast<char*>(str)
-
 #if PY_MAJOR_VERSION >= 3
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
   #define PyString_Check PyUnicode_Check
@@ -257,8 +255,14 @@
 // Creates or retrieve a Python descriptor of the specified type.
 // Objects are interned: the same descriptor will return the same object if it
 // was kept alive.
+// 'was_created' is an optional pointer to a bool, and is set to true if a new
+// object was allocated.
 // Always return a new reference.
-PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor) {
+PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor,
+                                bool* was_created) {
+  if (was_created) {
+    *was_created = false;
+  }
   if (descriptor == NULL) {
     PyErr_BadInternalCall();
     return NULL;
@@ -283,6 +287,9 @@
   GetDescriptorPool()->interned_descriptors->insert(
       std::make_pair(descriptor, reinterpret_cast<PyObject*>(py_descriptor)));
 
+  if (was_created) {
+    *was_created = true;
+  }
   return reinterpret_cast<PyObject*>(py_descriptor);
 }
 
@@ -298,9 +305,7 @@
 
 PyTypeObject PyBaseDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.internal._message."
-  "DescriptorBase",                     // tp_name
+  FULL_MODULE_NAME ".DescriptorBase",   // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   (destructor)Dealloc,                  // tp_dealloc
@@ -357,7 +362,7 @@
 }
 
 static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
-  return PyFileDescriptor_New(_GetDescriptor(self)->file());
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
 }
 
 static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
@@ -367,17 +372,6 @@
   return concrete_class;
 }
 
-static int SetConcreteClass(PyBaseDescriptor *self, PyObject *value,
-                            void *closure) {
-  // This attribute is also set from reflection.py. Check that it's actually a
-  // no-op.
-  if (value != cdescriptor_pool::GetMessageClass(
-          GetDescriptorPool(), _GetDescriptor(self))) {
-    PyErr_SetString(PyExc_AttributeError, "Cannot change _concrete_class");
-  }
-  return 0;
-}
-
 static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
   return NewMessageFieldsByName(_GetDescriptor(self));
 }
@@ -452,7 +446,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -515,29 +509,34 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "Last name", NULL},
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("_concrete_class"), (getter)GetConcreteClass, (setter)SetConcreteClass, "concrete class", NULL},
-  { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
+  { "name", (getter)GetName, NULL, "Last name"},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "_concrete_class", (getter)GetConcreteClass, NULL, "concrete class"},
+  { "file", (getter)GetFile, NULL, "File descriptor"},
 
-  { C("fields"), (getter)GetFieldsSeq, NULL, "Fields sequence", NULL},
-  { C("fields_by_name"), (getter)GetFieldsByName, NULL, "Fields by name", NULL},
-  { C("fields_by_number"), (getter)GetFieldsByNumber, NULL, "Fields by number", NULL},
-  { C("nested_types"), (getter)GetNestedTypesSeq, NULL, "Nested types sequence", NULL},
-  { C("nested_types_by_name"), (getter)GetNestedTypesByName, NULL, "Nested types by name", NULL},
-  { C("extensions"), (getter)GetExtensions, NULL, "Extensions Sequence", NULL},
-  { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
-  { C("extension_ranges"), (getter)GetExtensionRanges, NULL, "Extension ranges", NULL},
-  { C("enum_types"), (getter)GetEnumsSeq, NULL, "Enum sequence", NULL},
-  { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enum types by name", NULL},
-  { C("enum_values_by_name"), (getter)GetEnumValuesByName, NULL, "Enum values by name", NULL},
-  { C("oneofs_by_name"), (getter)GetOneofsByName, NULL, "Oneofs by name", NULL},
-  { C("oneofs"), (getter)GetOneofsSeq, NULL, "Oneofs by name", NULL},
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("is_extendable"), (getter)IsExtendable, (setter)NULL, NULL, NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
-  { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+  { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"},
+  { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"},
+  { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"},
+  { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"},
+  { "nested_types_by_name", (getter)GetNestedTypesByName, NULL,
+    "Nested types by name"},
+  { "extensions", (getter)GetExtensions, NULL, "Extensions Sequence"},
+  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
+    "Extensions by name"},
+  { "extension_ranges", (getter)GetExtensionRanges, NULL, "Extension ranges"},
+  { "enum_types", (getter)GetEnumsSeq, NULL, "Enum sequence"},
+  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL,
+    "Enum types by name"},
+  { "enum_values_by_name", (getter)GetEnumValuesByName, NULL,
+    "Enum values by name"},
+  { "oneofs_by_name", (getter)GetOneofsByName, NULL, "Oneofs by name"},
+  { "oneofs", (getter)GetOneofsSeq, NULL, "Oneofs by name"},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "is_extendable", (getter)IsExtendable, (setter)NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
   {NULL}
 };
 
@@ -552,9 +551,7 @@
 
 PyTypeObject PyMessageDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  C("google.protobuf.internal._message."
-    "MessageDescriptor"),      // tp_name
+  FULL_MODULE_NAME ".MessageDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -573,7 +570,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Message Descriptor"),            // tp_doc
+  "A Message Descriptor",               // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -586,10 +583,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyMessageDescriptor_New(
+PyObject* PyMessageDescriptor_FromDescriptor(
     const Descriptor* message_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyMessageDescriptor_Type, message_descriptor);
+      &PyMessageDescriptor_Type, message_descriptor, NULL);
 }
 
 const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) {
@@ -715,7 +712,7 @@
 static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) {
   const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type();
   if (enum_type) {
-    return PyEnumDescriptor_New(enum_type);
+    return PyEnumDescriptor_FromDescriptor(enum_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -728,7 +725,7 @@
 static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) {
   const Descriptor* message_type = _GetDescriptor(self)->message_type();
   if (message_type) {
-    return PyMessageDescriptor_New(message_type);
+    return PyMessageDescriptor_FromDescriptor(message_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -743,7 +740,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -758,7 +755,7 @@
   const Descriptor* extension_scope =
       _GetDescriptor(self)->extension_scope();
   if (extension_scope) {
-    return PyMessageDescriptor_New(extension_scope);
+    return PyMessageDescriptor_FromDescriptor(extension_scope);
   } else {
     Py_RETURN_NONE;
   }
@@ -768,7 +765,7 @@
   const OneofDescriptor* containing_oneof =
       _GetDescriptor(self)->containing_oneof();
   if (containing_oneof) {
-    return PyOneofDescriptor_New(containing_oneof);
+    return PyOneofDescriptor_FromDescriptor(containing_oneof);
   } else {
     Py_RETURN_NONE;
   }
@@ -803,26 +800,30 @@
 
 
 static PyGetSetDef Getters[] = {
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("name"), (getter)GetName, NULL, "Unqualified name", NULL},
-  { C("type"), (getter)GetType, NULL, "C++ Type", NULL},
-  { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL},
-  { C("label"), (getter)GetLabel, NULL, "Label", NULL},
-  { C("number"), (getter)GetNumber, NULL, "Number", NULL},
-  { C("index"), (getter)GetIndex, NULL, "Index", NULL},
-  { C("default_value"), (getter)GetDefaultValue, NULL, "Default Value", NULL},
-  { C("has_default_value"), (getter)HasDefaultValue, NULL, NULL, NULL},
-  { C("is_extension"), (getter)IsExtension, NULL, "ID", NULL},
-  { C("id"), (getter)GetID, NULL, "ID", NULL},
-  { C("_cdescriptor"), (getter)GetCDescriptor, NULL, "HAACK REMOVE ME", NULL},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "name", (getter)GetName, NULL, "Unqualified name"},
+  { "type", (getter)GetType, NULL, "C++ Type"},
+  { "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
+  { "label", (getter)GetLabel, NULL, "Label"},
+  { "number", (getter)GetNumber, NULL, "Number"},
+  { "index", (getter)GetIndex, NULL, "Index"},
+  { "default_value", (getter)GetDefaultValue, NULL, "Default Value"},
+  { "has_default_value", (getter)HasDefaultValue},
+  { "is_extension", (getter)IsExtension, NULL, "ID"},
+  { "id", (getter)GetID, NULL, "ID"},
+  { "_cdescriptor", (getter)GetCDescriptor, NULL, "HAACK REMOVE ME"},
 
-  { C("message_type"), (getter)GetMessageType, (setter)SetMessageType, "Message type", NULL},
-  { C("enum_type"), (getter)GetEnumType, (setter)SetEnumType, "Enum type", NULL},
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("extension_scope"), (getter)GetExtensionScope, (setter)NULL, "Extension scope", NULL},
-  { C("containing_oneof"), (getter)GetContainingOneof, (setter)SetContainingOneof, "Containing oneof", NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "message_type", (getter)GetMessageType, (setter)SetMessageType,
+    "Message type"},
+  { "enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "extension_scope", (getter)GetExtensionScope, (setter)NULL,
+    "Extension scope"},
+  { "containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof,
+    "Containing oneof"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   {NULL}
 };
 
@@ -835,8 +836,7 @@
 
 PyTypeObject PyFieldDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.FieldDescriptor"),        // tp_name
+  FULL_MODULE_NAME ".FieldDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -855,7 +855,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Field Descriptor"),              // tp_doc
+  "A Field Descriptor",                 // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -868,10 +868,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyFieldDescriptor_New(
+PyObject* PyFieldDescriptor_FromDescriptor(
     const FieldDescriptor* field_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyFieldDescriptor_Type, field_descriptor);
+      &PyFieldDescriptor_Type, field_descriptor, NULL);
 }
 
 const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) {
@@ -900,7 +900,7 @@
 }
 
 static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
-  return PyFileDescriptor_New(_GetDescriptor(self)->file());
+  return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file());
 }
 
 static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) {
@@ -919,7 +919,7 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
@@ -964,16 +964,19 @@
 };
 
 static PyGetSetDef Getters[] = {
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("name"), (getter)GetName, NULL, "last name", NULL},
-  { C("file"), (getter)GetFile, NULL, "File descriptor", NULL},
-  { C("values"), (getter)GetEnumvaluesSeq, NULL, "values", NULL},
-  { C("values_by_name"), (getter)GetEnumvaluesByName, NULL, "Enumvalues by name", NULL},
-  { C("values_by_number"), (getter)GetEnumvaluesByNumber, NULL, "Enumvalues by number", NULL},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "name", (getter)GetName, NULL, "last name"},
+  { "file", (getter)GetFile, NULL, "File descriptor"},
+  { "values", (getter)GetEnumvaluesSeq, NULL, "values"},
+  { "values_by_name", (getter)GetEnumvaluesByName, NULL,
+    "Enum values by name"},
+  { "values_by_number", (getter)GetEnumvaluesByNumber, NULL,
+    "Enum values by number"},
 
-  { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL},
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "containing_type", (getter)GetContainingType, (setter)SetContainingType,
+    "Containing type"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   {NULL}
 };
 
@@ -981,9 +984,7 @@
 
 PyTypeObject PyEnumDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  C("google.protobuf.internal._message."
-    "EnumDescriptor"),                  // tp_name
+  FULL_MODULE_NAME ".EnumDescriptor",   // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1002,7 +1003,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Enum Descriptor"),               // tp_doc
+  "A Enum Descriptor",                  // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1015,10 +1016,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyEnumDescriptor_New(
+PyObject* PyEnumDescriptor_FromDescriptor(
     const EnumDescriptor* enum_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyEnumDescriptor_Type, enum_descriptor);
+      &PyEnumDescriptor_Type, enum_descriptor, NULL);
 }
 
 namespace enumvalue_descriptor {
@@ -1042,7 +1043,7 @@
 }
 
 static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
-  return PyEnumDescriptor_New(_GetDescriptor(self)->type());
+  return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type());
 }
 
 static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
@@ -1069,13 +1070,13 @@
 
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "name", NULL},
-  { C("number"), (getter)GetNumber, NULL, "number", NULL},
-  { C("index"), (getter)GetIndex, NULL, "index", NULL},
-  { C("type"), (getter)GetType, NULL, "index", NULL},
+  { "name", (getter)GetName, NULL, "name"},
+  { "number", (getter)GetNumber, NULL, "number"},
+  { "index", (getter)GetIndex, NULL, "index"},
+  { "type", (getter)GetType, NULL, "index"},
 
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   {NULL}
 };
 
@@ -1088,8 +1089,7 @@
 
 PyTypeObject PyEnumValueDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.EnumValueDescriptor"),    // tp_name
+  FULL_MODULE_NAME ".EnumValueDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1108,7 +1108,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A EnumValue Descriptor"),          // tp_doc
+  "A EnumValue Descriptor",             // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1121,10 +1121,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyEnumValueDescriptor_New(
+PyObject* PyEnumValueDescriptor_FromDescriptor(
     const EnumValueDescriptor* enumvalue_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyEnumValueDescriptor_Type, enumvalue_descriptor);
+      &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL);
 }
 
 namespace file_descriptor {
@@ -1218,18 +1218,20 @@
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "name", NULL},
-  { C("package"), (getter)GetPackage, NULL, "package", NULL},
-  { C("serialized_pb"), (getter)GetSerializedPb, NULL, NULL, NULL},
-  { C("message_types_by_name"), (getter)GetMessageTypesByName, NULL, "Messages by name", NULL},
-  { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enums by name", NULL},
-  { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL},
-  { C("dependencies"), (getter)GetDependencies, NULL, "Dependencies", NULL},
-  { C("public_dependencies"), (getter)GetPublicDependencies, NULL, "Dependencies", NULL},
+  { "name", (getter)GetName, NULL, "name"},
+  { "package", (getter)GetPackage, NULL, "package"},
+  { "serialized_pb", (getter)GetSerializedPb},
+  { "message_types_by_name", (getter)GetMessageTypesByName, NULL,
+    "Messages by name"},
+  { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"},
+  { "extensions_by_name", (getter)GetExtensionsByName, NULL,
+    "Extensions by name"},
+  { "dependencies", (getter)GetDependencies, NULL, "Dependencies"},
+  { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"},
 
-  { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL},
-  { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL},
-  { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
+  { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"},
   {NULL}
 };
 
@@ -1243,11 +1245,10 @@
 
 PyTypeObject PyFileDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.FileDescriptor"),         // tp_name
+  FULL_MODULE_NAME ".FileDescriptor",   // tp_name
   sizeof(PyFileDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
-  (destructor)file_descriptor::Dealloc, // tp_dealloc
+  (destructor)file_descriptor::Dealloc,  // tp_dealloc
   0,                                    // tp_print
   0,                                    // tp_getattr
   0,                                    // tp_setattr
@@ -1263,7 +1264,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A File Descriptor"),               // tp_doc
+  "A File Descriptor",                  // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1284,23 +1285,28 @@
   PyObject_Del,                         // tp_free
 };
 
-PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor) {
-  return descriptor::NewInternedDescriptor(
-      &PyFileDescriptor_Type, file_descriptor);
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor) {
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor,
+                                                         NULL);
 }
 
-PyObject* PyFileDescriptor_NewWithPb(
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
     const FileDescriptor* file_descriptor, PyObject *serialized_pb) {
-  PyObject* py_descriptor = PyFileDescriptor_New(file_descriptor);
+  bool was_created;
+  PyObject* py_descriptor = descriptor::NewInternedDescriptor(
+      &PyFileDescriptor_Type, file_descriptor, &was_created);
   if (py_descriptor == NULL) {
     return NULL;
   }
-  if (serialized_pb != NULL) {
+  if (was_created) {
     PyFileDescriptor* cfile_descriptor =
         reinterpret_cast<PyFileDescriptor*>(py_descriptor);
     Py_XINCREF(serialized_pb);
     cfile_descriptor->serialized_pb = serialized_pb;
   }
+  // TODO(amauryfa): In the case of a cached object, check that serialized_pb
+  // is the same as before.
 
   return py_descriptor;
 }
@@ -1333,19 +1339,19 @@
   const Descriptor* containing_type =
       _GetDescriptor(self)->containing_type();
   if (containing_type) {
-    return PyMessageDescriptor_New(containing_type);
+    return PyMessageDescriptor_FromDescriptor(containing_type);
   } else {
     Py_RETURN_NONE;
   }
 }
 
 static PyGetSetDef Getters[] = {
-  { C("name"), (getter)GetName, NULL, "Name", NULL},
-  { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL},
-  { C("index"), (getter)GetIndex, NULL, "Index", NULL},
+  { "name", (getter)GetName, NULL, "Name"},
+  { "full_name", (getter)GetFullName, NULL, "Full name"},
+  { "index", (getter)GetIndex, NULL, "Index"},
 
-  { C("containing_type"), (getter)GetContainingType, NULL, "Containing type", NULL},
-  { C("fields"), (getter)GetFields, NULL, "Fields", NULL},
+  { "containing_type", (getter)GetContainingType, NULL, "Containing type"},
+  { "fields", (getter)GetFields, NULL, "Fields"},
   {NULL}
 };
 
@@ -1353,8 +1359,7 @@
 
 PyTypeObject PyOneofDescriptor_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.OneofDescriptor"),        // tp_name
+  FULL_MODULE_NAME ".OneofDescriptor",  // tp_name
   sizeof(PyBaseDescriptor),             // tp_basicsize
   0,                                    // tp_itemsize
   0,                                    // tp_dealloc
@@ -1373,7 +1378,7 @@
   0,                                    // tp_setattro
   0,                                    // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                   // tp_flags
-  C("A Oneof Descriptor"),              // tp_doc
+  "A Oneof Descriptor",                 // tp_doc
   0,                                    // tp_traverse
   0,                                    // tp_clear
   0,                                    // tp_richcompare
@@ -1386,10 +1391,10 @@
   &descriptor::PyBaseDescriptor_Type,   // tp_base
 };
 
-PyObject* PyOneofDescriptor_New(
+PyObject* PyOneofDescriptor_FromDescriptor(
     const OneofDescriptor* oneof_descriptor) {
   return descriptor::NewInternedDescriptor(
-      &PyOneofDescriptor_Type, oneof_descriptor);
+      &PyOneofDescriptor_Type, oneof_descriptor, NULL);
 }
 
 // Add a enum values to a type dictionary.
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index ba6e729..b255040 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -48,21 +48,24 @@
 extern PyTypeObject PyFileDescriptor_Type;
 extern PyTypeObject PyOneofDescriptor_Type;
 
-// Return a new reference to a Descriptor object.
+// Wraps a Descriptor in a Python object.
 // The C++ pointer is usually borrowed from the global DescriptorPool.
 // In any case, it must stay alive as long as the Python object.
-PyObject* PyMessageDescriptor_New(const Descriptor* descriptor);
-PyObject* PyFieldDescriptor_New(const FieldDescriptor* descriptor);
-PyObject* PyEnumDescriptor_New(const EnumDescriptor* descriptor);
-PyObject* PyEnumValueDescriptor_New(const EnumValueDescriptor* descriptor);
-PyObject* PyOneofDescriptor_New(const OneofDescriptor* descriptor);
-PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor);
+// Returns a new reference.
+PyObject* PyMessageDescriptor_FromDescriptor(const Descriptor* descriptor);
+PyObject* PyFieldDescriptor_FromDescriptor(const FieldDescriptor* descriptor);
+PyObject* PyEnumDescriptor_FromDescriptor(const EnumDescriptor* descriptor);
+PyObject* PyEnumValueDescriptor_FromDescriptor(
+    const EnumValueDescriptor* descriptor);
+PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor);
+PyObject* PyFileDescriptor_FromDescriptor(
+    const FileDescriptor* file_descriptor);
 
 // Alternate constructor of PyFileDescriptor, used when we already have a
 // serialized FileDescriptorProto that can be cached.
 // Returns a new reference.
-PyObject* PyFileDescriptor_NewWithPb(const FileDescriptor* file_descriptor,
-                                     PyObject* serialized_pb);
+PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
+    const FileDescriptor* file_descriptor, PyObject* serialized_pb);
 
 // Return the C++ descriptor pointer.
 // This function checks the parameter type; on error, return NULL with a Python
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 06edebf..92e11e3 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -898,7 +898,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -956,7 +956,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_New(item);
+  return PyMessageDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1006,7 +1006,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_New(item);
+  return PyEnumDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1082,7 +1082,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_New(item);
+  return PyEnumValueDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1124,7 +1124,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1174,7 +1174,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyOneofDescriptor_New(item);
+  return PyOneofDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1238,7 +1238,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumValueDescriptor_New(item);
+  return PyEnumValueDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1302,7 +1302,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static int GetItemIndex(ItemDescriptor item) {
@@ -1354,7 +1354,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyMessageDescriptor_New(item);
+  return PyMessageDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1400,7 +1400,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyEnumDescriptor_New(item);
+  return PyEnumDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1446,7 +1446,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFieldDescriptor_New(item);
+  return PyFieldDescriptor_FromDescriptor(item);
 }
 
 static const string& GetItemName(ItemDescriptor item) {
@@ -1488,7 +1488,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_New(item);
+  return PyFileDescriptor_FromDescriptor(item);
 }
 
 static DescriptorContainerDef ContainerDef = {
@@ -1522,7 +1522,7 @@
 }
 
 static PyObject* NewObjectFromItem(ItemDescriptor item) {
-  return PyFileDescriptor_New(item);
+  return PyFileDescriptor_FromDescriptor(item);
 }
 
 static DescriptorContainerDef ContainerDef = {
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index d81537d..8fbdaff 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -28,6 +28,9 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
+
 // Mappings and Sequences of descriptors.
 // They implement containers like fields_by_name, EnumDescriptor.values...
 // See descriptor_containers.cc for more description.
@@ -92,4 +95,6 @@
 
 }  // namespace python
 }  // namespace protobuf
+
 }  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index bc3077b..ecd9084 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -35,10 +35,9 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
-#define C(str) const_cast<char*>(str)
-
 #if PY_MAJOR_VERSION >= 3
   #define PyString_FromStringAndSize PyUnicode_FromStringAndSize
   #if PY_VERSION_HEX < 0x03030000
@@ -108,11 +107,11 @@
       self->pool->FindMessageTypeByName(string(name, name_size));
 
   if (message_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find message %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name);
     return NULL;
   }
 
-  return PyMessageDescriptor_New(message_descriptor);
+  return PyMessageDescriptor_FromDescriptor(message_descriptor);
 }
 
 // Add a message class to our database.
@@ -158,6 +157,24 @@
   }
 }
 
+PyObject* FindFileByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const FileDescriptor* file_descriptor =
+      self->pool->FindFileByName(string(name, name_size));
+  if (file_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s",
+                 name);
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
 PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) {
   Py_ssize_t name_size;
   char* name;
@@ -168,12 +185,12 @@
   const FieldDescriptor* field_descriptor =
       self->pool->FindFieldByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s",
+    PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s",
                  name);
     return NULL;
   }
 
-  return PyFieldDescriptor_New(field_descriptor);
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
 }
 
 PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) {
@@ -186,11 +203,11 @@
   const FieldDescriptor* field_descriptor =
       self->pool->FindExtensionByName(string(name, name_size));
   if (field_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name);
     return NULL;
   }
 
-  return PyFieldDescriptor_New(field_descriptor);
+  return PyFieldDescriptor_FromDescriptor(field_descriptor);
 }
 
 PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) {
@@ -203,11 +220,11 @@
   const EnumDescriptor* enum_descriptor =
       self->pool->FindEnumTypeByName(string(name, name_size));
   if (enum_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find enum %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name);
     return NULL;
   }
 
-  return PyEnumDescriptor_New(enum_descriptor);
+  return PyEnumDescriptor_FromDescriptor(enum_descriptor);
 }
 
 PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
@@ -220,22 +237,106 @@
   const OneofDescriptor* oneof_descriptor =
       self->pool->FindOneofByName(string(name, name_size));
   if (oneof_descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError, "Couldn't find oneof %.200s", name);
+    PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name);
     return NULL;
   }
 
-  return PyOneofDescriptor_New(oneof_descriptor);
+  return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
+}
+
+// The code below loads new Descriptors from a serialized FileDescriptorProto.
+
+
+// Collects errors that occur during proto file building to allow them to be
+// propagated in the python exception instead of only living in ERROR logs.
+class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
+ public:
+  BuildFileErrorCollector() : error_message(""), had_errors(false) {}
+
+  void AddError(const string& filename, const string& element_name,
+                const Message* descriptor, ErrorLocation location,
+                const string& message) {
+    // Replicates the logging behavior that happens in the C++ implementation
+    // when an error collector is not passed in.
+    if (!had_errors) {
+      error_message +=
+          ("Invalid proto descriptor for file \"" + filename + "\":\n");
+      had_errors = true;
+    }
+    // As this only happens on failure and will result in the program not
+    // running at all, no effort is made to optimize this string manipulation.
+    error_message += ("  " + element_name + ": " + message + "\n");
+  }
+
+  string error_message;
+  bool had_errors;
+};
+
+PyObject* AddSerializedFile(PyDescriptorPool* self, PyObject* serialized_pb) {
+  char* message_type;
+  Py_ssize_t message_len;
+
+  if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
+    return NULL;
+  }
+
+  FileDescriptorProto file_proto;
+  if (!file_proto.ParseFromArray(message_type, message_len)) {
+    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
+    return NULL;
+  }
+
+  // If the file was already part of a C++ library, all its descriptors are in
+  // the underlying pool.  No need to do anything else.
+  const FileDescriptor* generated_file =
+      DescriptorPool::generated_pool()->FindFileByName(file_proto.name());
+  if (generated_file != NULL) {
+    return PyFileDescriptor_FromDescriptorWithSerializedPb(
+        generated_file, serialized_pb);
+  }
+
+  BuildFileErrorCollector error_collector;
+  const FileDescriptor* descriptor =
+      self->pool->BuildFileCollectingErrors(file_proto,
+                                            &error_collector);
+  if (descriptor == NULL) {
+    PyErr_Format(PyExc_TypeError,
+                 "Couldn't build proto file into descriptor pool!\n%s",
+                 error_collector.error_message.c_str());
+    return NULL;
+  }
+
+  return PyFileDescriptor_FromDescriptorWithSerializedPb(
+      descriptor, serialized_pb);
+}
+
+PyObject* Add(PyDescriptorPool* self, PyObject* file_descriptor_proto) {
+  ScopedPyObjectPtr serialized_pb(
+      PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL));
+  if (serialized_pb == NULL) {
+    return NULL;
+  }
+  return AddSerializedFile(self, serialized_pb);
 }
 
 static PyMethodDef Methods[] = {
-  { C("FindFieldByName"),
-    (PyCFunction)FindFieldByName,
-    METH_O,
-    C("Searches for a field descriptor by full name.") },
-  { C("FindExtensionByName"),
-    (PyCFunction)FindExtensionByName,
-    METH_O,
-    C("Searches for extension descriptor by full name.") },
+  { "Add", (PyCFunction)Add, METH_O,
+    "Adds the FileDescriptorProto and its types to this pool." },
+  { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O,
+    "Adds a serialized FileDescriptorProto to this pool." },
+
+  { "FindFileByName", (PyCFunction)FindFileByName, METH_O,
+    "Searches for a file descriptor by its .proto name." },
+  { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O,
+    "Searches for a message descriptor by full name." },
+  { "FindFieldByName", (PyCFunction)FindFieldByName, METH_O,
+    "Searches for a field descriptor by full name." },
+  { "FindExtensionByName", (PyCFunction)FindExtensionByName, METH_O,
+    "Searches for extension descriptor by full name." },
+  { "FindEnumTypeByName", (PyCFunction)FindEnumTypeByName, METH_O,
+    "Searches for enum type descriptor by full name." },
+  { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
+    "Searches for oneof descriptor by full name." },
   {NULL}
 };
 
@@ -243,8 +344,7 @@
 
 PyTypeObject PyDescriptorPool_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  C("google.protobuf.internal."
-    "_message.DescriptorPool"),        // tp_name
+  FULL_MODULE_NAME ".DescriptorPool",  // tp_name
   sizeof(PyDescriptorPool),            // tp_basicsize
   0,                                   // tp_itemsize
   (destructor)cdescriptor_pool::Dealloc,  // tp_dealloc
@@ -263,7 +363,7 @@
   0,                                   // tp_setattro
   0,                                   // tp_as_buffer
   Py_TPFLAGS_DEFAULT,                  // tp_flags
-  C("A Descriptor Pool"),              // tp_doc
+  "A Descriptor Pool",                 // tp_doc
   0,                                   // tp_traverse
   0,                                   // tp_clear
   0,                                   // tp_richcompare
@@ -284,69 +384,6 @@
   PyObject_Del,                        // tp_free
 };
 
-// The code below loads new Descriptors from a serialized FileDescriptorProto.
-
-
-// Collects errors that occur during proto file building to allow them to be
-// propagated in the python exception instead of only living in ERROR logs.
-class BuildFileErrorCollector : public DescriptorPool::ErrorCollector {
- public:
-  BuildFileErrorCollector() : error_message(""), had_errors(false) {}
-
-  void AddError(const string& filename, const string& element_name,
-                const Message* descriptor, ErrorLocation location,
-                const string& message) {
-    // Replicates the logging behavior that happens in the C++ implementation
-    // when an error collector is not passed in.
-    if (!had_errors) {
-      error_message +=
-          ("Invalid proto descriptor for file \"" + filename + "\":\n");
-    }
-    // As this only happens on failure and will result in the program not
-    // running at all, no effort is made to optimize this string manipulation.
-    error_message += ("  " + element_name + ": " + message + "\n");
-  }
-
-  string error_message;
-  bool had_errors;
-};
-
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) {
-  char* message_type;
-  Py_ssize_t message_len;
-
-  if (PyBytes_AsStringAndSize(serialized_pb, &message_type, &message_len) < 0) {
-    return NULL;
-  }
-
-  FileDescriptorProto file_proto;
-  if (!file_proto.ParseFromArray(message_type, message_len)) {
-    PyErr_SetString(PyExc_TypeError, "Couldn't parse file content!");
-    return NULL;
-  }
-
-  // If the file was already part of a C++ library, all its descriptors are in
-  // the underlying pool.  No need to do anything else.
-  const FileDescriptor* generated_file =
-      DescriptorPool::generated_pool()->FindFileByName(file_proto.name());
-  if (generated_file != NULL) {
-    return PyFileDescriptor_NewWithPb(generated_file, serialized_pb);
-  }
-
-  BuildFileErrorCollector error_collector;
-  const FileDescriptor* descriptor =
-      GetDescriptorPool()->pool->BuildFileCollectingErrors(file_proto,
-                                                           &error_collector);
-  if (descriptor == NULL) {
-    PyErr_Format(PyExc_TypeError,
-                 "Couldn't build proto file into descriptor pool!\n%s",
-                 error_collector.error_message.c_str());
-    return NULL;
-  }
-
-  return PyFileDescriptor_NewWithPb(descriptor, serialized_pb);
-}
-
 static PyDescriptorPool* global_cdescriptor_pool = NULL;
 
 bool InitDescriptorPool() {
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 4e494b8..efb1abe 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -95,6 +95,8 @@
 const Descriptor* RegisterMessageClass(
     PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor);
 
+// The function below are also exposed as methods of the DescriptorPool type.
+
 // Retrieves the Python class registered with the given message descriptor.
 //
 // Returns a *borrowed* reference if found, otherwise returns NULL with an
@@ -134,12 +136,8 @@
 
 }  // namespace cdescriptor_pool
 
-// Implement the Python "_BuildFile" method, it takes a serialized
-// FileDescriptorProto, and adds it to the C++ DescriptorPool.
-// It returns a new FileDescriptor object, or NULL when an exception is raised.
-PyObject* Python_BuildFile(PyObject* ignored, PyObject* args);
-
 // Retrieve the global descriptor pool owned by the _message module.
+// Returns a *borrowed* reference.
 PyDescriptorPool* GetDescriptorPool();
 
 // Initialize objects used by this module.
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index 8e38fc4..b8d18f8 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -51,16 +51,6 @@
 
 namespace extension_dict {
 
-// TODO(tibell): Always use self->message for clarity, just like in
-// RepeatedCompositeContainer.
-static Message* GetMessage(ExtensionDict* self) {
-  if (self->parent != NULL) {
-    return self->parent->message;
-  } else {
-    return self->message;
-  }
-}
-
 PyObject* len(ExtensionDict* self) {
 #if PY_MAJOR_VERSION >= 3
   return PyLong_FromLong(PyDict_Size(self->values));
@@ -89,7 +79,7 @@
     }
   } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     if (cmessage::ReleaseSubMessage(
-            GetMessage(self), descriptor,
+            self->parent, descriptor,
             reinterpret_cast<CMessage*>(extension)) < 0) {
       return -1;
     }
@@ -109,7 +99,7 @@
 
   if (descriptor->label() != FieldDescriptor::LABEL_REPEATED &&
       descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
-    return cmessage::InternalGetScalar(self->parent, descriptor);
+    return cmessage::InternalGetScalar(self->parent->message, descriptor);
   }
 
   PyObject* value = PyDict_GetItem(self->values, key);
@@ -266,8 +256,7 @@
 
 PyTypeObject ExtensionDict_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  "google.protobuf.internal."
-  "cpp._message.ExtensionDict",        // tp_name
+  FULL_MODULE_NAME ".ExtensionDict",   // tp_name
   sizeof(ExtensionDict),               // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)extension_dict::dealloc,  //  tp_dealloc
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index a2b357b..a4843e8 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -59,6 +59,8 @@
 #include <google/protobuf/pyext/extension_dict.h>
 #include <google/protobuf/pyext/repeated_composite_container.h>
 #include <google/protobuf/pyext/repeated_scalar_container.h>
+#include <google/protobuf/pyext/message_map_container.h>
+#include <google/protobuf/pyext/scalar_map_container.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/stubs/strutil.h>
 
@@ -93,9 +95,9 @@
 static const Descriptor* GetMessageDescriptor(PyTypeObject* cls);
 static string GetMessageName(CMessage* self);
 int InternalReleaseFieldByDescriptor(
+    CMessage* self,
     const FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    Message* parent_message);
+    PyObject* composite_field);
 }  // namespace cmessage
 
 // ---------------------------------------------------------------------
@@ -127,10 +129,29 @@
                                Visitor visitor) {
   if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      RepeatedCompositeContainer* container =
-        reinterpret_cast<RepeatedCompositeContainer*>(child);
-      if (visitor.VisitRepeatedCompositeContainer(container) == -1)
-        return -1;
+      if (descriptor->is_map()) {
+        const Descriptor* entry_type = descriptor->message_type();
+        const FieldDescriptor* value_type =
+            entry_type->FindFieldByName("value");
+        if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+          MessageMapContainer* container =
+            reinterpret_cast<MessageMapContainer*>(child);
+          if (visitor.VisitMessageMapContainer(container) == -1) {
+            return -1;
+          }
+        } else {
+          ScalarMapContainer* container =
+            reinterpret_cast<ScalarMapContainer*>(child);
+          if (visitor.VisitScalarMapContainer(container) == -1) {
+            return -1;
+          }
+        }
+      } else {
+        RepeatedCompositeContainer* container =
+          reinterpret_cast<RepeatedCompositeContainer*>(child);
+        if (visitor.VisitRepeatedCompositeContainer(container) == -1)
+          return -1;
+      }
     } else {
       RepeatedScalarContainer* container =
         reinterpret_cast<RepeatedScalarContainer*>(child);
@@ -444,7 +465,7 @@
   }
 
   if (InternalReleaseFieldByDescriptor(
-          existing_field, child_message, message) < 0) {
+          cmessage, existing_field, child_message) < 0) {
     return -1;
   }
   return PyDict_DelItemString(cmessage->composite_fields, field_name);
@@ -483,6 +504,16 @@
     return 0;
   }
 
+  int VisitScalarMapContainer(ScalarMapContainer* container) {
+    container->message = message_;
+    return 0;
+  }
+
+  int VisitMessageMapContainer(MessageMapContainer* container) {
+    container->message = message_;
+    return 0;
+  }
+
  private:
   Message* message_;
 };
@@ -500,6 +531,9 @@
         self->message->GetDescriptor());
     self->message = prototype->New();
     self->owner.reset(self->message);
+    // Cascade the new owner to eventual children: even if this message is
+    // empty, some submessages or repeated containers might exist already.
+    SetOwner(self, self->owner);
   } else {
     // Otherwise, we need a mutable child message.
     if (AssureWritable(self->parent) == -1)
@@ -520,8 +554,9 @@
   // When a CMessage is made writable its Message pointer is updated
   // to point to a new mutable Message.  When that happens we need to
   // update any references to the old, read-only CMessage.  There are
-  // three places such references occur: RepeatedScalarContainer,
-  // RepeatedCompositeContainer, and ExtensionDict.
+  // five places such references occur: RepeatedScalarContainer,
+  // RepeatedCompositeContainer, ScalarMapContainer, MessageMapContainer,
+  // and ExtensionDict.
   if (self->extensions != NULL)
     self->extensions->message = self->message;
   if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1)
@@ -583,15 +618,43 @@
   return PyFieldDescriptor_AsDescriptor(extension);
 }
 
+// If value is a string, convert it into an enum value based on the labels in
+// descriptor, otherwise simply return value.  Always returns a new reference.
+static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor,
+                                     PyObject* value) {
+  if (PyString_Check(value) || PyUnicode_Check(value)) {
+    const EnumDescriptor* enum_descriptor = descriptor.enum_type();
+    if (enum_descriptor == NULL) {
+      PyErr_SetString(PyExc_TypeError, "not an enum field");
+      return NULL;
+    }
+    char* enum_label;
+    Py_ssize_t size;
+    if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) {
+      return NULL;
+    }
+    const EnumValueDescriptor* enum_value_descriptor =
+        enum_descriptor->FindValueByName(string(enum_label, size));
+    if (enum_value_descriptor == NULL) {
+      PyErr_SetString(PyExc_ValueError, "unknown enum label");
+      return NULL;
+    }
+    return PyInt_FromLong(enum_value_descriptor->number());
+  }
+  Py_INCREF(value);
+  return value;
+}
+
 // If cmessage_list is not NULL, this function releases values into the
 // container CMessages instead of just removing. Repeated composite container
 // needs to do this to make sure CMessages stay alive if they're still
 // referenced after deletion. Repeated scalar container doesn't need to worry.
 int InternalDeleteRepeatedField(
-    Message* message,
+    CMessage* self,
     const FieldDescriptor* field_descriptor,
     PyObject* slice,
     PyObject* cmessage_list) {
+  Message* message = self->message;
   Py_ssize_t length, from, to, step, slice_length;
   const Reflection* reflection = message->GetReflection();
   int min, max;
@@ -665,7 +728,7 @@
       CMessage* last_cmessage = reinterpret_cast<CMessage*>(
           PyList_GET_ITEM(cmessage_list, PyList_GET_SIZE(cmessage_list) - 1));
       repeated_composite_container::ReleaseLastTo(
-          field_descriptor, message, last_cmessage);
+          self, field_descriptor, last_cmessage);
       if (PySequence_DelItem(cmessage_list, -1) < 0) {
         return -1;
       }
@@ -696,16 +759,90 @@
                    PyString_AsString(name));
       return -1;
     }
-    if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
+    if (descriptor->is_map()) {
+      ScopedPyObjectPtr map(GetAttr(self, name));
+      const FieldDescriptor* value_descriptor =
+          descriptor->message_type()->FindFieldByName("value");
+      if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        Py_ssize_t map_pos = 0;
+        PyObject* map_key;
+        PyObject* map_value;
+        while (PyDict_Next(value, &map_pos, &map_key, &map_value)) {
+          ScopedPyObjectPtr function_return;
+          function_return.reset(PyObject_GetItem(map.get(), map_key));
+          if (function_return.get() == NULL) {
+            return -1;
+          }
+          ScopedPyObjectPtr ok(PyObject_CallMethod(
+              function_return.get(), "MergeFrom", "O", map_value));
+          if (ok.get() == NULL) {
+            return -1;
+          }
+        }
+      } else {
+        ScopedPyObjectPtr function_return;
+        function_return.reset(
+            PyObject_CallMethod(map.get(), "update", "O", value));
+        if (function_return.get() == NULL) {
+          return -1;
+        }
+      }
+    } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
       ScopedPyObjectPtr container(GetAttr(self, name));
       if (container == NULL) {
         return -1;
       }
       if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-        if (repeated_composite_container::Extend(
-                reinterpret_cast<RepeatedCompositeContainer*>(container.get()),
-                value)
-            == NULL) {
+        RepeatedCompositeContainer* rc_container =
+            reinterpret_cast<RepeatedCompositeContainer*>(container.get());
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == NULL) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter))) != NULL) {
+          PyObject* kwargs = (PyDict_Check(next) ? next.get() : NULL);
+          ScopedPyObjectPtr new_msg(
+              repeated_composite_container::Add(rc_container, NULL, kwargs));
+          if (new_msg == NULL) {
+            return -1;
+          }
+          if (kwargs == NULL) {
+            // next was not a dict, it's a message we need to merge
+            ScopedPyObjectPtr merged(
+                MergeFrom(reinterpret_cast<CMessage*>(new_msg.get()), next));
+            if (merged == NULL) {
+              return -1;
+            }
+          }
+        }
+        if (PyErr_Occurred()) {
+          // Check to see how PyIter_Next() exited.
+          return -1;
+        }
+      } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        RepeatedScalarContainer* rs_container =
+            reinterpret_cast<RepeatedScalarContainer*>(container.get());
+        ScopedPyObjectPtr iter(PyObject_GetIter(value));
+        if (iter == NULL) {
+          PyErr_SetString(PyExc_TypeError, "Value must be iterable");
+          return -1;
+        }
+        ScopedPyObjectPtr next;
+        while ((next.reset(PyIter_Next(iter))) != NULL) {
+          ScopedPyObjectPtr enum_value(GetIntegerEnumValue(*descriptor, next));
+          if (enum_value == NULL) {
+            return -1;
+          }
+          ScopedPyObjectPtr new_msg(
+              repeated_scalar_container::Append(rs_container, enum_value));
+          if (new_msg == NULL) {
+            return -1;
+          }
+        }
+        if (PyErr_Occurred()) {
+          // Check to see how PyIter_Next() exited.
           return -1;
         }
       } else {
@@ -721,12 +858,26 @@
       if (message == NULL) {
         return -1;
       }
-      if (MergeFrom(reinterpret_cast<CMessage*>(message.get()),
-                             value) == NULL) {
-        return -1;
+      CMessage* cmessage = reinterpret_cast<CMessage*>(message.get());
+      if (PyDict_Check(value)) {
+        if (InitAttributes(cmessage, value) < 0) {
+          return -1;
+        }
+      } else {
+        ScopedPyObjectPtr merged(MergeFrom(cmessage, value));
+        if (merged == NULL) {
+          return -1;
+        }
       }
     } else {
-      if (SetAttr(self, name, value) < 0) {
+      ScopedPyObjectPtr new_val;
+      if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+        new_val.reset(GetIntegerEnumValue(*descriptor, value));
+        if (new_val == NULL) {
+          return -1;
+        }
+      }
+      if (SetAttr(self, name, (new_val == NULL) ? value : new_val) < 0) {
         return -1;
       }
     }
@@ -789,7 +940,6 @@
   }
   self->message = default_message->New();
   self->owner.reset(self->message);
-
   return reinterpret_cast<PyObject*>(self);
 }
 
@@ -830,6 +980,16 @@
     return 0;
   }
 
+  int VisitScalarMapContainer(ScalarMapContainer* container) {
+    container->parent = NULL;
+    return 0;
+  }
+
+  int VisitMessageMapContainer(MessageMapContainer* container) {
+    container->parent = NULL;
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
     cmessage->parent = NULL;
@@ -1064,6 +1224,16 @@
     return 0;
   }
 
+  int VisitScalarMapContainer(ScalarMapContainer* container) {
+    scalar_map_container::SetOwner(container, new_owner_);
+    return 0;
+  }
+
+  int VisitMessageMapContainer(MessageMapContainer* container) {
+    message_map_container::SetOwner(container, new_owner_);
+    return 0;
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
     return SetOwner(cmessage, new_owner_);
@@ -1084,11 +1254,11 @@
 // Releases the message specified by 'field' and returns the
 // pointer. If the field does not exist a new message is created using
 // 'descriptor'. The caller takes ownership of the returned pointer.
-Message* ReleaseMessage(Message* message,
+Message* ReleaseMessage(CMessage* self,
                         const Descriptor* descriptor,
                         const FieldDescriptor* field_descriptor) {
-  Message* released_message = message->GetReflection()->ReleaseMessage(
-      message, field_descriptor, message_factory);
+  Message* released_message = self->message->GetReflection()->ReleaseMessage(
+      self->message, field_descriptor, message_factory);
   // ReleaseMessage will return NULL which differs from
   // child_cmessage->message, if the field does not exist.  In this case,
   // the latter points to the default instance via a const_cast<>, so we
@@ -1102,12 +1272,12 @@
   return released_message;
 }
 
-int ReleaseSubMessage(Message* message,
+int ReleaseSubMessage(CMessage* self,
                       const FieldDescriptor* field_descriptor,
                       CMessage* child_cmessage) {
   // Release the Message
   shared_ptr<Message> released_message(ReleaseMessage(
-      message, child_cmessage->message->GetDescriptor(), field_descriptor));
+      self, child_cmessage->message->GetDescriptor(), field_descriptor));
   child_cmessage->message = released_message.get();
   child_cmessage->owner.swap(released_message);
   child_cmessage->parent = NULL;
@@ -1119,8 +1289,8 @@
 
 struct ReleaseChild : public ChildVisitor {
   // message must outlive this object.
-  explicit ReleaseChild(Message* parent_message) :
-      parent_message_(parent_message) {}
+  explicit ReleaseChild(CMessage* parent) :
+      parent_(parent) {}
 
   int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
     return repeated_composite_container::Release(
@@ -1132,23 +1302,33 @@
         reinterpret_cast<RepeatedScalarContainer*>(container));
   }
 
+  int VisitScalarMapContainer(ScalarMapContainer* container) {
+    return scalar_map_container::Release(
+        reinterpret_cast<ScalarMapContainer*>(container));
+  }
+
+  int VisitMessageMapContainer(MessageMapContainer* container) {
+    return message_map_container::Release(
+        reinterpret_cast<MessageMapContainer*>(container));
+  }
+
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
-    return ReleaseSubMessage(parent_message_, field_descriptor,
+    return ReleaseSubMessage(parent_, field_descriptor,
         reinterpret_cast<CMessage*>(cmessage));
   }
 
-  Message* parent_message_;
+  CMessage* parent_;
 };
 
 int InternalReleaseFieldByDescriptor(
+    CMessage* self,
     const FieldDescriptor* field_descriptor,
-    PyObject* composite_field,
-    Message* parent_message) {
+    PyObject* composite_field) {
   return VisitCompositeField(
       field_descriptor,
       composite_field,
-      ReleaseChild(parent_message));
+      ReleaseChild(self));
 }
 
 PyObject* ClearFieldByDescriptor(
@@ -1200,8 +1380,8 @@
   // Only release the field if there's a possibility that there are
   // references to it.
   if (composite_field != NULL) {
-    if (InternalReleaseFieldByDescriptor(field_descriptor,
-                                         composite_field, message) < 0) {
+    if (InternalReleaseFieldByDescriptor(self, field_descriptor,
+                                         composite_field) < 0) {
       return NULL;
     }
     PyDict_DelItem(self->composite_fields, arg);
@@ -1219,7 +1399,7 @@
 
 PyObject* Clear(CMessage* self) {
   AssureWritable(self);
-  if (ForEachCompositeField(self, ReleaseChild(self->message)) == -1)
+  if (ForEachCompositeField(self, ReleaseChild(self)) == -1)
     return NULL;
 
   // The old ExtensionDict still aliases this CMessage, but all its
@@ -1582,7 +1762,8 @@
     }
 
     if (fields[i]->is_extension()) {
-      ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(fields[i]));
+      ScopedPyObjectPtr extension_field(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (extension_field == NULL) {
         return NULL;
       }
@@ -1616,7 +1797,8 @@
         PyErr_SetString(PyExc_ValueError, "bad string");
         return NULL;
       }
-      ScopedPyObjectPtr field_descriptor(PyFieldDescriptor_New(fields[i]));
+      ScopedPyObjectPtr field_descriptor(
+          PyFieldDescriptor_FromDescriptor(fields[i]));
       if (field_descriptor == NULL) {
         return NULL;
       }
@@ -1683,10 +1865,8 @@
   }
 }
 
-PyObject* InternalGetScalar(
-    CMessage* self,
-    const FieldDescriptor* field_descriptor) {
-  Message* message = self->message;
+PyObject* InternalGetScalar(const Message* message,
+                            const FieldDescriptor* field_descriptor) {
   const Reflection* reflection = message->GetReflection();
 
   if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
@@ -1739,12 +1919,12 @@
       if (!message->GetReflection()->SupportsUnknownEnumValues() &&
           !message->GetReflection()->HasField(*message, field_descriptor)) {
         // Look for the value in the unknown fields.
-        UnknownFieldSet* unknown_field_set =
-            message->GetReflection()->MutableUnknownFields(message);
-        for (int i = 0; i < unknown_field_set->field_count(); ++i) {
-          if (unknown_field_set->field(i).number() ==
+        const UnknownFieldSet& unknown_field_set =
+            message->GetReflection()->GetUnknownFields(*message);
+        for (int i = 0; i < unknown_field_set.field_count(); ++i) {
+          if (unknown_field_set.field(i).number() ==
               field_descriptor->number()) {
-            result = PyInt_FromLong(unknown_field_set->field(i).varint());
+            result = PyInt_FromLong(unknown_field_set.field(i).varint());
             break;
           }
         }
@@ -1793,21 +1973,16 @@
   return reinterpret_cast<PyObject*>(cmsg);
 }
 
-int InternalSetScalar(
-    CMessage* self,
+int InternalSetNonOneofScalar(
+    Message* message,
     const FieldDescriptor* field_descriptor,
     PyObject* arg) {
-  Message* message = self->message;
   const Reflection* reflection = message->GetReflection();
 
   if (!CheckFieldBelongsToMessage(field_descriptor, message)) {
     return -1;
   }
 
-  if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
-    return -1;
-  }
-
   switch (field_descriptor->cpp_type()) {
     case FieldDescriptor::CPPTYPE_INT32: {
       GOOGLE_CHECK_GET_INT32(arg, value, -1);
@@ -1878,6 +2053,21 @@
   return 0;
 }
 
+int InternalSetScalar(
+    CMessage* self,
+    const FieldDescriptor* field_descriptor,
+    PyObject* arg) {
+  if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) {
+    return -1;
+  }
+
+  if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) {
+    return -1;
+  }
+
+  return InternalSetNonOneofScalar(self->message, field_descriptor, arg);
+}
+
 PyObject* FromString(PyTypeObject* cls, PyObject* serialized) {
   PyObject* py_cmsg = PyObject_CallObject(
       reinterpret_cast<PyObject*>(cls), NULL);
@@ -1955,7 +2145,8 @@
   // which was built previously.
   for (int i = 0; i < message_descriptor->enum_type_count(); ++i) {
     const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i);
-    ScopedPyObjectPtr enum_type(PyEnumDescriptor_New(enum_descriptor));
+    ScopedPyObjectPtr enum_type(
+        PyEnumDescriptor_FromDescriptor(enum_descriptor));
     if (enum_type == NULL) {
       return NULL;
      }
@@ -1993,7 +2184,7 @@
   // which was defined previously.
   for (int i = 0; i < message_descriptor->extension_count(); ++i) {
     const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i);
-    ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(field));
+    ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field));
     if (extension_field == NULL) {
       return NULL;
     }
@@ -2097,26 +2288,6 @@
 }
 
 // CMessage static methods:
-PyObject* _GetMessageDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindMessageByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetFieldDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindFieldByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetExtensionDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindExtensionByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetEnumDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindEnumTypeByName(GetDescriptorPool(), arg);
-}
-
-PyObject* _GetOneofDescriptor(PyObject* unused, PyObject* arg) {
-  return cdescriptor_pool::FindOneofByName(GetDescriptorPool(), arg);
-}
-
 PyObject* _CheckCalledFromGeneratedFile(PyObject* unused,
                                         PyObject* unused_arg) {
   if (!_CalledFromGeneratedFile(1)) {
@@ -2188,21 +2359,6 @@
     "or None if no field is set." },
 
   // Static Methods.
-  { "_BuildFile", (PyCFunction)Python_BuildFile, METH_O | METH_STATIC,
-    "Registers a new protocol buffer file in the global C++ descriptor pool." },
-  { "_GetMessageDescriptor", (PyCFunction)_GetMessageDescriptor,
-    METH_O | METH_STATIC, "Finds a message descriptor in the message pool." },
-  { "_GetFieldDescriptor", (PyCFunction)_GetFieldDescriptor,
-    METH_O | METH_STATIC, "Finds a field descriptor in the message pool." },
-  { "_GetExtensionDescriptor", (PyCFunction)_GetExtensionDescriptor,
-    METH_O | METH_STATIC,
-    "Finds a extension descriptor in the message pool." },
-  { "_GetEnumDescriptor", (PyCFunction)_GetEnumDescriptor,
-    METH_O | METH_STATIC,
-    "Finds an enum descriptor in the message pool." },
-  { "_GetOneofDescriptor", (PyCFunction)_GetOneofDescriptor,
-    METH_O | METH_STATIC,
-    "Finds an oneof descriptor in the message pool." },
   { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile,
     METH_NOARGS | METH_STATIC,
     "Raises TypeError if the caller is not in a _pb2.py file."},
@@ -2234,6 +2390,31 @@
         reinterpret_cast<PyObject*>(self), name);
   }
 
+  if (field_descriptor->is_map()) {
+    PyObject* py_container = NULL;
+    const Descriptor* entry_type = field_descriptor->message_type();
+    const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
+    if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      PyObject* value_class = cdescriptor_pool::GetMessageClass(
+          GetDescriptorPool(), value_type->message_type());
+      if (value_class == NULL) {
+        return NULL;
+      }
+      py_container = message_map_container::NewContainer(self, field_descriptor,
+                                                         value_class);
+    } else {
+      py_container = scalar_map_container::NewContainer(self, field_descriptor);
+    }
+    if (py_container == NULL) {
+      return NULL;
+    }
+    if (!SetCompositeField(self, name, py_container)) {
+      Py_DECREF(py_container);
+      return NULL;
+    }
+    return py_container;
+  }
+
   if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
     PyObject* py_container = NULL;
     if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -2267,7 +2448,7 @@
     return sub_message;
   }
 
-  return InternalGetScalar(self, field_descriptor);
+  return InternalGetScalar(self->message, field_descriptor);
 }
 
 int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
@@ -2304,9 +2485,7 @@
 
 PyTypeObject CMessage_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "CMessage",                          // tp_name
+  FULL_MODULE_NAME ".CMessage",        // tp_name
   sizeof(CMessage),                    // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)cmessage::Dealloc,       //  tp_dealloc
@@ -2401,7 +2580,7 @@
   k_extensions_by_name = PyString_FromString("_extensions_by_name");
   k_extensions_by_number = PyString_FromString("_extensions_by_number");
 
-  message_factory = new DynamicMessageFactory(GetDescriptorPool()->pool);
+  message_factory = new DynamicMessageFactory();
   message_factory->SetDelegateToGeneratedFactory(true);
 }
 
@@ -2469,6 +2648,61 @@
       reinterpret_cast<PyObject*>(
           &RepeatedCompositeContainer_Type));
 
+  // ScalarMapContainer_Type derives from our MutableMapping type.
+  PyObject* containers =
+      PyImport_ImportModule("google.protobuf.internal.containers");
+  if (containers == NULL) {
+    return false;
+  }
+
+  PyObject* mutable_mapping =
+      PyObject_GetAttrString(containers, "MutableMapping");
+  Py_DECREF(containers);
+
+  if (mutable_mapping == NULL) {
+    return false;
+  }
+
+  if (!PyObject_TypeCheck(mutable_mapping, &PyType_Type)) {
+    Py_DECREF(mutable_mapping);
+    return false;
+  }
+
+  ScalarMapContainer_Type.tp_base =
+      reinterpret_cast<PyTypeObject*>(mutable_mapping);
+
+  if (PyType_Ready(&ScalarMapContainer_Type) < 0) {
+    return false;
+  }
+
+  PyModule_AddObject(m, "ScalarMapContainer",
+                     reinterpret_cast<PyObject*>(&ScalarMapContainer_Type));
+
+  if (PyType_Ready(&ScalarMapIterator_Type) < 0) {
+    return false;
+  }
+
+  PyModule_AddObject(m, "ScalarMapIterator",
+                     reinterpret_cast<PyObject*>(&ScalarMapIterator_Type));
+
+  Py_INCREF(mutable_mapping);
+  MessageMapContainer_Type.tp_base =
+      reinterpret_cast<PyTypeObject*>(mutable_mapping);
+
+  if (PyType_Ready(&MessageMapContainer_Type) < 0) {
+    return false;
+  }
+
+  PyModule_AddObject(m, "MessageMapContainer",
+                     reinterpret_cast<PyObject*>(&MessageMapContainer_Type));
+
+  if (PyType_Ready(&MessageMapIterator_Type) < 0) {
+    return false;
+  }
+
+  PyModule_AddObject(m, "MessageMapIterator",
+                     reinterpret_cast<PyObject*>(&MessageMapIterator_Type));
+
   ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented;
   if (PyType_Ready(&ExtensionDict_Type) < 0) {
     return false;
@@ -2478,6 +2712,12 @@
       m, "ExtensionDict",
       reinterpret_cast<PyObject*>(&ExtensionDict_Type));
 
+  // Expose the DescriptorPool used to hold all descriptors added from generated
+  // pb2.py files.
+  Py_INCREF(GetDescriptorPool());  // PyModule_AddObject steals a reference.
+  PyModule_AddObject(
+      m, "default_pool", reinterpret_cast<PyObject*>(GetDescriptorPool()));
+
   // This implementation provides full Descriptor types, we advertise it so that
   // descriptor.py can use them in replacement of the Python classes.
   PyModule_AddIntConstant(m, "_USE_C_DESCRIPTORS", 1);
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 2f2da79..7360b20 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -120,7 +120,7 @@
 // A new message will be created if this is a read-only default instance.
 //
 // Corresponds to reflection api method ReleaseMessage.
-int ReleaseSubMessage(Message* message,
+int ReleaseSubMessage(CMessage* self,
                       const FieldDescriptor* field_descriptor,
                       CMessage* child_cmessage);
 
@@ -144,7 +144,7 @@
 // by slice will be removed from cmessage_list by this function.
 //
 // Corresponds to reflection api method RemoveLast.
-int InternalDeleteRepeatedField(Message* message,
+int InternalDeleteRepeatedField(CMessage* self,
                                 const FieldDescriptor* field_descriptor,
                                 PyObject* slice, PyObject* cmessage_list);
 
@@ -153,10 +153,15 @@
                       const FieldDescriptor* field_descriptor,
                       PyObject* value);
 
+// Sets the specified scalar value to the message.  Requires it is not a Oneof.
+int InternalSetNonOneofScalar(Message* message,
+                              const FieldDescriptor* field_descriptor,
+                              PyObject* arg);
+
 // Retrieves the specified scalar value from the message.
 //
 // Returns a new python reference.
-PyObject* InternalGetScalar(CMessage* self,
+PyObject* InternalGetScalar(const Message* message,
                             const FieldDescriptor* field_descriptor);
 
 // Clears the message, removing all contained data. Extension dictionary and
@@ -279,7 +284,7 @@
 extern PyObject* kint64max_py;
 extern PyObject* kuint64max_py;
 
-#define C(str) const_cast<char*>(str)
+#define FULL_MODULE_NAME "google.protobuf.pyext._message"
 
 void FormatTypeError(PyObject* arg, char* expected_types);
 template<class T>
diff --git a/python/google/protobuf/pyext/message_map_container.cc b/python/google/protobuf/pyext/message_map_container.cc
new file mode 100644
index 0000000..ab8d8fb
--- /dev/null
+++ b/python/google/protobuf/pyext/message_map_container.cc
@@ -0,0 +1,540 @@
+// 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.
+
+// Author: haberman@google.com (Josh Haberman)
+
+#include <google/protobuf/pyext/message_map_container.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct MessageMapIterator {
+  PyObject_HEAD;
+
+  // This dict contains the full contents of what we want to iterate over.
+  // There's no way to avoid building this, because the list representation
+  // (which is canonical) can contain duplicate keys.  So at the very least we
+  // need a set that lets us skip duplicate keys.  And at the point that we're
+  // doing that, we might as well just build the actual dict we're iterating
+  // over and use dict's built-in iterator.
+  PyObject* dict;
+
+  // An iterator on dict.
+  PyObject* iter;
+
+  // A pointer back to the container, so we can notice changes to the version.
+  MessageMapContainer* container;
+
+  // The version of the map when we took the iterator to it.
+  //
+  // We store this so that if the map is modified during iteration we can throw
+  // an error.
+  uint64 version;
+};
+
+static MessageMapIterator* GetIter(PyObject* obj) {
+  return reinterpret_cast<MessageMapIterator*>(obj);
+}
+
+namespace message_map_container {
+
+static MessageMapContainer* GetMap(PyObject* obj) {
+  return reinterpret_cast<MessageMapContainer*>(obj);
+}
+
+// The private constructor of MessageMapContainer objects.
+PyObject* NewContainer(CMessage* parent,
+                       const google::protobuf::FieldDescriptor* parent_field_descriptor,
+                       PyObject* concrete_class) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+  PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0);
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  MessageMapContainer* self = GetMap(obj);
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  self->message_dict = PyDict_New();
+  if (self->message_dict == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate message dict.");
+  }
+
+  Py_INCREF(concrete_class);
+  self->subclass_init = concrete_class;
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    Py_DECREF(obj);
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj;
+}
+
+// Initializes the underlying Message object of "to" so it becomes a new parent
+// repeated scalar, and copies all the values from "from" to it. A child scalar
+// container can be released by passing it as both from and to (e.g. making it
+// the recipient of the new parent message and copying the values from itself).
+static int InitializeAndCopyToParentContainer(
+    MessageMapContainer* from,
+    MessageMapContainer* to) {
+  // For now we require from == to, re-evaluate if we want to support deep copy
+  // as in repeated_composite_container.cc.
+  GOOGLE_DCHECK(from == to);
+  Message* old_message = from->message;
+  Message* new_message = old_message->New();
+  to->parent = NULL;
+  to->parent_field_descriptor = from->parent_field_descriptor;
+  to->message = new_message;
+  to->owner.reset(new_message);
+
+  vector<const FieldDescriptor*> fields;
+  fields.push_back(from->parent_field_descriptor);
+  old_message->GetReflection()->SwapFields(old_message, new_message, fields);
+  return 0;
+}
+
+static PyObject* GetCMessage(MessageMapContainer* self, Message* entry) {
+  // Get or create the CMessage object corresponding to this message.
+  Message* message = entry->GetReflection()->MutableMessage(
+      entry, self->value_field_descriptor);
+  ScopedPyObjectPtr key(PyLong_FromVoidPtr(message));
+  PyObject* ret = PyDict_GetItem(self->message_dict, key);
+
+  if (ret == NULL) {
+    CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init,
+                                               message->GetDescriptor());
+    ret = reinterpret_cast<PyObject*>(cmsg);
+
+    if (cmsg == NULL) {
+      return NULL;
+    }
+    cmsg->owner = self->owner;
+    cmsg->message = message;
+    cmsg->parent = self->parent;
+
+    if (PyDict_SetItem(self->message_dict, key, ret) < 0) {
+      Py_DECREF(ret);
+      return NULL;
+    }
+  } else {
+    Py_INCREF(ret);
+  }
+
+  return ret;
+}
+
+int Release(MessageMapContainer* self) {
+  InitializeAndCopyToParentContainer(self, self);
+  return 0;
+}
+
+void SetOwner(MessageMapContainer* self,
+              const shared_ptr<Message>& new_owner) {
+  self->owner = new_owner;
+}
+
+Py_ssize_t Length(PyObject* _self) {
+  MessageMapContainer* self = GetMap(_self);
+  google::protobuf::Message* message = self->message;
+  return message->GetReflection()->FieldSize(*message,
+                                             self->parent_field_descriptor);
+}
+
+int MapKeyMatches(MessageMapContainer* self, const Message* entry,
+                  PyObject* key) {
+  // TODO(haberman): do we need more strict type checking?
+  ScopedPyObjectPtr entry_key(
+      cmessage::InternalGetScalar(entry, self->key_field_descriptor));
+  int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ);
+  return ret;
+}
+
+int SetItem(PyObject *_self, PyObject *key, PyObject *v) {
+  if (v) {
+    PyErr_Format(PyExc_ValueError,
+                 "Direct assignment of submessage not allowed");
+    return -1;
+  }
+
+  // Now we know that this is a delete, not a set.
+
+  MessageMapContainer* self = GetMap(_self);
+  cmessage::AssureWritable(self->parent);
+
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.  We need to search from the end because the underlying
+  // representation can have duplicates if a user calls MergeFrom(); the last
+  // one needs to win.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  bool found = false;
+  for (int i = size - 1; i >= 0; i--) {
+    Message* entry = reflection->MutableRepeatedMessage(
+        message, self->parent_field_descriptor, i);
+    int matches = MapKeyMatches(self, entry, key);
+    if (matches < 0) return -1;
+    if (matches) {
+      found = true;
+      if (i != size - 1) {
+        reflection->SwapElements(message, self->parent_field_descriptor, i,
+                                 size - 1);
+      }
+      reflection->RemoveLast(message, self->parent_field_descriptor);
+
+      // Can't exit now, the repeated field representation of maps allows
+      // duplicate keys, and we have to be sure to remove all of them.
+    }
+  }
+
+  if (!found) {
+    PyErr_Format(PyExc_KeyError, "Key not present in map");
+    return -1;
+  }
+
+  self->version++;
+
+  return 0;
+}
+
+PyObject* GetIterator(PyObject *_self) {
+  MessageMapContainer* self = GetMap(_self);
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&MessageMapIterator_Type, 0));
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
+  }
+
+  MessageMapIterator* iter = GetIter(obj);
+
+  Py_INCREF(self);
+  iter->container = self;
+  iter->version = self->version;
+  iter->dict = PyDict_New();
+  if (iter->dict == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate dict for iterator.");
+  }
+
+  // Build the entire map into a dict right now.  Start from the beginning so
+  // that later entries win in the case of duplicates.
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.  We need to search from the end because the underlying
+  // representation can have duplicates if a user calls MergeFrom(); the last
+  // one needs to win.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = size - 1; i >= 0; i--) {
+    Message* entry = reflection->MutableRepeatedMessage(
+        message, self->parent_field_descriptor, i);
+    ScopedPyObjectPtr key(
+        cmessage::InternalGetScalar(entry, self->key_field_descriptor));
+    if (PyDict_SetItem(iter->dict, key.get(), GetCMessage(self, entry)) < 0) {
+      return PyErr_Format(PyExc_RuntimeError,
+                          "SetItem failed in iterator construction.");
+    }
+  }
+
+  iter->iter = PyObject_GetIter(iter->dict);
+
+  return obj.release();
+}
+
+PyObject* GetItem(PyObject* _self, PyObject* key) {
+  MessageMapContainer* self = GetMap(_self);
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.  We need to search from the end because the underlying
+  // representation can have duplicates if a user calls MergeFrom(); the last
+  // one needs to win.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = size - 1; i >= 0; i--) {
+    Message* entry = reflection->MutableRepeatedMessage(
+        message, self->parent_field_descriptor, i);
+    int matches = MapKeyMatches(self, entry, key);
+    if (matches < 0) return NULL;
+    if (matches) {
+      return GetCMessage(self, entry);
+    }
+  }
+
+  // Key is not already present; insert a new entry.
+  Message* entry =
+      reflection->AddMessage(message, self->parent_field_descriptor);
+
+  self->version++;
+
+  if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
+                                          key) < 0) {
+    reflection->RemoveLast(message, self->parent_field_descriptor);
+    return NULL;
+  }
+
+  return GetCMessage(self, entry);
+}
+
+PyObject* Contains(PyObject* _self, PyObject* key) {
+  MessageMapContainer* self = GetMap(_self);
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = 0; i < size; i++) {
+    Message* entry = reflection->MutableRepeatedMessage(
+        message, self->parent_field_descriptor, i);
+    int matches = MapKeyMatches(self, entry, key);
+    if (matches < 0) return NULL;
+    if (matches) {
+      Py_RETURN_TRUE;
+    }
+  }
+
+  Py_RETURN_FALSE;
+}
+
+PyObject* Clear(PyObject* _self) {
+  MessageMapContainer* self = GetMap(_self);
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  self->version++;
+  reflection->ClearField(message, self->parent_field_descriptor);
+
+  Py_RETURN_NONE;
+}
+
+PyObject* Get(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return GetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static PyMappingMethods MpMethods = {
+  Length,    // mp_length
+  GetItem,   // mp_subscript
+  SetItem,   // mp_ass_subscript
+};
+
+static void Dealloc(PyObject* _self) {
+  MessageMapContainer* self = GetMap(_self);
+  self->owner.reset();
+  Py_DECREF(self->message_dict);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef Methods[] = {
+  { "__contains__", (PyCFunction)Contains, METH_O,
+    "Tests whether the map contains this element."},
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map."},
+  { "get", Get, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  { "get_or_create", GetItem, METH_O,
+    "Alias for getitem, useful to make explicit that the map is mutated." },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+}  // namespace message_map_container
+
+namespace message_map_iterator {
+
+static void Dealloc(PyObject* _self) {
+  MessageMapIterator* self = GetIter(_self);
+  Py_DECREF(self->dict);
+  Py_DECREF(self->iter);
+  Py_DECREF(self->container);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+PyObject* IterNext(PyObject* _self) {
+  MessageMapIterator* self = GetIter(_self);
+
+  // This won't catch mutations to the map performed by MergeFrom(); no easy way
+  // to address that.
+  if (self->version != self->container->version) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Map modified during iteration.");
+  }
+
+  return PyIter_Next(self->iter);
+}
+
+}  // namespace message_map_iterator
+
+PyTypeObject MessageMapContainer_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MessageMapContainer",  //  tp_name
+  sizeof(MessageMapContainer),         //  tp_basicsize
+  0,                                   //  tp_itemsize
+  message_map_container::Dealloc,      //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  &message_map_container::MpMethods,   //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A map container for message",       //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  message_map_container::GetIterator,  //  tp_iter
+  0,                                   //  tp_iternext
+  message_map_container::Methods,      //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+PyTypeObject MessageMapIterator_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MessageMapIterator",  //  tp_name
+  sizeof(MessageMapIterator),          //  tp_basicsize
+  0,                                   //  tp_itemsize
+  message_map_iterator::Dealloc,       //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  0,                                   //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A scalar map iterator",             //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  PyObject_SelfIter,                   //  tp_iter
+  message_map_iterator::IterNext,       //  tp_iternext
+  0,                                   //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/message_map_container.h b/python/google/protobuf/pyext/message_map_container.h
new file mode 100644
index 0000000..4ca0aec
--- /dev/null
+++ b/python/google/protobuf/pyext/message_map_container.h
@@ -0,0 +1,117 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct CMessage;
+
+struct MessageMapContainer {
+  PyObject_HEAD;
+
+  // This is the top-level C++ Message object that owns the whole
+  // proto tree.  Every Python MessageMapContainer holds a
+  // reference to it in order to keep it alive as long as there's a
+  // Python object that references any part of the tree.
+  shared_ptr<Message> owner;
+
+  // Pointer to the C++ Message that contains this container.  The
+  // MessageMapContainer does not own this pointer.
+  Message* message;
+
+  // Weak reference to a parent CMessage object (i.e. may be NULL.)
+  //
+  // Used to make sure all ancestors are also mutable when first
+  // modifying the container.
+  CMessage* parent;
+
+  // Pointer to the parent's descriptor that describes this
+  // field.  Used together with the parent's message when making a
+  // default message instance mutable.
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
+  const FieldDescriptor* key_field_descriptor;
+  const FieldDescriptor* value_field_descriptor;
+
+  // A callable that is used to create new child messages.
+  PyObject* subclass_init;
+
+  // A dict mapping Message* -> CMessage.
+  PyObject* message_dict;
+
+  // We bump this whenever we perform a mutation, to invalidate existing
+  // iterators.
+  uint64 version;
+};
+
+extern PyTypeObject MessageMapContainer_Type;
+extern PyTypeObject MessageMapIterator_Type;
+
+namespace message_map_container {
+
+// Builds a MessageMapContainer object, from a parent message and a
+// field descriptor.
+extern PyObject* NewContainer(CMessage* parent,
+                              const FieldDescriptor* parent_field_descriptor,
+                              PyObject* concrete_class);
+
+// Releases the messages in the container to a new message.
+//
+// Returns 0 on success, -1 on failure.
+int Release(MessageMapContainer* self);
+
+// Set the owner field of self and any children of self.
+void SetOwner(MessageMapContainer* self,
+              const shared_ptr<Message>& new_owner);
+
+}  // namespace message_map_container
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc
index 0fe98e7..86b75d0 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.cc
+++ b/python/google/protobuf/pyext/repeated_composite_container.cc
@@ -367,8 +367,8 @@
   }
 
   // Delete from the underlying Message, if any.
-  if (self->message != NULL) {
-    if (cmessage::InternalDeleteRepeatedField(self->message,
+  if (self->parent != NULL) {
+    if (cmessage::InternalDeleteRepeatedField(self->parent,
                                               self->parent_field_descriptor,
                                               slice,
                                               self->child_messages) < 0) {
@@ -572,47 +572,35 @@
   return item;
 }
 
-// The caller takes ownership of the returned Message.
-Message* ReleaseLast(const FieldDescriptor* field,
-                     const Descriptor* type,
-                     Message* message) {
+// Release field of parent message and transfer the ownership to target.
+void ReleaseLastTo(CMessage* parent,
+                   const FieldDescriptor* field,
+                   CMessage* target) {
+  GOOGLE_CHECK_NOTNULL(parent);
   GOOGLE_CHECK_NOTNULL(field);
-  GOOGLE_CHECK_NOTNULL(type);
-  GOOGLE_CHECK_NOTNULL(message);
+  GOOGLE_CHECK_NOTNULL(target);
 
-  Message* released_message = message->GetReflection()->ReleaseLast(
-      message, field);
+  shared_ptr<Message> released_message(
+      parent->message->GetReflection()->ReleaseLast(parent->message, field));
   // TODO(tibell): Deal with proto1.
 
   // ReleaseMessage will return NULL which differs from
   // child_cmessage->message, if the field does not exist.  In this case,
   // the latter points to the default instance via a const_cast<>, so we
   // have to reset it to a new mutable object since we are taking ownership.
-  if (released_message == NULL) {
+  if (released_message.get() == NULL) {
     const Message* prototype =
-        cmessage::GetMessageFactory()->GetPrototype(type);
+        cmessage::GetMessageFactory()->GetPrototype(
+            target->message->GetDescriptor());
     GOOGLE_CHECK_NOTNULL(prototype);
-    return prototype->New();
-  } else {
-    return released_message;
+    released_message.reset(prototype->New());
   }
-}
 
-// Release field of message and transfer the ownership to cmessage.
-void ReleaseLastTo(const FieldDescriptor* field,
-                   Message* message,
-                   CMessage* cmessage) {
-  GOOGLE_CHECK_NOTNULL(field);
-  GOOGLE_CHECK_NOTNULL(message);
-  GOOGLE_CHECK_NOTNULL(cmessage);
-
-  shared_ptr<Message> released_message(
-      ReleaseLast(field, cmessage->message->GetDescriptor(), message));
-  cmessage->parent = NULL;
-  cmessage->parent_field_descriptor = NULL;
-  cmessage->message = released_message.get();
-  cmessage->read_only = false;
-  cmessage::SetOwner(cmessage, released_message);
+  target->parent = NULL;
+  target->parent_field_descriptor = NULL;
+  target->message = released_message.get();
+  target->read_only = false;
+  cmessage::SetOwner(target, released_message);
 }
 
 // Called to release a container using
@@ -635,7 +623,7 @@
   for (Py_ssize_t i = size - 1; i >= 0; --i) {
     CMessage* child_cmessage = reinterpret_cast<CMessage*>(
         PyList_GET_ITEM(self->child_messages, i));
-    ReleaseLastTo(field, message, child_cmessage);
+    ReleaseLastTo(self->parent, field, child_cmessage);
   }
 
   // Detach from containing message.
@@ -732,9 +720,7 @@
 
 PyTypeObject RepeatedCompositeContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "RepeatedCompositeContainer",        // tp_name
+  FULL_MODULE_NAME ".RepeatedCompositeContainer",  // tp_name
   sizeof(RepeatedCompositeContainer),  // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_composite_container::Dealloc,  //  tp_dealloc
diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h
index ce7cee0..e0f2136 100644
--- a/python/google/protobuf/pyext/repeated_composite_container.h
+++ b/python/google/protobuf/pyext/repeated_composite_container.h
@@ -161,13 +161,13 @@
              const shared_ptr<Message>& new_owner);
 
 // Removes the last element of the repeated message field 'field' on
-// the Message 'message', and transfers the ownership of the released
-// Message to 'cmessage'.
+// the Message 'parent', and transfers the ownership of the released
+// Message to 'target'.
 //
 // Corresponds to reflection api method ReleaseMessage.
-void ReleaseLastTo(const FieldDescriptor* field,
-                   Message* message,
-                   CMessage* cmessage);
+void ReleaseLastTo(CMessage* parent,
+                   const FieldDescriptor* field,
+                   CMessage* target);
 
 }  // namespace repeated_composite_container
 }  // namespace python
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index 110a4c8..fd19683 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -102,7 +102,7 @@
 
   if (arg == NULL) {
     ScopedPyObjectPtr py_index(PyLong_FromLong(index));
-    return cmessage::InternalDeleteRepeatedField(message, field_descriptor,
+    return cmessage::InternalDeleteRepeatedField(self->parent, field_descriptor,
                                                  py_index, NULL);
   }
 
@@ -470,7 +470,7 @@
 
   if (value == NULL) {
     return cmessage::InternalDeleteRepeatedField(
-        message, field_descriptor, slice, NULL);
+        self->parent, field_descriptor, slice, NULL);
   }
 
   if (!create_list) {
@@ -769,9 +769,7 @@
 
 PyTypeObject RepeatedScalarContainer_Type = {
   PyVarObject_HEAD_INIT(&PyType_Type, 0)
-  // Keep the fully qualified _message symbol in a line for opensource.
-  "google.protobuf.pyext._message."
-  "RepeatedScalarContainer",           // tp_name
+  FULL_MODULE_NAME ".RepeatedScalarContainer",  // tp_name
   sizeof(RepeatedScalarContainer),     // tp_basicsize
   0,                                   //  tp_itemsize
   (destructor)repeated_scalar_container::Dealloc,  //  tp_dealloc
diff --git a/python/google/protobuf/pyext/scalar_map_container.cc b/python/google/protobuf/pyext/scalar_map_container.cc
new file mode 100644
index 0000000..6f731d2
--- /dev/null
+++ b/python/google/protobuf/pyext/scalar_map_container.cc
@@ -0,0 +1,514 @@
+// 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.
+
+// Author: haberman@google.com (Josh Haberman)
+
+#include <google/protobuf/pyext/scalar_map_container.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/pyext/message.h>
+#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
+
+namespace google {
+namespace protobuf {
+namespace python {
+
+struct ScalarMapIterator {
+  PyObject_HEAD;
+
+  // This dict contains the full contents of what we want to iterate over.
+  // There's no way to avoid building this, because the list representation
+  // (which is canonical) can contain duplicate keys.  So at the very least we
+  // need a set that lets us skip duplicate keys.  And at the point that we're
+  // doing that, we might as well just build the actual dict we're iterating
+  // over and use dict's built-in iterator.
+  PyObject* dict;
+
+  // An iterator on dict.
+  PyObject* iter;
+
+  // A pointer back to the container, so we can notice changes to the version.
+  ScalarMapContainer* container;
+
+  // The version of the map when we took the iterator to it.
+  //
+  // We store this so that if the map is modified during iteration we can throw
+  // an error.
+  uint64 version;
+};
+
+static ScalarMapIterator* GetIter(PyObject* obj) {
+  return reinterpret_cast<ScalarMapIterator*>(obj);
+}
+
+namespace scalar_map_container {
+
+static ScalarMapContainer* GetMap(PyObject* obj) {
+  return reinterpret_cast<ScalarMapContainer*>(obj);
+}
+
+// The private constructor of ScalarMapContainer objects.
+PyObject *NewContainer(
+    CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) {
+  if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0));
+  if (obj.get() == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate new container.");
+  }
+
+  ScalarMapContainer* self = GetMap(obj);
+
+  self->message = parent->message;
+  self->parent = parent;
+  self->parent_field_descriptor = parent_field_descriptor;
+  self->owner = parent->owner;
+  self->version = 0;
+
+  self->key_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("key");
+  self->value_field_descriptor =
+      parent_field_descriptor->message_type()->FindFieldByName("value");
+
+  if (self->key_field_descriptor == NULL ||
+      self->value_field_descriptor == NULL) {
+    return PyErr_Format(PyExc_KeyError,
+                        "Map entry descriptor did not have key/value fields");
+  }
+
+  return obj.release();
+}
+
+// Initializes the underlying Message object of "to" so it becomes a new parent
+// repeated scalar, and copies all the values from "from" to it. A child scalar
+// container can be released by passing it as both from and to (e.g. making it
+// the recipient of the new parent message and copying the values from itself).
+static int InitializeAndCopyToParentContainer(
+    ScalarMapContainer* from,
+    ScalarMapContainer* to) {
+  // For now we require from == to, re-evaluate if we want to support deep copy
+  // as in repeated_scalar_container.cc.
+  GOOGLE_DCHECK(from == to);
+  Message* old_message = from->message;
+  Message* new_message = old_message->New();
+  to->parent = NULL;
+  to->parent_field_descriptor = from->parent_field_descriptor;
+  to->message = new_message;
+  to->owner.reset(new_message);
+
+  vector<const FieldDescriptor*> fields;
+  fields.push_back(from->parent_field_descriptor);
+  old_message->GetReflection()->SwapFields(old_message, new_message, fields);
+  return 0;
+}
+
+int Release(ScalarMapContainer* self) {
+  return InitializeAndCopyToParentContainer(self, self);
+}
+
+void SetOwner(ScalarMapContainer* self,
+              const shared_ptr<Message>& new_owner) {
+  self->owner = new_owner;
+}
+
+Py_ssize_t Length(PyObject* _self) {
+  ScalarMapContainer* self = GetMap(_self);
+  google::protobuf::Message* message = self->message;
+  return message->GetReflection()->FieldSize(*message,
+                                             self->parent_field_descriptor);
+}
+
+int MapKeyMatches(ScalarMapContainer* self, const Message* entry,
+                  PyObject* key) {
+  // TODO(haberman): do we need more strict type checking?
+  ScopedPyObjectPtr entry_key(
+      cmessage::InternalGetScalar(entry, self->key_field_descriptor));
+  int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ);
+  return ret;
+}
+
+PyObject* GetItem(PyObject* _self, PyObject* key) {
+  ScalarMapContainer* self = GetMap(_self);
+
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size = reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = size - 1; i >= 0; i--) {
+    const Message& entry = reflection->GetRepeatedMessage(
+        *message, self->parent_field_descriptor, i);
+    int matches = MapKeyMatches(self, &entry, key);
+    if (matches < 0) return NULL;
+    if (matches) {
+      return cmessage::InternalGetScalar(&entry, self->value_field_descriptor);
+    }
+  }
+
+  // Need to add a new entry.
+  Message* entry =
+      reflection->AddMessage(message, self->parent_field_descriptor);
+  PyObject* ret = NULL;
+
+  if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
+                                          key) >= 0) {
+    ret = cmessage::InternalGetScalar(entry, self->value_field_descriptor);
+  }
+
+  self->version++;
+
+  // If there was a type error above, it set the Python exception.
+  return ret;
+}
+
+int SetItem(PyObject *_self, PyObject *key, PyObject *v) {
+  ScalarMapContainer* self = GetMap(_self);
+  cmessage::AssureWritable(self->parent);
+
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+  self->version++;
+
+  if (v) {
+    // Set item.
+    //
+    // Right now the Reflection API doesn't support map lookup, so we implement
+    // it via linear search.
+    //
+    // TODO(haberman): add lookup API to Reflection API.
+    for (int i = size - 1; i >= 0; i--) {
+      Message* entry = reflection->MutableRepeatedMessage(
+          message, self->parent_field_descriptor, i);
+      int matches = MapKeyMatches(self, entry, key);
+      if (matches < 0) return -1;
+      if (matches) {
+        return cmessage::InternalSetNonOneofScalar(
+            entry, self->value_field_descriptor, v);
+      }
+    }
+
+    // Key is not already present; insert a new entry.
+    Message* entry =
+        reflection->AddMessage(message, self->parent_field_descriptor);
+
+    if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor,
+                                            key) < 0 ||
+        cmessage::InternalSetNonOneofScalar(entry, self->value_field_descriptor,
+                                            v) < 0) {
+      reflection->RemoveLast(message, self->parent_field_descriptor);
+      return -1;
+    }
+
+    return 0;
+  } else {
+    bool found = false;
+    for (int i = size - 1; i >= 0; i--) {
+      Message* entry = reflection->MutableRepeatedMessage(
+          message, self->parent_field_descriptor, i);
+      int matches = MapKeyMatches(self, entry, key);
+      if (matches < 0) return -1;
+      if (matches) {
+        found = true;
+        if (i != size - 1) {
+          reflection->SwapElements(message, self->parent_field_descriptor, i,
+                                   size - 1);
+        }
+        reflection->RemoveLast(message, self->parent_field_descriptor);
+
+        // Can't exit now, the repeated field representation of maps allows
+        // duplicate keys, and we have to be sure to remove all of them.
+      }
+    }
+
+    if (found) {
+      return 0;
+    } else {
+      PyErr_Format(PyExc_KeyError, "Key not present in map");
+      return -1;
+    }
+  }
+}
+
+PyObject* GetIterator(PyObject *_self) {
+  ScalarMapContainer* self = GetMap(_self);
+
+  ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapIterator_Type, 0));
+  if (obj == NULL) {
+    return PyErr_Format(PyExc_KeyError, "Could not allocate iterator");
+  }
+
+  ScalarMapIterator* iter = GetIter(obj.get());
+
+  Py_INCREF(self);
+  iter->container = self;
+  iter->version = self->version;
+  iter->dict = PyDict_New();
+  if (iter->dict == NULL) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Could not allocate dict for iterator.");
+  }
+
+  // Build the entire map into a dict right now.  Start from the beginning so
+  // that later entries win in the case of duplicates.
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.  We need to search from the end because the underlying
+  // representation can have duplicates if a user calls MergeFrom(); the last
+  // one needs to win.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size =
+      reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = 0; i < size; i++) {
+    Message* entry = reflection->MutableRepeatedMessage(
+        message, self->parent_field_descriptor, i);
+    ScopedPyObjectPtr key(
+        cmessage::InternalGetScalar(entry, self->key_field_descriptor));
+    ScopedPyObjectPtr val(
+        cmessage::InternalGetScalar(entry, self->value_field_descriptor));
+    if (PyDict_SetItem(iter->dict, key.get(), val.get()) < 0) {
+      return PyErr_Format(PyExc_RuntimeError,
+                          "SetItem failed in iterator construction.");
+    }
+  }
+
+
+  iter->iter = PyObject_GetIter(iter->dict);
+
+
+  return obj.release();
+}
+
+PyObject* Clear(PyObject* _self) {
+  ScalarMapContainer* self = GetMap(_self);
+  cmessage::AssureWritable(self->parent);
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  reflection->ClearField(message, self->parent_field_descriptor);
+
+  Py_RETURN_NONE;
+}
+
+PyObject* Contains(PyObject* _self, PyObject* key) {
+  ScalarMapContainer* self = GetMap(_self);
+
+  Message* message = self->message;
+  const Reflection* reflection = message->GetReflection();
+
+  // Right now the Reflection API doesn't support map lookup, so we implement it
+  // via linear search.
+  //
+  // TODO(haberman): add lookup API to Reflection API.
+  size_t size = reflection->FieldSize(*message, self->parent_field_descriptor);
+  for (int i = size - 1; i >= 0; i--) {
+    const Message& entry = reflection->GetRepeatedMessage(
+        *message, self->parent_field_descriptor, i);
+    int matches = MapKeyMatches(self, &entry, key);
+    if (matches < 0) return NULL;
+    if (matches) {
+      Py_RETURN_TRUE;
+    }
+  }
+
+  Py_RETURN_FALSE;
+}
+
+PyObject* Get(PyObject* self, PyObject* args) {
+  PyObject* key;
+  PyObject* default_value = NULL;
+  if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) {
+    return NULL;
+  }
+
+  ScopedPyObjectPtr is_present(Contains(self, key));
+  if (is_present.get() == NULL) {
+    return NULL;
+  }
+
+  if (PyObject_IsTrue(is_present.get())) {
+    return GetItem(self, key);
+  } else {
+    if (default_value != NULL) {
+      Py_INCREF(default_value);
+      return default_value;
+    } else {
+      Py_RETURN_NONE;
+    }
+  }
+}
+
+static PyMappingMethods MpMethods = {
+  Length,    // mp_length
+  GetItem,   // mp_subscript
+  SetItem,   // mp_ass_subscript
+};
+
+static void Dealloc(PyObject* _self) {
+  ScalarMapContainer* self = GetMap(_self);
+  self->owner.reset();
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+static PyMethodDef Methods[] = {
+  { "__contains__", Contains, METH_O,
+    "Tests whether a key is a member of the map." },
+  { "clear", (PyCFunction)Clear, METH_NOARGS,
+    "Removes all elements from the map." },
+  { "get", Get, METH_VARARGS,
+    "Gets the value for the given key if present, or otherwise a default" },
+  /*
+  { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS,
+    "Makes a deep copy of the class." },
+  { "__reduce__", (PyCFunction)Reduce, METH_NOARGS,
+    "Outputs picklable representation of the repeated field." },
+  */
+  {NULL, NULL},
+};
+
+}  // namespace scalar_map_container
+
+namespace scalar_map_iterator {
+
+static void Dealloc(PyObject* _self) {
+  ScalarMapIterator* self = GetIter(_self);
+  Py_DECREF(self->dict);
+  Py_DECREF(self->iter);
+  Py_DECREF(self->container);
+  Py_TYPE(_self)->tp_free(_self);
+}
+
+PyObject* IterNext(PyObject* _self) {
+  ScalarMapIterator* self = GetIter(_self);
+
+  // This won't catch mutations to the map performed by MergeFrom(); no easy way
+  // to address that.
+  if (self->version != self->container->version) {
+    return PyErr_Format(PyExc_RuntimeError,
+                        "Map modified during iteration.");
+  }
+
+  return PyIter_Next(self->iter);
+}
+
+}  // namespace scalar_map_iterator
+
+PyTypeObject ScalarMapContainer_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".ScalarMapContainer",  //  tp_name
+  sizeof(ScalarMapContainer),          //  tp_basicsize
+  0,                                   //  tp_itemsize
+  scalar_map_container::Dealloc,       //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  &scalar_map_container::MpMethods,    //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A scalar map container",            //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  scalar_map_container::GetIterator,   //  tp_iter
+  0,                                   //  tp_iternext
+  scalar_map_container::Methods,       //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+PyTypeObject ScalarMapIterator_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".ScalarMapIterator",  //  tp_name
+  sizeof(ScalarMapIterator),           //  tp_basicsize
+  0,                                   //  tp_itemsize
+  scalar_map_iterator::Dealloc,        //  tp_dealloc
+  0,                                   //  tp_print
+  0,                                   //  tp_getattr
+  0,                                   //  tp_setattr
+  0,                                   //  tp_compare
+  0,                                   //  tp_repr
+  0,                                   //  tp_as_number
+  0,                                   //  tp_as_sequence
+  0,                                   //  tp_as_mapping
+  0,                                   //  tp_hash
+  0,                                   //  tp_call
+  0,                                   //  tp_str
+  0,                                   //  tp_getattro
+  0,                                   //  tp_setattro
+  0,                                   //  tp_as_buffer
+  Py_TPFLAGS_DEFAULT,                  //  tp_flags
+  "A scalar map iterator",             //  tp_doc
+  0,                                   //  tp_traverse
+  0,                                   //  tp_clear
+  0,                                   //  tp_richcompare
+  0,                                   //  tp_weaklistoffset
+  PyObject_SelfIter,                   //  tp_iter
+  scalar_map_iterator::IterNext,       //  tp_iternext
+  0,                                   //  tp_methods
+  0,                                   //  tp_members
+  0,                                   //  tp_getset
+  0,                                   //  tp_base
+  0,                                   //  tp_dict
+  0,                                   //  tp_descr_get
+  0,                                   //  tp_descr_set
+  0,                                   //  tp_dictoffset
+  0,                                   //  tp_init
+};
+
+}  // namespace python
+}  // namespace protobuf
+}  // namespace google
diff --git a/python/google/protobuf/pyext/scalar_map_container.h b/python/google/protobuf/pyext/scalar_map_container.h
new file mode 100644
index 0000000..254e6e9
--- /dev/null
+++ b/python/google/protobuf/pyext/scalar_map_container.h
@@ -0,0 +1,110 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
+#define GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
+
+#include <Python.h>
+
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+
+class Message;
+
+using internal::shared_ptr;
+
+namespace python {
+
+struct CMessage;
+
+struct ScalarMapContainer {
+  PyObject_HEAD;
+
+  // This is the top-level C++ Message object that owns the whole
+  // proto tree.  Every Python ScalarMapContainer holds a
+  // reference to it in order to keep it alive as long as there's a
+  // Python object that references any part of the tree.
+  shared_ptr<Message> owner;
+
+  // Pointer to the C++ Message that contains this container.  The
+  // ScalarMapContainer does not own this pointer.
+  Message* message;
+
+  // Weak reference to a parent CMessage object (i.e. may be NULL.)
+  //
+  // Used to make sure all ancestors are also mutable when first
+  // modifying the container.
+  CMessage* parent;
+
+  // Pointer to the parent's descriptor that describes this
+  // field.  Used together with the parent's message when making a
+  // default message instance mutable.
+  // The pointer is owned by the global DescriptorPool.
+  const FieldDescriptor* parent_field_descriptor;
+  const FieldDescriptor* key_field_descriptor;
+  const FieldDescriptor* value_field_descriptor;
+
+  // We bump this whenever we perform a mutation, to invalidate existing
+  // iterators.
+  uint64 version;
+};
+
+extern PyTypeObject ScalarMapContainer_Type;
+extern PyTypeObject ScalarMapIterator_Type;
+
+namespace scalar_map_container {
+
+// Builds a ScalarMapContainer object, from a parent message and a
+// field descriptor.
+extern PyObject *NewContainer(
+    CMessage* parent, const FieldDescriptor* parent_field_descriptor);
+
+// Releases the messages in the container to a new message.
+//
+// Returns 0 on success, -1 on failure.
+int Release(ScalarMapContainer* self);
+
+// Set the owner field of self and any children of self.
+void SetOwner(ScalarMapContainer* self,
+              const shared_ptr<Message>& new_owner);
+
+}  // namespace scalar_map_container
+}  // namespace python
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__
diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py
index 55e653a..82fca66 100755
--- a/python/google/protobuf/reflection.py
+++ b/python/google/protobuf/reflection.py
@@ -144,7 +144,6 @@
     _InitMessage(descriptor, cls)
     superclass = super(GeneratedProtocolMessageType, cls)
     superclass.__init__(name, bases, dictionary)
-    setattr(descriptor, '_concrete_class', cls)
 
 
 def ParseMessage(descriptor, byte_str):
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index a47ce3e..8cbd682 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -100,6 +100,10 @@
     return result.rstrip()
   return result
 
+def _IsMapEntry(field):
+  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+          field.message_type.has_options and
+          field.message_type.GetOptions().map_entry)
 
 def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
                  pointy_brackets=False, use_index_order=False,
@@ -108,7 +112,19 @@
   if use_index_order:
     fields.sort(key=lambda x: x[0].index)
   for field, value in fields:
-    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+    if _IsMapEntry(field):
+      for key in value:
+        # This is slow for maps with submessage entires because it copies the
+        # entire tree.  Unfortunately this would take significant refactoring
+        # of this file to work around.
+        #
+        # TODO(haberman): refactor and optimize if this becomes an issue.
+        entry_submsg = field.message_type._concrete_class(
+            key=key, value=value[key])
+        PrintField(field, entry_submsg, out, indent, as_utf8, as_one_line,
+                   pointy_brackets=pointy_brackets,
+                   use_index_order=use_index_order, float_format=float_format)
+    elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       for element in value:
         PrintField(field, element, out, indent, as_utf8, as_one_line,
                    pointy_brackets=pointy_brackets,
@@ -367,6 +383,7 @@
               message_descriptor.full_name, name))
 
   if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+    is_map_entry = _IsMapEntry(field)
     tokenizer.TryConsume(':')
 
     if tokenizer.TryConsume('<'):
@@ -378,6 +395,8 @@
     if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       if field.is_extension:
         sub_message = message.Extensions[field].add()
+      elif is_map_entry:
+        sub_message = field.message_type._concrete_class()
       else:
         sub_message = getattr(message, field.name).add()
     else:
@@ -391,6 +410,14 @@
       if tokenizer.AtEnd():
         raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))
       _MergeField(tokenizer, sub_message, allow_multiple_scalars)
+
+    if is_map_entry:
+      value_cpptype = field.message_type.fields_by_name['value'].cpp_type
+      if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        value = getattr(message, field.name)[sub_message.key]
+        value.MergeFrom(sub_message.value)
+      else:
+        getattr(message, field.name)[sub_message.key] = sub_message.value
   else:
     _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)
 
@@ -701,13 +728,16 @@
     String literals (whether bytes or text) can come in multiple adjacent
     tokens which are automatically concatenated, like in C or Python.  This
     method only consumes one token.
+
+    Raises:
+      ParseError: When the wrong format data is found.
     """
     text = self.token
     if len(text) < 1 or text[0] not in ('\'', '"'):
-      raise self._ParseError('Expected string but found: "%r"' % text)
+      raise self._ParseError('Expected string but found: %r' % (text,))
 
     if len(text) < 2 or text[-1] != text[0]:
-      raise self._ParseError('String missing ending quote.')
+      raise self._ParseError('String missing ending quote: %r' % (text,))
 
     try:
       result = text_encoding.CUnescape(text[1:-1])
diff --git a/python/setup.py b/python/setup.py
index a1365fb..5c321f5 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -91,6 +91,7 @@
   if not os.path.exists("../.git"):
     return
 
+  generate_proto("../src/google/protobuf/map_unittest.proto")
   generate_proto("../src/google/protobuf/unittest.proto")
   generate_proto("../src/google/protobuf/unittest_custom_options.proto")
   generate_proto("../src/google/protobuf/unittest_import.proto")
diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto
index b1d6323..42d82a6 100644
--- a/ruby/tests/generated_code.proto
+++ b/ruby/tests/generated_code.proto
@@ -3,17 +3,17 @@
 package A.B.C;
 
 message TestMessage {
-  optional int32 optional_int32 = 1;
-  optional int64 optional_int64 = 2;
-  optional uint32 optional_uint32 = 3;
-  optional uint64 optional_uint64 = 4;
-  optional bool optional_bool = 5;
-  optional double optional_double = 6;
-  optional float optional_float = 7;
-  optional string optional_string = 8;
-  optional bytes optional_bytes = 9;
-  optional TestEnum optional_enum = 10;
-  optional TestMessage optional_msg = 11;
+  int32 optional_int32 = 1;
+  int64 optional_int64 = 2;
+  uint32 optional_uint32 = 3;
+  uint64 optional_uint64 = 4;
+  bool optional_bool = 5;
+  double optional_double = 6;
+  float optional_float = 7;
+  string optional_string = 8;
+  bytes optional_bytes = 9;
+  TestEnum optional_enum = 10;
+  TestMessage optional_msg = 11;
 
   repeated int32 repeated_int32 = 21;
   repeated int64 repeated_int64 = 22;
@@ -53,10 +53,10 @@
   map<string, bool> map_string_bool = 70;
 
   message NestedMessage {
-    optional int32 foo = 1;
+    int32 foo = 1;
   }
 
-  optional NestedMessage nested_message = 80;
+  NestedMessage nested_message = 80;
 }
 
 enum TestEnum {
diff --git a/src/Makefile.am b/src/Makefile.am
index fd10b78..2ecf602 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -88,6 +88,7 @@
   google/protobuf/stubs/type_traits.h                           \
   google/protobuf/any.pb.h                                      \
   google/protobuf/api.pb.h                                      \
+  google/protobuf/any.h                                         \
   google/protobuf/arena.h                                       \
   google/protobuf/arenastring.h                                 \
   google/protobuf/descriptor_database.h                         \
@@ -186,6 +187,7 @@
   $(libprotobuf_lite_la_SOURCES)                               \
   google/protobuf/any.pb.cc                                    \
   google/protobuf/api.pb.cc                                    \
+  google/protobuf/any.cc                                       \
   google/protobuf/descriptor.cc                                \
   google/protobuf/descriptor_database.cc                       \
   google/protobuf/descriptor.pb.cc                             \
@@ -264,6 +266,8 @@
   google/protobuf/compiler/java/java_enum.cc                   \
   google/protobuf/compiler/java/java_enum_field.cc             \
   google/protobuf/compiler/java/java_enum_field.h              \
+  google/protobuf/compiler/java/java_enum_field_lite.cc        \
+  google/protobuf/compiler/java/java_enum_field_lite.h         \
   google/protobuf/compiler/java/java_enum.h                    \
   google/protobuf/compiler/java/java_extension.cc              \
   google/protobuf/compiler/java/java_extension.h               \
@@ -278,22 +282,38 @@
   google/protobuf/compiler/java/java_helpers.h                 \
   google/protobuf/compiler/java/java_lazy_message_field.cc     \
   google/protobuf/compiler/java/java_lazy_message_field.h      \
+  google/protobuf/compiler/java/java_lazy_message_field_lite.cc\
+  google/protobuf/compiler/java/java_lazy_message_field_lite.h \
   google/protobuf/compiler/java/java_map_field.cc              \
   google/protobuf/compiler/java/java_map_field.h               \
+  google/protobuf/compiler/java/java_map_field_lite.cc         \
+  google/protobuf/compiler/java/java_map_field_lite.h          \
   google/protobuf/compiler/java/java_message.cc                \
+  google/protobuf/compiler/java/java_message_lite.cc           \
+  google/protobuf/compiler/java/java_message_builder.cc        \
+  google/protobuf/compiler/java/java_message_builder_lite.cc   \
   google/protobuf/compiler/java/java_message_field.cc          \
   google/protobuf/compiler/java/java_message_field.h           \
+  google/protobuf/compiler/java/java_message_field_lite.cc     \
+  google/protobuf/compiler/java/java_message_field_lite.h      \
   google/protobuf/compiler/java/java_message.h                 \
+  google/protobuf/compiler/java/java_message_lite.h            \
+  google/protobuf/compiler/java/java_message_builder.h         \
+  google/protobuf/compiler/java/java_message_builder_lite.h    \
   google/protobuf/compiler/java/java_name_resolver.cc          \
   google/protobuf/compiler/java/java_name_resolver.h           \
   google/protobuf/compiler/java/java_primitive_field.cc        \
   google/protobuf/compiler/java/java_primitive_field.h         \
+  google/protobuf/compiler/java/java_primitive_field_lite.cc   \
+  google/protobuf/compiler/java/java_primitive_field_lite.h    \
   google/protobuf/compiler/java/java_shared_code_generator.cc  \
   google/protobuf/compiler/java/java_shared_code_generator.h   \
   google/protobuf/compiler/java/java_service.cc                \
   google/protobuf/compiler/java/java_service.h                 \
   google/protobuf/compiler/java/java_string_field.cc           \
   google/protobuf/compiler/java/java_string_field.h            \
+  google/protobuf/compiler/java/java_string_field_lite.cc      \
+  google/protobuf/compiler/java/java_string_field_lite.h       \
   google/protobuf/compiler/java/java_doc_comment.cc            \
   google/protobuf/compiler/java/java_doc_comment.h             \
   google/protobuf/compiler/javanano/javanano_enum.cc           \
@@ -381,6 +401,7 @@
 # Tests ==============================================================
 
 protoc_inputs =                                                \
+  google/protobuf/any_test.proto                               \
   google/protobuf/map_lite_unittest.proto                      \
   google/protobuf/map_proto2_unittest.proto                    \
   google/protobuf/map_unittest.proto                           \
@@ -419,6 +440,7 @@
   google/protobuf/testdata/golden_message_proto3               \
   google/protobuf/testdata/golden_packed_fields_message        \
   google/protobuf/testdata/bad_utf8_string                     \
+  google/protobuf/testdata/map_test_data.txt                   \
   google/protobuf/testdata/text_format_unittest_data.txt       \
   google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt  \
   google/protobuf/testdata/text_format_unittest_data_pointy.txt             \
@@ -443,6 +465,8 @@
 
 protoc_outputs =                                               \
   $(protoc_lite_outputs)                                       \
+  google/protobuf/any_test.pb.cc                               \
+  google/protobuf/any_test.pb.h                                \
   google/protobuf/map_proto2_unittest.pb.cc                    \
   google/protobuf/map_proto2_unittest.pb.h                     \
   google/protobuf/map_unittest.pb.cc                           \
@@ -543,6 +567,7 @@
   google/protobuf/stubs/stringprintf_unittest.cc               \
   google/protobuf/stubs/template_util_unittest.cc              \
   google/protobuf/stubs/type_traits_unittest.cc                \
+  google/protobuf/any_test.cc                                  \
   google/protobuf/arenastring_unittest.cc                      \
   google/protobuf/arena_unittest.cc                            \
   google/protobuf/descriptor_database_unittest.cc              \
@@ -604,6 +629,8 @@
 protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la
 protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS)
 protobuf_lite_test_SOURCES =                                           \
+  google/protobuf/arena_test_util.cc                                   \
+  google/protobuf/arena_test_util.h                                    \
   google/protobuf/lite_unittest.cc                                     \
   google/protobuf/map_lite_test_util.cc                                \
   google/protobuf/map_lite_test_util.h                                 \
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
new file mode 100644
index 0000000..c66fdfa
--- /dev/null
+++ b/src/google/protobuf/any.cc
@@ -0,0 +1,100 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/any.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+namespace {
+string GetTypeUrl(const Descriptor* message) {
+  return string(kTypeGoogleApisComPrefix) + message->full_name();
+}
+
+}  // namespace
+
+const char kAnyFullTypeName[] = "google.protobuf.Any";
+const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+
+AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
+    : type_url_(type_url), value_(value) {
+}
+
+void AnyMetadata::PackFrom(const Message& message) {
+  type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
+      GetTypeUrl(message.GetDescriptor()));
+  message.SerializeToString(value_->MutableNoArena(
+      &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
+}
+
+bool AnyMetadata::UnpackTo(Message* message) const {
+  if (!InternalIs(message->GetDescriptor())) {
+    return false;
+  }
+  return message->ParseFromString(
+      value_->GetNoArena(&::google::protobuf::internal::GetEmptyString()));
+}
+
+bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
+  return type_url_->GetNoArena(
+             &::google::protobuf::internal::GetEmptyString()) ==
+         GetTypeUrl(descriptor);
+}
+
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
+  const int prefix_len = strlen(kTypeGoogleApisComPrefix);
+  if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) {
+    full_type_name->assign(type_url.data() + prefix_len,
+                           type_url.size() - prefix_len);
+    return true;
+  }
+  return true;
+}
+
+
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field) {
+    const Descriptor* descriptor = message.GetDescriptor();
+    if (descriptor->full_name() != kAnyFullTypeName) {
+      return false;
+    }
+    *type_url_field = descriptor->FindFieldByNumber(1);
+    *value_field = descriptor->FindFieldByNumber(2);
+    return (*type_url_field != NULL &&
+            (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+            *value_field != NULL &&
+            (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
new file mode 100644
index 0000000..757b45a
--- /dev/null
+++ b/src/google/protobuf/any.h
@@ -0,0 +1,90 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_ANY_H__
+#define GOOGLE_PROTOBUF_ANY_H__
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// Helper class used to implement google::protobuf::Any.
+class AnyMetadata {
+  typedef ArenaStringPtr UrlType;
+  typedef ArenaStringPtr ValueType;
+ public:
+  // AnyMetadata does not take ownership of "type_url" and "value".
+  AnyMetadata(UrlType* type_url, ValueType* value);
+
+  void PackFrom(const Message& message);
+
+  bool UnpackTo(Message* message) const;
+
+  template<typename T>
+  bool Is() const {
+    return InternalIs(T::default_instance().GetDescriptor());
+  }
+
+ private:
+  bool InternalIs(const Descriptor* message) const;
+
+  UrlType* type_url_;
+  ValueType* value_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata);
+};
+
+extern const char kAnyFullTypeName[];          // "google.protobuf.Any".
+extern const char kTypeGoogleApisComPrefix[];  // "type.googleapis.com/".
+
+// Get the proto type name from Any::type_url value. For example, passing
+// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
+// *full_type_name. Returns false if type_url does not start with
+// "type.googleapis.com".
+bool ParseAnyTypeUrl(const string& type_url, string* full_type_name);
+
+// See if message is of type google.protobuf.Any, if so, return the descriptors
+// for "type_url" and "value" fields.
+bool GetAnyFieldDescriptors(const Message& message,
+                            const FieldDescriptor** type_url_field,
+                            const FieldDescriptor** value_field);
+
+}  // namespace internal
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_ANY_H__
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index 75cc875..2c492b0 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -111,13 +111,21 @@
 
 // ===================================================================
 
+void Any::PackFrom(const ::google::protobuf::Message& message) {
+  _any_metadata_.PackFrom(message);
+}
+
+bool Any::UnpackTo(::google::protobuf::Message* message) const {
+  return _any_metadata_.UnpackTo(message);
+}
+
 #ifndef _MSC_VER
 const int Any::kTypeUrlFieldNumber;
 const int Any::kValueFieldNumber;
 #endif  // !_MSC_VER
 
 Any::Any()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Any)
 }
@@ -128,7 +136,8 @@
 
 Any::Any(const Any& from)
   : ::google::protobuf::Message(),
-    _internal_metadata_(NULL) {
+    _internal_metadata_(NULL),
+    _any_metadata_(&type_url_, &value_) {
   SharedCtor();
   MergeFrom(from);
   // @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
@@ -316,9 +325,9 @@
 
 void Any::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Any* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Any*>(
-      &from);
+  const Any* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Any>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -378,7 +387,7 @@
 // Any
 
 // optional string type_url = 1;
- void Any::clear_type_url() {
+void Any::clear_type_url() {
   type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Any::type_url() const {
@@ -421,7 +430,7 @@
 }
 
 // optional bytes value = 2;
- void Any::clear_value() {
+void Any::clear_value() {
   value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Any::value() const {
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index b2c238c..c324c4a 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -27,6 +27,7 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/unknown_field_set.h>
+#include "google/protobuf/any.h"
 // @@protoc_insertion_point(includes)
 
 namespace google {
@@ -56,6 +57,14 @@
   static const ::google::protobuf::Descriptor* descriptor();
   static const Any& default_instance();
 
+  // implements Any -----------------------------------------------
+
+  void PackFrom(const ::google::protobuf::Message& message);
+  bool UnpackTo(::google::protobuf::Message* message) const;
+  template<typename T> bool Is() const {
+    return _any_metadata_.Is<T>();
+  }
+
   void Swap(Any* other);
 
   // implements Message ----------------------------------------------
@@ -127,6 +136,7 @@
   ::google::protobuf::internal::ArenaStringPtr type_url_;
   ::google::protobuf::internal::ArenaStringPtr value_;
   mutable int _cached_size_;
+  ::google::protobuf::internal::AnyMetadata _any_metadata_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto();
diff --git a/src/google/protobuf/any_test.cc b/src/google/protobuf/any_test.cc
new file mode 100644
index 0000000..1bfaa63
--- /dev/null
+++ b/src/google/protobuf/any_test.cc
@@ -0,0 +1,89 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/any_test.pb.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace {
+
+TEST(AnyTest, TestPackAndUnpack) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(submessage);
+
+  string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  ASSERT_TRUE(message.any_value().UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestPackAndUnpackAny) {
+  // We can pack a Any message inside another Any message.
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  google::protobuf::Any any;
+  any.PackFrom(submessage);
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(any);
+
+  string data = message.SerializeAsString();
+
+  ASSERT_TRUE(message.ParseFromString(data));
+  EXPECT_TRUE(message.has_any_value());
+  ASSERT_TRUE(message.any_value().UnpackTo(&any));
+  ASSERT_TRUE(any.UnpackTo(&submessage));
+  EXPECT_EQ(12345, submessage.int32_value());
+}
+
+TEST(AnyTest, TestIs) {
+  protobuf_unittest::TestAny submessage;
+  submessage.set_int32_value(12345);
+  google::protobuf::Any any;
+  any.PackFrom(submessage);
+  ASSERT_TRUE(any.ParseFromString(any.SerializeAsString()));
+  EXPECT_TRUE(any.Is<protobuf_unittest::TestAny>());
+  EXPECT_FALSE(any.Is<google::protobuf::Any>());
+
+  protobuf_unittest::TestAny message;
+  message.mutable_any_value()->PackFrom(any);
+  ASSERT_TRUE(message.ParseFromString(message.SerializeAsString()));
+  EXPECT_FALSE(message.any_value().Is<protobuf_unittest::TestAny>());
+  EXPECT_TRUE(message.any_value().Is<google::protobuf::Any>());
+}
+
+}  // namespace
+}  // namespace protobuf
+
+}  // namespace google
diff --git a/src/google/protobuf/any_test.proto b/src/google/protobuf/any_test.proto
new file mode 100644
index 0000000..0c5b30b
--- /dev/null
+++ b/src/google/protobuf/any_test.proto
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package protobuf_unittest;
+
+import "google/protobuf/any.proto";
+
+message TestAny {
+  int32 int32_value = 1;
+  google.protobuf.Any any_value = 2;
+  repeated google.protobuf.Any repeated_any_value = 3;
+}
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index b34ce80..434320d 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -162,7 +162,7 @@
 #endif  // !_MSC_VER
 
 Api::Api()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Api)
 }
@@ -230,7 +230,7 @@
 void Api::Clear() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
   methods_.Clear();
   options_.Clear();
@@ -266,26 +266,31 @@
       case 2: {
         if (tag == 18) {
          parse_methods:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_methods:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_methods()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_methods;
-        if (input->ExpectTag(26)) goto parse_options;
+        if (input->ExpectTag(18)) goto parse_loop_methods;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.Option options = 3;
       case 3: {
         if (tag == 26) {
-         parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(26)) goto parse_options;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(34)) goto parse_version;
         break;
       }
@@ -483,9 +488,9 @@
 
 void Api::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Api* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Api*>(
-      &from);
+  const Api* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Api>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -553,7 +558,7 @@
 // Api
 
 // optional string name = 1;
- void Api::clear_name() {
+void Api::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Api::name() const {
@@ -596,10 +601,10 @@
 }
 
 // repeated .google.protobuf.Method methods = 2;
- int Api::methods_size() const {
+int Api::methods_size() const {
   return methods_.size();
 }
- void Api::clear_methods() {
+void Api::clear_methods() {
   methods_.Clear();
 }
  const ::google::protobuf::Method& Api::methods(int index) const {
@@ -626,10 +631,10 @@
 }
 
 // repeated .google.protobuf.Option options = 3;
- int Api::options_size() const {
+int Api::options_size() const {
   return options_.size();
 }
- void Api::clear_options() {
+void Api::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& Api::options(int index) const {
@@ -656,7 +661,7 @@
 }
 
 // optional string version = 4;
- void Api::clear_version() {
+void Api::clear_version() {
   version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Api::version() const {
@@ -699,11 +704,11 @@
 }
 
 // optional .google.protobuf.SourceContext source_context = 5;
- bool Api::has_source_context() const {
+bool Api::has_source_context() const {
   return !_is_default_instance_ && source_context_ != NULL;
 }
- void Api::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+void Api::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
  const ::google::protobuf::SourceContext& Api::source_context() const {
@@ -749,7 +754,7 @@
 #endif  // !_MSC_VER
 
 Method::Method()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Method)
 }
@@ -929,12 +934,15 @@
       case 6: {
         if (tag == 50) {
          parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(50)) goto parse_options;
+        if (input->ExpectTag(50)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1119,9 +1127,9 @@
 
 void Method::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Method* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Method*>(
-      &from);
+  const Method* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Method>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1196,7 +1204,7 @@
 // Method
 
 // optional string name = 1;
- void Method::clear_name() {
+void Method::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Method::name() const {
@@ -1239,7 +1247,7 @@
 }
 
 // optional string request_type_url = 2;
- void Method::clear_request_type_url() {
+void Method::clear_request_type_url() {
   request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Method::request_type_url() const {
@@ -1282,7 +1290,7 @@
 }
 
 // optional bool request_streaming = 3;
- void Method::clear_request_streaming() {
+void Method::clear_request_streaming() {
   request_streaming_ = false;
 }
  bool Method::request_streaming() const {
@@ -1296,7 +1304,7 @@
 }
 
 // optional string response_type_url = 4;
- void Method::clear_response_type_url() {
+void Method::clear_response_type_url() {
   response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Method::response_type_url() const {
@@ -1339,7 +1347,7 @@
 }
 
 // optional bool response_streaming = 5;
- void Method::clear_response_streaming() {
+void Method::clear_response_streaming() {
   response_streaming_ = false;
 }
  bool Method::response_streaming() const {
@@ -1353,10 +1361,10 @@
 }
 
 // repeated .google.protobuf.Option options = 6;
- int Method::options_size() const {
+int Method::options_size() const {
   return options_.size();
 }
- void Method::clear_options() {
+void Method::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& Method::options(int index) const {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index f459af0..985adc5 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -466,7 +466,7 @@
   return !_is_default_instance_ && source_context_ != NULL;
 }
 inline void Api::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
 inline const ::google::protobuf::SourceContext& Api::source_context() const {
@@ -690,6 +690,8 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index f7059d2..9600964 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -29,7 +29,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <google/protobuf/arena.h>
-#include <google/protobuf/stubs/common.h>
 
 #ifdef ADDRESS_SANITIZER
 #include <sanitizer/asan_interface.h>
@@ -155,10 +154,16 @@
             reinterpret_cast<google::protobuf::internal::AtomicWord>(node)));
 }
 
-void* Arena::AllocateAligned(size_t n) {
+void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) {
   // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.)
   n = (n + 7) & -8;
 
+  // Monitor allocation if needed.
+  if (GOOGLE_PREDICT_FALSE(hooks_cookie_ != NULL) &&
+      options_.on_arena_allocation != NULL) {
+    options_.on_arena_allocation(allocated, n, hooks_cookie_);
+  }
+
   // 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
   // same arena.
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index b48bef9..4adcd67 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -28,12 +28,12 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// This header is logically internal, but is made public because it is used
-// from protocol-compiler-generated code, which may reside in other components.
-
 #ifndef GOOGLE_PROTOBUF_ARENA_H__
 #define GOOGLE_PROTOBUF_ARENA_H__
 
+#if __cplusplus >= 201103L
+#include <google/protobuf/stubs/type_traits.h>
+#endif
 #include <typeinfo>
 
 #include <google/protobuf/stubs/atomic_sequence_num.h>
@@ -113,10 +113,13 @@
   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
 
-  // type_name is promised to be a static string - its lifetime extends to
-  // match program's lifetime.
-  void (*on_arena_allocation)(const char* type_name, uint64 alloc_size,
-      Arena* arena, void* cookie);
+  // type_info is promised to be static - its lifetime extends to
+  // match program's lifetime (It is given by typeid operator).
+  // Note: typeid(void) will be passed as allocated_type every time we
+  // intentionally want to avoid monitoring an allocation. (i.e. internal
+  // allocations for managing the arena)
+  void (*on_arena_allocation)(const std::type_info* allocated_type,
+      uint64 alloc_size, void* cookie);
 
   ArenaOptions()
       : start_block_size(kDefaultStartBlockSize),
@@ -137,6 +140,14 @@
   static const size_t kDefaultMaxBlockSize   = 8192;
 };
 
+// Support for non-RTTI environments. (The metrics hooks API uses type
+// information.)
+#ifndef GOOGLE_PROTOBUF_NO_RTTI
+#define RTTI_TYPE_ID(type) (&typeid(type))
+#else
+#define RTTI_TYPE_ID(type) (NULL)
+#endif
+
 // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
 // with new/delete, and improves performance by aggregating allocations into
 // larger blocks and freeing allocations all at once. Protocol messages are
@@ -146,6 +157,44 @@
 // This is a thread-safe implementation: multiple threads may allocate from the
 // arena concurrently. Destruction is not thread-safe and the destructing
 // thread must synchronize with users of the arena first.
+//
+// An arena provides two allocation interfaces: CreateMessage<T>, which works
+// for arena-enabled proto2 message types as well as other types that satisfy
+// the appropriate protocol (described below), and Create<T>, which works for
+// any arbitrary type T. CreateMessage<T> is better when the type T supports it,
+// because this interface (i) passes the arena pointer to the created object so
+// that its sub-objects and internal allocations can use the arena too, and (ii)
+// elides the object's destructor call when possible. Create<T> does not place
+// any special requirements on the type T, and will invoke the object's
+// destructor when the arena is destroyed.
+//
+// The arena message allocation protocol, required by CreateMessage<T>, is as
+// follows:
+//
+// - The type T must have (at least) two constructors: a constructor with no
+//   arguments, called when a T is allocated on the heap; and a constructor with
+//   a google::protobuf::Arena* argument, called when a T is allocated on an arena. If the
+//   second constructor is called with a NULL arena pointer, it must be
+//   equivalent to invoking the first (no-argument) constructor.
+//
+// - The type T must have a particular type trait: a nested type
+//   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
+//   such type trait exists, then the instantiation CreateMessage<T> will fail
+//   to compile.
+//
+// - The type T *may* have the type trait |DestructorSkippable_|. If this type
+//   trait is present in the type, then its destructor will not be called if and
+//   only if it was passed a non-NULL arena pointer. If this type trait is not
+//   present on the type, then its destructor is always called when the
+//   containing arena is destroyed.
+//
+// - One- and two-user-argument forms of CreateMessage<T>() also exist that
+//   forward these constructor arguments to T's constructor: for example,
+//   CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
+//   arg1, arg2).
+//
+// This protocol is implemented by all arena-enabled proto2 message classes as
+// well as RepeatedPtrField.
 class LIBPROTOBUF_EXPORT Arena {
  public:
   // Arena constructor taking custom options. See ArenaOptions below for
@@ -172,8 +221,10 @@
   // compilation error will occur.
   //
   // RepeatedField and RepeatedPtrField may also be instantiated directly on an
-  // arena with this method: they act as "arena-capable message types" for the
-  // purposes of the Arena API.
+  // arena with this method.
+  //
+  // This function also accepts any type T that satisfies the arena message
+  // allocation protocol, documented above.
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   static T* CreateMessage(::google::protobuf::Arena* arena) {
     if (arena == NULL) {
@@ -183,17 +234,55 @@
     }
   }
 
+  // One-argument form of CreateMessage. This is useful for constructing objects
+  // that implement the arena message construction protocol described above but
+  // take additional constructor arguments.
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessage(::google::protobuf::Arena* arena, const Arg& arg) {
+    if (arena == NULL) {
+      return new T(NULL, arg);
+    } else {
+      return arena->CreateMessageInternal<T>(static_cast<T*>(0),
+                                             arg);
+    }
+  }
+
+  // Two-argument form of CreateMessage. This is useful for constructing objects
+  // that implement the arena message construction protocol described above but
+  // take additional constructor arguments.
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  static T* CreateMessage(::google::protobuf::Arena* arena,
+                          const Arg1& arg1,
+                          const Arg2& arg2) {
+    if (arena == NULL) {
+      return new T(NULL, arg1, arg2);
+    } else {
+      return arena->CreateMessageInternal<T>(static_cast<T*>(0),
+                                             arg1, arg2);
+    }
+  }
+
   // API to create any objects on the arena. Note that only the object will
   // be created on the arena; the underlying ptrs (in case of a proto2 message)
   // will be still heap allocated. Proto messages should usually be allocated
   // with CreateMessage<T>() instead.
+  //
+  // Note that even if T satisfies the arena message construction protocol
+  // (InternalArenaConstructable_ trait and optional DestructorSkippable_
+  // trait), as described above, this function does not follow the protocol;
+  // instead, it treats T as a black-box type, just as if it did not have these
+  // traits. Specifically, T's constructor arguments will always be only those
+  // passed to Create<T>() -- no additional arena pointer is implicitly added.
+  // Furthermore, the destructor will always be called at arena destruction time
+  // (unless the destructor is trivial). Hence, from T's point of view, it is as
+  // if the object were allocated on the heap (except that the underlying memory
+  // is obtained from the arena).
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   static T* Create(::google::protobuf::Arena* arena) {
     if (arena == NULL) {
       return new T();
     } else {
-      return arena->CreateInternal<T>(
-          SkipDeleteList<T>(static_cast<T*>(0)));
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value);
     }
   }
 
@@ -203,7 +292,7 @@
     if (arena == NULL) {
       return new T(arg);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
                                       arg);
     }
   }
@@ -214,9 +303,8 @@
     if (arena == NULL) {
       return new T(arg1, arg2);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2);
     }
   }
 
@@ -229,10 +317,8 @@
     if (arena == NULL) {
       return new T(arg1, arg2, arg3);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2,
-                                      arg3);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3);
     }
   }
 
@@ -246,20 +332,95 @@
     if (arena == NULL) {
       return new T(arg1, arg2, arg3, arg4);
     } else {
-      return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
-                                      arg1,
-                                      arg2,
-                                      arg3,
-                                      arg4);
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4);
     }
   }
 
-  // Create an array of object type T on the arena. Type T must have a trivial
-  // constructor, as it will not be invoked when created on the arena.
+  // Version of the above with five constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5);
+    }
+  }
+
+  // Version of the above with six constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+  }
+
+  // Version of the above with seven constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6,
+                                           const Arg7& arg7) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    } else {
+      return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
+                                      arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+  }
+
+  // Version of the above with eight constructor arguments for the created
+  // object.
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7,
+            typename Arg8>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
+                                           const Arg1& arg1, const Arg2& arg2,
+                                           const Arg3& arg3, const Arg4& arg4,
+                                           const Arg5& arg5, const Arg6& arg6,
+                                           const Arg7& arg7, const Arg8& arg8) {
+    if (arena == NULL) {
+      return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    } else {
+      return arena->CreateInternal<T>(
+          google::protobuf::internal::has_trivial_destructor<T>::value,
+          arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    }
+  }
+
+  // Create an array of object type T on the arena *without* invoking the
+  // constructor of T. If `arena` is null, then the return value should be freed
+  // with `delete[] x;` (or `::operator delete[](x);`).
+  // To ensure safe uses, this function checks at compile time
+  // (when compiled as C++11) that T is trivially default-constructible and
+  // trivially destructible.
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
+#if __cplusplus >= 201103L
+    static_assert(std::is_trivially_default_constructible<T>::value,
+                  "CreateArray requires a trivially constructible type");
+    static_assert(std::is_trivially_destructible<T>::value,
+                  "CreateArray requires a trivially destructible type");
+#endif
     if (arena == NULL) {
-      return new T[num_elements];
+      return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
     } else {
       return arena->CreateInternalRawArray<T>(num_elements);
     }
@@ -374,27 +535,26 @@
   // wrap them in static functions.
   static ThreadCache& thread_cache();
 #elif defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
-  // Android ndk does not support __thread keyword so we use a custom thread
+  // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
   // local storage class we implemented.
-  // iOS also does not support the __thread keyword.
+  // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
   static ThreadCache& thread_cache();
 #else
   static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
   static ThreadCache& thread_cache() { return thread_cache_; }
 #endif
 
-  // SFINAE for skipping addition to delete list for a Type. This is mainly to
-  // skip proto2/proto1 message objects with cc_enable_arenas=true from being
-  // part of the delete list. Also, note, compiler will optimize out the branch
-  // in CreateInternal<T>.
-  //
+  // SFINAE for skipping addition to delete list for a message type when created
+  // with CreateMessage. This is mainly to skip proto2/proto1 message objects
+  // with cc_enable_arenas=true from being part of the delete list. Also, note,
+  // compiler will optimize out the branch in CreateInternal<T>.
   template<typename T>
   static inline bool SkipDeleteList(typename T::DestructorSkippable_*) {
     return true;
   }
 
-  // For non message objects, we skip addition to delete list if the object has
-  // a trivial destructor.
+  // For message objects that don't have the DestructorSkippable_ trait, we
+  // always add to the delete list.
   template<typename T>
   static inline bool SkipDeleteList(...) {
     return google::protobuf::internal::has_trivial_destructor<T>::value;
@@ -419,14 +579,15 @@
   // Just allocate the required size for the given type assuming the
   // type has a trivial constructor.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateInternalRawArray(uint32 num_elements) {
-    return static_cast<T*>(AllocateAligned(sizeof(T) * num_elements));
+  inline T* CreateInternalRawArray(size_t num_elements) {
+    return static_cast<T*>(
+        AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements));
   }
 
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   inline T* CreateInternal(
       bool skip_explicit_ownership) {
-    T* t = new (AllocateAligned(sizeof(T))) T();
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T();
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
     }
@@ -436,7 +597,7 @@
   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   inline T* CreateInternal(
       bool skip_explicit_ownership, const Arg& arg) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg);
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg);
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
     }
@@ -446,7 +607,7 @@
   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   inline T* CreateInternal(
       bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2);
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2);
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
     }
@@ -458,7 +619,8 @@
                                                    const Arg1& arg1,
                                                    const Arg2& arg2,
                                                    const Arg3& arg3) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3);
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3);
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
     }
@@ -472,7 +634,79 @@
                                                    const Arg2& arg2,
                                                    const Arg3& arg3,
                                                    const Arg4& arg4) {
-    T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, arg4);
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3,
+                                                   const Arg4& arg4,
+                                                   const Arg5& arg5) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3,
+                                                   const Arg4& arg4,
+                                                   const Arg5& arg5,
+                                                   const Arg6& arg6) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3,
+                                                   const Arg4& arg4,
+                                                   const Arg5& arg5,
+                                                   const Arg6& arg6,
+                                                   const Arg7& arg7) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    if (!skip_explicit_ownership) {
+      AddListNode(t, &internal::arena_destruct_object<T>);
+    }
+    return t;
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3,
+            typename Arg4, typename Arg5, typename Arg6, typename Arg7,
+            typename Arg8>
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
+                                                   const Arg1& arg1,
+                                                   const Arg2& arg2,
+                                                   const Arg3& arg3,
+                                                   const Arg4& arg4,
+                                                   const Arg5& arg5,
+                                                   const Arg6& arg6,
+                                                   const Arg7& arg7,
+                                                   const Arg8& arg8) {
+    T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
+        T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
     }
@@ -485,6 +719,20 @@
                                      this);
   }
 
+  template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
+                                  const Arg& arg) {
+    return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                     this, arg);
+  }
+
+  template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
+  inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
+                                  const Arg1& arg1, const Arg2& arg2) {
+    return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
+                                     this, arg1, arg2);
+  }
+
   // CreateInArenaStorage is used to implement map field. Without it,
   // google::protobuf::Map need to call generated message's protected arena constructor,
   // which needs to declare google::protobuf::Map as friend of generated message.
@@ -536,8 +784,15 @@
     return NULL;
   }
 
+  // Allocate and also optionally call on_arena_allocation callback with the
+  // allocated type info when the hooks are in place in ArenaOptions and
+  // the cookie is not null.
+  void* AllocateAligned(const std::type_info* allocated, size_t n);
 
-  void* AllocateAligned(size_t size);
+  // Allocate an internal allocation, avoiding optional typed monitoring.
+  GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline void* AllocateAligned(size_t n) {
+    return AllocateAligned(NULL, n);
+  }
 
   void Init();
 
@@ -596,6 +851,9 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
 };
 
+// Defined above for supporting environments without RTTI.
+#undef RTTI_TYPE_ID
+
 template<typename T>
 const typename Arena::is_arena_constructable<T>::type
     Arena::is_arena_constructable<T>::value =
diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py
index f390df3..87a69b2 100644
--- a/src/google/protobuf/arena_nc_test.py
+++ b/src/google/protobuf/arena_nc_test.py
@@ -35,6 +35,7 @@
 import unittest
 
 from google3.testing.pybase import fake_target_util
+import unittest
 
 
 class ArenaNcTest(unittest.TestCase):
diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h
index 7db7a90..690cc70 100644
--- a/src/google/protobuf/arena_test_util.h
+++ b/src/google/protobuf/arena_test_util.h
@@ -31,6 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 #define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__
 
+
 namespace google {
 namespace protobuf {
 namespace internal {
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index d9b198e..873e85a 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -39,6 +39,7 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #include <string>
+#include <typeinfo>
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
@@ -47,11 +48,14 @@
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest_arena.pb.h>
 #include <google/protobuf/unittest_no_arena.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message_lite.h>
 #include <google/protobuf/repeated_field.h>
+#include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/unknown_field_set.h>
 #include <gtest/gtest.h>
 
@@ -125,6 +129,29 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour);
 };
 
+// A class that takes eight different types as constructor arguments.
+class MustBeConstructedWithOneThroughEight {
+ public:
+  MustBeConstructedWithOneThroughEight(
+      int one, const char* two, const string& three,
+      const PleaseDontCopyMe* four, int five, const char* six,
+      const string& seven, const string& eight)
+      : one_(one), two_(two), three_(three), four_(four), five_(five),
+        six_(six), seven_(seven), eight_(eight) {}
+
+  int one_;
+  const char* const two_;
+  string three_;
+  const PleaseDontCopyMe* four_;
+  int five_;
+  const char* const six_;
+  string seven_;
+  string eight_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughEight);
+};
+
 }  // namespace
 
 TEST(ArenaTest, ArenaConstructable) {
@@ -156,7 +183,7 @@
   EXPECT_EQ(2, notifier.GetCount());
 }
 
-TEST(ArenaTest, CreateWithManyConstructorArguments) {
+TEST(ArenaTest, CreateWithFourConstructorArguments) {
   Arena arena;
   const string three("3");
   const PleaseDontCopyMe four(4);
@@ -170,6 +197,26 @@
   ASSERT_EQ(4, new_object->four_->value());
 }
 
+TEST(ArenaTest, CreateWithEightConstructorArguments) {
+  Arena arena;
+  const string three("3");
+  const PleaseDontCopyMe four(4);
+  const string seven("7");
+  const string eight("8");
+  const MustBeConstructedWithOneThroughEight* new_object =
+      Arena::Create<MustBeConstructedWithOneThroughEight>(
+          &arena, 1, "2", three, &four, 5, "6", seven, eight);
+  EXPECT_TRUE(new_object != NULL);
+  ASSERT_EQ(1, new_object->one_);
+  ASSERT_STREQ("2", new_object->two_);
+  ASSERT_EQ("3", new_object->three_);
+  ASSERT_EQ(4, new_object->four_->value());
+  ASSERT_EQ(5, new_object->five_);
+  ASSERT_STREQ("6", new_object->six_);
+  ASSERT_EQ("7", new_object->seven_);
+  ASSERT_EQ("8", new_object->eight_);
+}
+
 TEST(ArenaTest, InitialBlockTooSmall) {
   // 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
@@ -1113,6 +1160,19 @@
   EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message));
 }
 
+TEST(ArenaTest, UnsafeSetAllocatedOnArena) {
+  ::google::protobuf::Arena arena;
+  TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena);
+  EXPECT_FALSE(message->has_optional_string());
+
+  string owned_string = "test with long enough content to heap-allocate";
+  message->unsafe_arena_set_allocated_optional_string(&owned_string);
+  EXPECT_TRUE(message->has_optional_string());
+
+  message->unsafe_arena_set_allocated_optional_string(NULL);
+  EXPECT_FALSE(message->has_optional_string());
+}
+
 // A helper utility class to only contain static hook functions, some
 // counters to be used to verify the counters have been called and a cookie
 // value to be verified.
@@ -1124,6 +1184,13 @@
     return static_cast<void*>(cookie);
   }
 
+  static void on_allocation(const std::type_info* /*unused*/, uint64 alloc_size,
+                            void* cookie) {
+    ++num_allocations;
+    int cookie_value = *static_cast<int*>(cookie);
+    EXPECT_EQ(kCookieValue, cookie_value);
+  }
+
   static void on_reset(::google::protobuf::Arena* arena, void* cookie,
                        uint64 space_used) {
     ++num_reset;
@@ -1141,10 +1208,12 @@
 
   static const int kCookieValue = 999;
   static uint32 num_init;
+  static uint32 num_allocations;
   static uint32 num_reset;
   static uint32 num_destruct;
 };
 uint32 ArenaHooksTestUtil::num_init = 0;
+uint32 ArenaHooksTestUtil::num_allocations = 0;
 uint32 ArenaHooksTestUtil::num_reset = 0;
 uint32 ArenaHooksTestUtil::num_destruct = 0;
 const int ArenaHooksTestUtil::kCookieValue;
@@ -1153,6 +1222,7 @@
 TEST(ArenaTest, ArenaHooksSanity) {
   ::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;
 
@@ -1160,6 +1230,9 @@
   {
     ::google::protobuf::Arena arena(options);
     EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
+    EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations);
+    ::google::protobuf::Arena::Create<uint64>(&arena);
+    EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations);
 
     arena.Reset();
     arena.Reset();
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index 321a8cc..b989f15 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -79,6 +79,37 @@
                         GeneratorContext* generator_context,
                         string* error) const = 0;
 
+  // Generates code for all given proto files, generating one or more files in
+  // the given output directory.
+  //
+  // This method should be called instead of |Generate()| when
+  // |HasGenerateAll()| returns |true|. It is used to emulate legacy semantics
+  // when more than one `.proto` file is specified on one compiler invocation.
+  //
+  // WARNING: Please do not use unless legacy semantics force the code generator
+  // to produce a single output file for all input files, or otherwise require
+  // an examination of all input files first. The canonical code generator
+  // design produces one output file per input .proto file, and we do not wish
+  // to encourage alternate designs.
+  //
+  // A parameter is given as passed on the command line, as in |Generate()|
+  // above.
+  //
+  // Returns true if successful.  Otherwise, sets *error to a description of
+  // the problem (e.g. "invalid parameter") and returns false.
+  virtual bool GenerateAll(const vector<const FileDescriptor*>& files,
+                           const string& parameter,
+                           GeneratorContext* generator_context,
+                           string* error) const {
+    *error = "Unimplemented GenerateAll() method.";
+    return false;
+  }
+
+  // Returns true if the code generator expects to receive all FileDescriptors
+  // at once (via |GenerateAll()|), rather than one at a time (via
+  // |Generate()|). This is required to implement legacy semantics.
+  virtual bool HasGenerateAll() const { return false; }
+
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
 };
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 567238a..291fb05 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -898,12 +898,14 @@
     return PARSE_ARGUMENT_FAIL;
   }
   if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) {
-    cerr << "Can only use --dependency_out=FILE when generating code." << endl;
+    std::cerr << "Can only use --dependency_out=FILE when generating code."
+              << std::endl;
     return PARSE_ARGUMENT_FAIL;
   }
   if (!dependency_out_name_.empty() && input_files_.size() > 1) {
-    cerr << "Can only process one input file when using --dependency_out=FILE."
-         << endl;
+    std::cerr
+        << "Can only process one input file when using --dependency_out=FILE."
+        << std::endl;
     return PARSE_ARGUMENT_FAIL;
   }
   if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) {
@@ -1054,11 +1056,11 @@
 
   } else if (name == "--dependency_out") {
     if (!dependency_out_name_.empty()) {
-      cerr << name << " may only be passed once." << endl;
+      std::cerr << name << " may only be passed once." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     if (value.empty()) {
-      cerr << name << " requires a non-empty value." << endl;
+      std::cerr << name << " requires a non-empty value." << std::endl;
       return PARSE_ARGUMENT_FAIL;
     }
     dependency_out_name_ = value;
@@ -1272,7 +1274,8 @@
 "                              defined in the given proto files. Groups share\n"
 "                              the same field number space with the parent \n"
 "                              message. Extension ranges are counted as \n"
-"                              occupied fields numbers."  << std::endl;
+"                              occupied fields numbers."
+      << std::endl;
   if (!plugin_prefix_.empty()) {
     std::cerr <<
 "  --plugin=EXECUTABLE         Specifies a plugin executable to use.\n"
@@ -1327,13 +1330,23 @@
       }
       parameters.append(generator_parameters_[output_directive.name]);
     }
-    for (int i = 0; i < parsed_files.size(); i++) {
-      if (!output_directive.generator->Generate(parsed_files[i], parameters,
-                                                generator_context, &error)) {
-        // Generator returned an error.
-        std::cerr << output_directive.name << ": " << parsed_files[i]->name()
-                  << ": " << error << std::endl;
-        return false;
+    if (output_directive.generator->HasGenerateAll()) {
+      if (!output_directive.generator->GenerateAll(
+          parsed_files, parameters, generator_context, &error)) {
+          // Generator returned an error.
+          std::cerr << output_directive.name << ": "
+                    << ": " << error << std::endl;
+          return false;
+      }
+    } else {
+      for (int i = 0; i < parsed_files.size(); i++) {
+        if (!output_directive.generator->Generate(parsed_files[i], parameters,
+                                                  generator_context, &error)) {
+          // Generator returned an error.
+          std::cerr << output_directive.name << ": " << parsed_files[i]->name()
+                    << ": " << error << std::endl;
+          return false;
+        }
       }
     }
   }
@@ -1403,7 +1416,8 @@
       printer.Print(" $disk_file$", "disk_file", disk_file);
       if (i < file_set.file_size() - 1) printer.Print("\\\n");
     } else {
-      cerr << "Unable to identify path for file " << virtual_file << endl;
+      std::cerr << "Unable to identify path for file " << virtual_file
+                << std::endl;
       return false;
     }
   }
@@ -1673,6 +1687,10 @@
     ranges->insert(FieldRange(descriptor->extension_range(i)->start,
                               descriptor->extension_range(i)->end));
   }
+  for (int i = 0; i < descriptor->reserved_range_count(); ++i) {
+    ranges->insert(FieldRange(descriptor->reserved_range(i)->start,
+                              descriptor->reserved_range(i)->end));
+  }
   // Handle the nested messages/groups in declaration order to make it
   // post-order strict.
   for (int i = 0; i < descriptor->nested_type_count(); ++i) {
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index e284c79..23d67e2 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -115,10 +115,15 @@
   // Create a subdirectory within temp_directory_.
   void CreateTempDir(const string& name);
 
+#ifdef PROTOBUF_OPENSOURCE
   // Change working directory to temp directory.
   void SwitchToTempDirectory() {
     File::ChangeWorkingDirectory(temp_directory_);
   }
+#else  // !PROTOBUF_OPENSOURCE
+  // TODO(teboring): Figure out how to change and get working directory in
+  // google3.
+#endif  // !PROTOBUF_OPENSOURCE
 
   void SetInputsAreProtoPathRelative(bool enable) {
     cli_.SetInputsAreProtoPathRelative(enable);
@@ -986,6 +991,7 @@
       "Can only process one input file when using --dependency_out=FILE.\n");
 }
 
+#ifdef PROTOBUF_OPENSOURCE
 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) {
   CreateTempFile("foo.proto",
     "syntax = \"proto2\";\n"
@@ -1011,6 +1017,10 @@
 
   File::ChangeWorkingDirectory(current_working_directory);
 }
+#else  // !PROTOBUF_OPENSOURCE
+// TODO(teboring): Figure out how to change and get working directory in
+// google3.
+#endif  // !PROTOBUF_OPENSOURCE
 
 TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) {
   CreateTempFile("foo.proto",
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 3eb20ab..70d3a60 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -70,12 +70,23 @@
 
 EnumGenerator::~EnumGenerator() {}
 
+void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) {
+  if (!options_.proto_h) {
+    return;
+  }
+  map<string, string> vars;
+  vars["classname"] = classname_;
+  printer->Print(vars, "enum $classname$ : int;\n");
+  printer->Print(vars, "bool $classname$_IsValid(int value);\n");
+}
+
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {
   map<string, string> vars;
   vars["classname"] = classname_;
   vars["short_name"] = descriptor_->name();
+  vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
 
-  printer->Print(vars, "enum $classname$ {\n");
+  printer->Print(vars, "enum $enumbase$ {\n");
   printer->Indent();
 
   const EnumValueDescriptor* min_value = descriptor_->value(0);
@@ -90,7 +101,6 @@
     vars["prefix"] = (descriptor_->containing_type() == NULL) ?
       "" : classname_ + "_";
 
-
     if (i > 0) printer->Print(",\n");
     printer->Print(vars, "$prefix$$name$ = $number$");
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index 1ebd7cf..3e93085 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -60,6 +60,12 @@
 
   // Header stuff.
 
+  // Generate header code to forward-declare the enum. This is for use when
+  // generating other .proto.h files. This code should be placed within the
+  // enum's package namespace, but NOT within any class, even for nested
+  // enums.
+  void GenerateForwardDeclaration(io::Printer* printer);
+
   // Generate header code defining the enum.  This code should be placed
   // within the enum's package namespace, but NOT within any class, even for
   // nested enums.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 7498970..965327b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -242,7 +242,7 @@
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField<int> $name$_;\n");
-  if (descriptor_->options().packed()
+  if (descriptor_->is_packed()
       && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
@@ -352,7 +352,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
-  if (!descriptor_->options().packed()) {
+  if (!descriptor_->is_packed()) {
       // This path is rarely executed, so we use a non-inlined implementation.
     if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
       printer->Print(variables_,
@@ -419,7 +419,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -432,7 +432,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
       "    this->$name$(i), output);\n");
@@ -446,7 +446,7 @@
 
 void RepeatedEnumFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -460,7 +460,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
       "    this->$name$(i), target);\n");
@@ -484,7 +484,7 @@
       "    this->$name$(i));\n"
       "}\n");
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
       "  total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index cd2b6b7..1d7f823 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -82,12 +82,38 @@
   // implementation is empty.
   virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {}
 
+  // Generate prototypes for accessors that will manipulate imported
+  // messages inline.  These are for .proto.h headers.
+  //
+  // In .proto.h mode, the headers of imports are not #included. However,
+  // functions that manipulate the imported message types need access to
+  // the class definition of the imported message, meaning that the headers
+  // must be #included. To get around this, functions that manipulate
+  // imported message objects are defined as dependent functions in a base
+  // template class. By making them dependent template functions, the
+  // function templates will not be instantiated until they are called, so
+  // we can defer to those translation units to #include the necessary
+  // generated headers.
+  //
+  // See:
+  // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
+  //
+  // Most field types don't need this, so the default implementation is empty.
+  virtual void GenerateDependentAccessorDeclarations(
+      io::Printer* printer) const {}
+
   // Generate prototypes for all of the accessor functions related to this
   // field.  These are placed inside the class definition.
   virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
 
+  // Generate inline definitions of depenent accessor functions for this field.
+  // These are placed inside the header after all class definitions.
+  virtual void GenerateDependentInlineAccessorDefinitions(
+    io::Printer* printer) const {}
+
   // Generate inline definitions of accessor functions for this field.
   // These are placed inside the header after all class definitions.
+  // In non-.proto.h mode, this generates dependent accessor functions as well.
   virtual void GenerateInlineAccessorDefinitions(
     io::Printer* printer, bool is_inline) const = 0;
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index a98c7d9..b997a51 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -94,113 +94,10 @@
 FileGenerator::~FileGenerator() {}
 
 void FileGenerator::GenerateHeader(io::Printer* printer) {
-  string filename_identifier = FilenameIdentifier(file_->name());
+  GenerateTopHeaderGuard(printer);
 
-  // Generate top of header.
-  printer->Print(
-    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
-    "// source: $filename$\n"
-    "\n"
-    "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
-    "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
-    "\n"
-    "#include <string>\n"
-    "\n",
-    "filename", file_->name(),
-    "filename_identifier", filename_identifier);
-
-
-  printer->Print(
-    "#include <google/protobuf/stubs/common.h>\n"
-    "\n");
-
-  // Verify the protobuf library header version is compatible with the protoc
-  // version before going any further.
-  printer->Print(
-    "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
-    "#error This file was generated by a newer version of protoc which is\n"
-    "#error incompatible with your Protocol Buffer headers.  Please update\n"
-    "#error your headers.\n"
-    "#endif\n"
-    "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
-    "#error This file was generated by an older version of protoc which is\n"
-    "#error incompatible with your Protocol Buffer headers.  Please\n"
-    "#error regenerate this file with a newer version of protoc.\n"
-    "#endif\n"
-    "\n",
-    "min_header_version",
-      SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
-    "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
-
-  // OK, it's now safe to #include other files.
-  printer->Print(
-    "#include <google/protobuf/arena.h>\n"
-    "#include <google/protobuf/arenastring.h>\n"
-    "#include <google/protobuf/generated_message_util.h>\n");
-  if (UseUnknownFieldSet(file_)) {
-    printer->Print(
-      "#include <google/protobuf/metadata.h>\n");
-  }
-  if (file_->message_type_count() > 0) {
-    if (HasDescriptorMethods(file_)) {
-      printer->Print(
-        "#include <google/protobuf/message.h>\n");
-    } else {
-      printer->Print(
-        "#include <google/protobuf/message_lite.h>\n");
-    }
-  }
-  printer->Print(
-    "#include <google/protobuf/repeated_field.h>\n"
-    "#include <google/protobuf/extension_set.h>\n");
-  if (HasMapFields(file_)) {
-    printer->Print(
-        "#include <google/protobuf/map.h>\n");
-    if (HasDescriptorMethods(file_)) {
-      printer->Print(
-          "#include <google/protobuf/map_field_inl.h>\n");
-    } else {
-      printer->Print(
-          "#include <google/protobuf/map_field_lite.h>\n");
-    }
-  }
-
-  if (HasEnumDefinitions(file_)) {
-    if (HasDescriptorMethods(file_)) {
-      printer->Print(
-          "#include <google/protobuf/generated_enum_reflection.h>\n");
-    } else {
-      printer->Print(
-          "#include <google/protobuf/generated_enum_util.h>\n");
-    }
-  }
-
-  if (HasGenericServices(file_)) {
-    printer->Print(
-      "#include <google/protobuf/service.h>\n");
-  }
-
-  if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
-    printer->Print(
-      "#include <google/protobuf/unknown_field_set.h>\n");
-  }
-
-
-  set<string> public_import_names;
-  for (int i = 0; i < file_->public_dependency_count(); i++) {
-    public_import_names.insert(file_->public_dependency(i)->name());
-  }
-
-  for (int i = 0; i < file_->dependency_count(); i++) {
-    const string& name = file_->dependency(i)->name();
-    bool public_import = (public_import_names.count(name) != 0);
-
-
-    printer->Print(
-      "#include \"$dependency$.pb.h\"$iwyu$\n",
-      "dependency", StripProto(name),
-      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
-  }
+  GenerateLibraryIncludes(printer);
+  GenerateDependencyIncludes(printer);
 
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
@@ -210,132 +107,44 @@
   // Open namespace.
   GenerateNamespaceOpeners(printer);
 
-  // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
-  // functions, so that we can declare them to be friends of each class.
-  printer->Print(
-    "\n"
-    "// Internal implementation detail -- do not call these.\n"
-    "void $dllexport_decl$$adddescriptorsname$();\n",
-    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
-    "dllexport_decl",
-    options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
-
-  printer->Print(
-    // Note that we don't put dllexport_decl on these because they are only
-    // called by the .pb.cc file in which they are defined.
-    "void $assigndescriptorsname$();\n"
-    "void $shutdownfilename$();\n"
-    "\n",
-    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
-    "shutdownfilename", GlobalShutdownFileName(file_->name()));
-
-  // Generate forward declarations of classes.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateForwardDeclaration(printer);
-  }
+  GenerateGlobalStateFunctionDeclarations(printer);
+  GenerateMessageForwardDeclarations(printer);
 
   printer->Print("\n");
 
-  // Generate enum definitions.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateEnumDefinitions(printer);
-  }
-  for (int i = 0; i < file_->enum_type_count(); i++) {
-    enum_generators_[i]->GenerateDefinition(printer);
-  }
+  GenerateEnumDefinitions(printer);
 
   printer->Print(kThickSeparator);
   printer->Print("\n");
 
-  // Generate class definitions.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    if (i > 0) {
-      printer->Print("\n");
-      printer->Print(kThinSeparator);
-      printer->Print("\n");
-    }
-    message_generators_[i]->GenerateClassDefinition(printer);
-  }
+  GenerateMessageDefinitions(printer);
 
   printer->Print("\n");
   printer->Print(kThickSeparator);
   printer->Print("\n");
 
-  if (HasGenericServices(file_)) {
-    // Generate service definitions.
-    for (int i = 0; i < file_->service_count(); i++) {
-      if (i > 0) {
-        printer->Print("\n");
-        printer->Print(kThinSeparator);
-        printer->Print("\n");
-      }
-      service_generators_[i]->GenerateDeclarations(printer);
-    }
+  GenerateServiceDefinitions(printer);
 
-    printer->Print("\n");
-    printer->Print(kThickSeparator);
-    printer->Print("\n");
-  }
-
-  // Declare extension identifiers.
-  for (int i = 0; i < file_->extension_count(); i++) {
-    extension_generators_[i]->GenerateDeclaration(printer);
-  }
+  GenerateExtensionIdentifiers(printer);
 
   printer->Print("\n");
   printer->Print(kThickSeparator);
   printer->Print("\n");
 
-  printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
-  // Generate class inline methods.
-  for (int i = 0; i < file_->message_type_count(); i++) {
-    if (i > 0) {
-      printer->Print(kThinSeparator);
-      printer->Print("\n");
-    }
-    message_generators_[i]->GenerateInlineMethods(printer,
-                                                  /* is_inline = */ true);
-  }
-  printer->Print("#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
-
-  printer->Print(
-    "\n"
-    "// @@protoc_insertion_point(namespace_scope)\n");
+  GenerateInlineFunctionDefinitions(printer);
 
   // Close up namespace.
   GenerateNamespaceClosers(printer);
 
-  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
-  if (HasEnumDefinitions(file_)) {
-    // The SWIG conditional is to avoid a null-pointer dereference
-    // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
-    //   namespace X { void Y<Z::W>(); }
-    // which appears in GetEnumDescriptor() specializations.
-    printer->Print(
-        "\n"
-        "#ifndef SWIG\n"
-        "namespace google {\nnamespace protobuf {\n"
-        "\n");
-    for (int i = 0; i < file_->message_type_count(); i++) {
-      message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
-    }
-    for (int i = 0; i < file_->enum_type_count(); i++) {
-      enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
-    }
-    printer->Print(
-        "\n"
-        "}  // namespace protobuf\n}  // namespace google\n"
-        "#endif  // SWIG\n");
-  }
+  // We need to specialize some templates in the ::google::protobuf namespace:
+  GenerateProto2NamespaceEnumSpecializations(printer);
 
   printer->Print(
     "\n"
     "// @@protoc_insertion_point(global_scope)\n"
     "\n");
 
-  printer->Print(
-    "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
-    "filename_identifier", filename_identifier);
+  GenerateBottomHeaderGuard(printer);
 }
 
 void FileGenerator::GenerateSource(io::Printer* printer) {
@@ -707,6 +516,294 @@
   }
 }
 
+void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) {
+  string filename_identifier = FilenameIdentifier(file_->name());
+  // Generate top of header.
+  printer->Print(
+    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "// source: $filename$\n"
+    "\n"
+    "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
+    "#define PROTOBUF_$filename_identifier$__INCLUDED\n"
+    "\n"
+    "#include <string>\n"
+    "\n",
+    "filename", file_->name(),
+    "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) {
+  string filename_identifier = FilenameIdentifier(file_->name());
+  printer->Print(
+    "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
+    "filename_identifier", filename_identifier);
+}
+
+void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
+
+  printer->Print(
+    "#include <google/protobuf/stubs/common.h>\n"
+    "\n");
+
+  // Verify the protobuf library header version is compatible with the protoc
+  // version before going any further.
+  printer->Print(
+    "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
+    "#error This file was generated by a newer version of protoc which is\n"
+    "#error incompatible with your Protocol Buffer headers.  Please update\n"
+    "#error your headers.\n"
+    "#endif\n"
+    "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
+    "#error This file was generated by an older version of protoc which is\n"
+    "#error incompatible with your Protocol Buffer headers.  Please\n"
+    "#error regenerate this file with a newer version of protoc.\n"
+    "#endif\n"
+    "\n",
+    "min_header_version",
+      SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
+    "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
+
+  // OK, it's now safe to #include other files.
+  printer->Print(
+    "#include <google/protobuf/arena.h>\n"
+    "#include <google/protobuf/arenastring.h>\n"
+    "#include <google/protobuf/generated_message_util.h>\n");
+  if (UseUnknownFieldSet(file_)) {
+    printer->Print(
+      "#include <google/protobuf/metadata.h>\n");
+  }
+  if (file_->message_type_count() > 0) {
+    if (HasDescriptorMethods(file_)) {
+      printer->Print(
+        "#include <google/protobuf/message.h>\n");
+    } else {
+      printer->Print(
+        "#include <google/protobuf/message_lite.h>\n");
+    }
+  }
+  printer->Print(
+    "#include <google/protobuf/repeated_field.h>\n"
+    "#include <google/protobuf/extension_set.h>\n");
+  if (HasMapFields(file_)) {
+    printer->Print(
+        "#include <google/protobuf/map.h>\n");
+    if (HasDescriptorMethods(file_)) {
+      printer->Print(
+          "#include <google/protobuf/map_field_inl.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/map_field_lite.h>\n");
+    }
+  }
+
+  if (HasEnumDefinitions(file_)) {
+    if (HasDescriptorMethods(file_)) {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_reflection.h>\n");
+    } else {
+      printer->Print(
+          "#include <google/protobuf/generated_enum_util.h>\n");
+    }
+  }
+
+  if (HasGenericServices(file_)) {
+    printer->Print(
+      "#include <google/protobuf/service.h>\n");
+  }
+
+  if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
+    printer->Print(
+      "#include <google/protobuf/unknown_field_set.h>\n");
+  }
+
+
+  if (IsAnyMessage(file_)) {
+    printer->Print(
+      "#include \"google/protobuf/any.h\"\n");
+  }
+}
+
+void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
+  set<string> public_import_names;
+  for (int i = 0; i < file_->public_dependency_count(); i++) {
+    public_import_names.insert(file_->public_dependency(i)->name());
+  }
+
+  for (int i = 0; i < file_->dependency_count(); i++) {
+    const string& name = file_->dependency(i)->name();
+    bool public_import = (public_import_names.count(name) != 0);
+
+
+    printer->Print(
+      "#include \"$dependency$.pb.h\"$iwyu$\n",
+      "dependency", StripProto(name),
+      "iwyu", (public_import) ? "  // IWYU pragma: export" : "");
+  }
+}
+
+void FileGenerator::GenerateGlobalStateFunctionDeclarations(
+    io::Printer* printer) {
+  // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
+  // functions, so that we can declare them to be friends of each class.
+  printer->Print(
+    "\n"
+    "// Internal implementation detail -- do not call these.\n"
+    "void $dllexport_decl$$adddescriptorsname$();\n",
+    "adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
+    "dllexport_decl",
+    options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
+
+  printer->Print(
+    // Note that we don't put dllexport_decl on these because they are only
+    // called by the .pb.cc file in which they are defined.
+    "void $assigndescriptorsname$();\n"
+    "void $shutdownfilename$();\n"
+    "\n",
+    "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
+    "shutdownfilename", GlobalShutdownFileName(file_->name()));
+}
+
+void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
+  // Generate forward declarations of classes.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateMessageForwardDeclaration(printer);
+  }
+}
+
+void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
+  // Generate class definitions.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print("\n");
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    message_generators_[i]->GenerateClassDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
+  // Generate enum definitions.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    message_generators_[i]->GenerateEnumDefinitions(printer);
+  }
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    enum_generators_[i]->GenerateDefinition(printer);
+  }
+}
+
+void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
+  if (HasGenericServices(file_)) {
+    // Generate service definitions.
+    for (int i = 0; i < file_->service_count(); i++) {
+      if (i > 0) {
+        printer->Print("\n");
+        printer->Print(kThinSeparator);
+        printer->Print("\n");
+      }
+      service_generators_[i]->GenerateDeclarations(printer);
+    }
+
+    printer->Print("\n");
+    printer->Print(kThickSeparator);
+    printer->Print("\n");
+  }
+}
+
+void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
+  // Declare extension identifiers.
+  for (int i = 0; i < file_->extension_count(); i++) {
+    extension_generators_[i]->GenerateDeclaration(printer);
+  }
+}
+
+void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
+  // An aside about inline functions in .proto.h mode:
+  //
+  // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally
+  // moving much of the inline functions to the .pb.cc file, which can be a
+  // significant performance benefit for compilation time, at the expense
+  // of non-inline function calls.
+  //
+  // However, in .proto.h mode, the definition of the internal dependent
+  // base class must remain in the header, and can never be out-lined. The
+  // dependent base class also needs access to has-bit manipuation
+  // functions, so the has-bit functions must be unconditionally inlined in
+  // proto_h mode.
+  //
+  // This gives us three flavors of functions:
+  //
+  //  1. Functions on the message not used by the internal dependent base
+  //     class: in .proto.h mode, only some functions are defined on the
+  //     message class; others are defined on the dependent base class.
+  //     These are guarded and can be out-lined. These are generated by
+  //     GenerateInlineMethods, and include has_* bit functions in
+  //     non-proto_h mode.
+  //
+  //  2. Functions on the internal dependent base class: these functions
+  //     are dependent on a template parameter, so they always need to
+  //     remain in the header.
+  //
+  //  3. Functions on the message that are used by the dependent base: the
+  //     dependent base class down casts itself to the message
+  //     implementation class to access these functions (the has_* bit
+  //     manipulation functions). Unlike #1, these functions must
+  //     unconditionally remain in the header. These are emitted by
+  //     GenerateDependentInlineMethods, even though they are not actually
+  //     dependent.
+
+  printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+  // Generate class inline methods.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    message_generators_[i]->GenerateInlineMethods(printer,
+                                                  /* is_inline = */ true);
+  }
+  printer->Print("#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS\n");
+
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (i > 0) {
+      printer->Print(kThinSeparator);
+      printer->Print("\n");
+    }
+    // Methods of the dependent base class must always be inline in the header.
+    message_generators_[i]->GenerateDependentInlineMethods(printer);
+  }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(namespace_scope)\n");
+}
+
+void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
+    io::Printer* printer) {
+  // Emit GetEnumDescriptor specializations into google::protobuf namespace:
+  if (HasEnumDefinitions(file_)) {
+    // The SWIG conditional is to avoid a null-pointer dereference
+    // (bug 1984964) in swig-1.3.21 resulting from the following syntax:
+    //   namespace X { void Y<Z::W>(); }
+    // which appears in GetEnumDescriptor() specializations.
+    printer->Print(
+        "\n"
+        "#ifndef SWIG\n"
+        "namespace google {\nnamespace protobuf {\n"
+        "\n");
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
+    }
+    printer->Print(
+        "\n"
+        "}  // namespace protobuf\n}  // namespace google\n"
+        "#endif  // SWIG\n");
+  }
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 0e06547..e68f67b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -80,6 +80,35 @@
   void GenerateNamespaceOpeners(io::Printer* printer);
   void GenerateNamespaceClosers(io::Printer* printer);
 
+  // Generates top or bottom of a header file.
+  void GenerateTopHeaderGuard(io::Printer* printer);
+  void GenerateBottomHeaderGuard(io::Printer* printer);
+
+  // Generates #include directives.
+  void GenerateLibraryIncludes(io::Printer* printer);
+  void GenerateDependencyIncludes(io::Printer* printer);
+
+  // Generates a couple of different pieces before definitions:
+  void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
+
+  // Generates types for classes.
+  void GenerateMessageForwardDeclarations(io::Printer* printer);
+  void GenerateMessageDefinitions(io::Printer* printer);
+
+  // Generates enum definitions.
+  void GenerateEnumDefinitions(io::Printer* printer);
+
+  // Generates generic service definitions.
+  void GenerateServiceDefinitions(io::Printer* printer);
+
+  // Generates extension identifiers.
+  void GenerateExtensionIdentifiers(io::Printer* printer);
+
+  // Generates inline function defintions.
+  void GenerateInlineFunctionDefinitions(io::Printer* printer);
+
+  void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer);
+
   const FileDescriptor* file_;
 
   google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index c999b93..9941637 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -82,6 +82,7 @@
   //   }
   // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
   // __declspec(dllimport) depending on what is being compiled.
+  //
   Options file_options;
 
   for (int i = 0; i < options.size(); i++) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 4e7155c..0f3688d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -51,6 +51,9 @@
 
 namespace {
 
+static const char kAnyMessageName[] = "Any";
+static const char kAnyProtoFile[] = "google/protobuf/any.proto";
+
 string DotsToUnderscores(const string& name) {
   return StringReplace(name, ".", "_", true);
 }
@@ -162,6 +165,10 @@
 }
 
 
+string DependentBaseClassTemplateName(const Descriptor* descriptor) {
+  return ClassName(descriptor, false) + "_InternalBase";
+}
+
 string SuperClassName(const Descriptor* descriptor) {
   return HasDescriptorMethods(descriptor->file()) ?
       "::google::protobuf::Message" : "::google::protobuf::MessageLite";
@@ -200,6 +207,47 @@
   return result;
 }
 
+bool IsFieldDependent(const FieldDescriptor* field) {
+  if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
+    return false;
+  }
+  if (field->containing_oneof() != NULL) {
+    // Oneof fields will always be dependent.
+    //
+    // This is a unique case for field codegen. Field generators are
+    // responsible for generating all the field-specific accessor
+    // functions, except for the clear_*() function; instead, field
+    // generators produce inline clearing code.
+    //
+    // For non-oneof fields, the Message class uses the inline clearing
+    // code to define the field's clear_*() function, as well as in the
+    // destructor. For oneof fields, the Message class generates a much
+    // more complicated clear_*() function, which clears only the oneof
+    // member that is set, in addition to clearing methods for each of the
+    // oneof members individually.
+    //
+    // Since oneofs do not have their own generator class, the Message code
+    // generation logic would be significantly complicated in order to
+    // split dependent and non-dependent manipulation logic based on
+    // whether the oneof truly needs to be dependent; so, for oneof fields,
+    // we just assume it (and its constituents) should be manipulated by a
+    // dependent base class function.
+    //
+    // This is less precise than how dependent message-typed fields are
+    // handled, but the cost is limited to only the generated code for the
+    // oneof field, which seems like an acceptable tradeoff.
+    return true;
+  }
+  if (field->file() == field->message_type()->file()) {
+    return false;
+  }
+  return true;
+}
+
+string DependentTypeName(const FieldDescriptor* field) {
+  return "InternalBase_" + field->name() + "_T";
+}
+
 string FieldMessageTypeName(const FieldDescriptor* field) {
   // Note:  The Google-internal version of Protocol Buffers uses this function
   //   as a hook point for hacks to support legacy code.
@@ -360,7 +408,7 @@
     } else {
       // Not alphanumeric.  To avoid any possibility of name conflicts we
       // use the hex code for the character.
-      StrAppend(&result, "_", ToHex(static_cast<uint8>(filename[i])));
+      StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
     }
   }
   return result;
@@ -521,6 +569,15 @@
 
 }
 
+bool IsAnyMessage(const FileDescriptor* descriptor) {
+  return descriptor->name() == kAnyProtoFile;
+}
+
+bool IsAnyMessage(const Descriptor* descriptor) {
+  return descriptor->name() == kAnyMessageName &&
+         descriptor->file()->name() == kAnyProtoFile;
+}
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 284fa2c..4bbf830 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -66,6 +66,10 @@
 string ClassName(const Descriptor* descriptor, bool qualified);
 string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
 
+// Name of the CRTP class template (for use with proto_h).
+// This is a class name, like "ProtoName_InternalBase".
+string DependentBaseClassTemplateName(const Descriptor* descriptor);
+
 string SuperClassName(const Descriptor* descriptor);
 
 // Get the (unqualified) name that should be used for this field in C++ code.
@@ -88,6 +92,20 @@
     field->extension_scope() : field->containing_type();
 }
 
+// Returns true if the given 'field_descriptor' has a message type that is
+// a dependency of the file where the field is defined (i.e., the field
+// type is defined in a different file than the message holding the field).
+//
+// This only applies to Message-typed fields. Enum-typed fields may refer
+// to an enum in a dependency; however, enums are specified and
+// forward-declared with an enum-base, so the definition is not required to
+// manipulate the field value.
+bool IsFieldDependent(const FieldDescriptor* field_descriptor);
+
+// Returns the name that should be used for forcing dependent lookup from a
+// dependent base class.
+string DependentTypeName(const FieldDescriptor* field);
+
 // Returns the fully-qualified type name field->message_type().  Usually this
 // is just ClassName(field->message_type(), true);
 string FieldMessageTypeName(const FieldDescriptor* field);
@@ -242,6 +260,9 @@
   return SupportsArenas(field->file());
 }
 
+bool IsAnyMessage(const FileDescriptor* descriptor);
+bool IsAnyMessage(const Descriptor* descriptor);
+
 }  // namespace cpp
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 8c38db2..0ff0d27 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -244,7 +244,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
 
   // If entry is allocated by arena, its desctructor should be avoided.
   if (SupportsArenas(descriptor_)) {
@@ -277,7 +278,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
 
   // If entry is allocated by arena, its desctructor should be avoided.
   if (SupportsArenas(descriptor_)) {
@@ -312,7 +314,8 @@
       "{\n"
       "  ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
       "  for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
-      "      it = $name$().begin(); it != $name$().end(); ++it) {\n");
+      "      it = this->$name$().begin();\n"
+      "      it != this->$name$().end(); ++it) {\n");
 
   // If entry is allocated by arena, its desctructor should be avoided.
   if (SupportsArenas(descriptor_)) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 98929b1..212fe2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -64,10 +64,15 @@
 
 namespace {
 
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
-  // Print the field's proto-syntax definition as a comment.  We don't want to
-  // print group bodies so we cut off after the first line.
-  string def = field->DebugString();
+template <class T>
+void PrintFieldComment(io::Printer* printer, const T* field) {
+  // Print the field's (or oneof's) proto-syntax definition as a comment.
+  // We don't want to print group bodies so we cut off after the first
+  // line.
+  DebugStringOptions options;
+  options.elide_group_body = true;
+  options.elide_oneof_body = true;
+  string def = field->DebugStringWithOptions(options);
   printer->Print("// $def$\n",
     "def", def.substr(0, def.find_first_of('\n')));
 }
@@ -280,6 +285,10 @@
   }
 }
 
+string MessageTypeProtoName(const FieldDescriptor* field) {
+  return field->message_type()->full_name();
+}
+
 // Emits an if-statement with a condition that evaluates to true if |field| is
 // considered non-default (will be sent over the wire), for message types
 // without true field presence. Should only be called if
@@ -379,7 +388,8 @@
       enum_generators_(
           new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
       extension_generators_(new google::protobuf::scoped_ptr<
-          ExtensionGenerator>[descriptor->extension_count()]) {
+          ExtensionGenerator>[descriptor->extension_count()]),
+      use_dependent_base_(false) {
 
   for (int i = 0; i < descriptor->nested_type_count(); i++) {
     nested_generators_[i].reset(
@@ -401,13 +411,16 @@
     if (descriptor->field(i)->is_required()) {
       ++num_required_fields_;
     }
+    if (options.proto_h && IsFieldDependent(descriptor->field(i))) {
+      use_dependent_base_ = true;
+    }
   }
 }
 
 MessageGenerator::~MessageGenerator() {}
 
 void MessageGenerator::
-GenerateForwardDeclaration(io::Printer* printer) {
+GenerateMessageForwardDeclaration(io::Printer* printer) {
   printer->Print("class $classname$;\n",
                  "classname", classname_);
 
@@ -416,7 +429,17 @@
     // message cannot be a top level class, we just need to avoid calling
     // GenerateForwardDeclaration here.
     if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
-    nested_generators_[i]->GenerateForwardDeclaration(printer);
+    nested_generators_[i]->GenerateMessageForwardDeclaration(printer);
+  }
+}
+
+void MessageGenerator::
+GenerateEnumForwardDeclaration(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    nested_generators_[i]->GenerateEnumForwardDeclaration(printer);
+  }
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    enum_generators_[i]->GenerateForwardDeclaration(printer);
   }
 }
 
@@ -442,6 +465,35 @@
 }
 
 void MessageGenerator::
+GenerateDependentFieldAccessorDeclarations(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    PrintFieldComment(printer, field);
+
+    map<string, string> vars;
+    SetCommonFieldVariables(field, &vars, options_);
+
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      // If the message is dependent, the inline clear_*() method will need
+      // to delete the message type, so it must be in the dependent base
+      // class. (See also GenerateFieldAccessorDeclarations.)
+      printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+    }
+    // Generate type-specific accessor declarations.
+    field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
+    printer->Print("\n");
+  }
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    const OneofDescriptor* oneof = descriptor_->oneof_decl(i);
+    PrintFieldComment(printer, oneof);
+    printer->Print(
+      "void clear_$oneof_name$();\n",
+      "oneof_name", oneof->name());
+  }
+}
+
+void MessageGenerator::
 GenerateFieldAccessorDeclarations(io::Printer* printer) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
@@ -452,6 +504,19 @@
     SetCommonFieldVariables(field, &vars, options_);
     vars["constant_name"] = FieldConstantName(field);
 
+    bool dependent_field = use_dependent_base_ && IsFieldDependent(field);
+    if (dependent_field) {
+      // If this field is dependent, the dependent base class determines
+      // the message type from the derived class (which is a template
+      // parameter). This typedef is for that:
+      printer->Print(
+          "private:\n"
+          "typedef $field_type$ $dependent_type$;\n"
+          "public:\n",
+          "field_type", FieldMessageTypeName(field),
+          "dependent_type", DependentTypeName(field));
+    }
+
     if (field->is_repeated()) {
       printer->Print(vars, "int $name$_size() const$deprecation$;\n");
     } else if (HasHasMethod(field)) {
@@ -463,7 +528,11 @@
           "public:\n");
     }
 
-    printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+    if (!dependent_field) {
+      // If this field is dependent, then its clear_() method is in the
+      // depenent base class. (See also GenerateDependentAccessorDeclarations.)
+      printer->Print(vars, "void clear_$name$()$deprecation$;\n");
+    }
     printer->Print(vars, "static const int $constant_name$ = $number$;\n");
 
     // Generate type-specific accessor declarations.
@@ -490,6 +559,188 @@
 }
 
 void MessageGenerator::
+GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
+  if (!use_dependent_base_) return;
+
+  printer->Print("// $classname$\n\n", "classname",
+                 DependentBaseClassTemplateName(descriptor_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    PrintFieldComment(printer, field);
+
+    // These functions are not really dependent: they are part of the
+    // (non-dependent) derived class. However, they need to live outside
+    // any #ifdef guards, so we treat them as if they were dependent.
+    //
+    // See the comment in FileGenerator::GenerateInlineFunctionDefinitions
+    // for a more complete explanation.
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      map<string, string> vars;
+      SetCommonFieldVariables(field, &vars, options_);
+      vars["inline"] = "inline ";
+      if (field->containing_oneof()) {
+        vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
+        vars["oneof_name"] = field->containing_oneof()->name();
+        vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
+        GenerateOneofMemberHasBits(field, vars, printer);
+      } else if (!field->is_repeated()) {
+        // There will be no header guard, so this always has to be inline.
+        GenerateSingularFieldHasBits(field, vars, printer);
+      }
+      // vars needed for clear_(), which is in the dependent base:
+      // (See also GenerateDependentFieldAccessorDeclarations.)
+      vars["tmpl"] = "template<class T>\n";
+      vars["dependent_classname"] =
+          DependentBaseClassTemplateName(descriptor_) + "<T>";
+      vars["this_message"] = "reinterpret_cast<T*>(this)->";
+      vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+      GenerateFieldClear(field, vars, printer);
+    }
+
+    // Generate type-specific accessors.
+    field_generators_.get(field)
+        .GenerateDependentInlineAccessorDefinitions(printer);
+
+    printer->Print("\n");
+  }
+
+  // Generate has_$name$() and clear_has_$name$() functions for oneofs
+  // Similar to other has-bits, these must always be in the header if we
+  // are using a dependent base class.
+  GenerateOneofHasBits(printer, true /* is_inline */);
+}
+
+void MessageGenerator::
+GenerateSingularFieldHasBits(const FieldDescriptor* field,
+                             map<string, string> vars,
+                             io::Printer* printer) {
+  if (HasFieldPresence(descriptor_->file())) {
+    // N.B.: without field presence, we do not use has-bits or generate
+    // has_$name$() methods.
+    vars["has_array_index"] = SimpleItoa(field->index() / 32);
+    vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32),
+                                           strings::Hex::ZERO_PAD_8));
+    printer->Print(vars,
+      "$inline$"
+      "bool $classname$::has_$name$() const {\n"
+      "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+      "}\n"
+      "$inline$"
+      "void $classname$::set_has_$name$() {\n"
+      "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
+      "}\n"
+      "$inline$"
+      "void $classname$::clear_has_$name$() {\n"
+      "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
+      "}\n");
+  } else {
+    // Message fields have a has_$name$() method.
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      bool is_lazy = false;
+      if (is_lazy) {
+        printer->Print(vars,
+          "$inline$"
+          "bool $classname$::has_$name$() const {\n"
+          "  return !$name$_.IsCleared();\n"
+          "}\n");
+      } else {
+        printer->Print(vars,
+          "$inline$"
+          "bool $classname$::has_$name$() const {\n"
+          "  return !_is_default_instance_ && $name$_ != NULL;\n"
+          "}\n");
+      }
+    }
+  }
+}
+
+void MessageGenerator::
+GenerateOneofHasBits(io::Printer* printer, bool is_inline) {
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    map<string, string> vars;
+    vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    vars["cap_oneof_name"] =
+        ToUpper(descriptor_->oneof_decl(i)->name());
+    vars["classname"] = classname_;
+    vars["inline"] = (is_inline ? "inline " : "");
+    printer->Print(
+        vars,
+        "$inline$"
+        "bool $classname$::has_$oneof_name$() const {\n"
+        "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
+        "}\n"
+        "$inline$"
+        "void $classname$::clear_has_$oneof_name$() {\n"
+        "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
+        "}\n");
+  }
+}
+
+void MessageGenerator::
+GenerateOneofMemberHasBits(const FieldDescriptor* field,
+                           const map<string, string>& vars,
+                           io::Printer* printer) {
+  // Singular field in a oneof
+  // N.B.: Without field presence, we do not use has-bits or generate
+  // has_$name$() methods, but oneofs still have set_has_$name$().
+  // Oneofs also have has_$name$() but only as a private helper
+  // method, so that generated code is slightly cleaner (vs.  comparing
+  // _oneof_case_[index] against a constant everywhere).
+  printer->Print(vars,
+    "$inline$"
+    "bool $classname$::has_$name$() const {\n"
+    "  return $oneof_name$_case() == k$field_name$;\n"
+    "}\n");
+  printer->Print(vars,
+    "$inline$"
+    "void $classname$::set_has_$name$() {\n"
+    "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
+    "}\n");
+}
+
+void MessageGenerator::
+GenerateFieldClear(const FieldDescriptor* field,
+                   const map<string, string>& vars,
+                   io::Printer* printer) {
+  // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and
+  // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is
+  // set by the Generate*Definitions functions.)
+  printer->Print(vars,
+    "$tmpl$"
+    "$inline$"
+    "void $dependent_classname$::clear_$name$() {\n");
+
+  printer->Indent();
+
+  if (field->containing_oneof()) {
+    // Clear this field only if it is the active field in this oneof,
+    // otherwise ignore
+    printer->Print(vars,
+      "if ($this_message$has_$name$()) {\n");
+    printer->Indent();
+    field_generators_.get(field).GenerateClearingCode(printer);
+    printer->Print(vars,
+      "$this_message$clear_has_$oneof_name$();\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  } else {
+    field_generators_.get(field).GenerateClearingCode(printer);
+    if (HasFieldPresence(descriptor_->file())) {
+      if (!field->is_repeated()) {
+        printer->Print(vars,
+                       "$this_message$clear_has_$name$();\n");
+      }
+    }
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void MessageGenerator::
 GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
   printer->Print("// $classname$\n\n", "classname", classname_);
 
@@ -500,101 +751,37 @@
 
     map<string, string> vars;
     SetCommonFieldVariables(field, &vars, options_);
-    vars["inline"] = is_inline ? "inline" : "";
+    vars["inline"] = is_inline ? "inline " : "";
 
     // Generate has_$name$() or $name$_size().
     if (field->is_repeated()) {
       printer->Print(vars,
-        "$inline$ int $classname$::$name$_size() const {\n"
+        "$inline$"
+        "int $classname$::$name$_size() const {\n"
         "  return $name$_.size();\n"
         "}\n");
     } else if (field->containing_oneof()) {
-      // Singular field in a oneof
-      // N.B.: Without field presence, we do not use has-bits or generate
-      // has_$name$() methods, but oneofs still have set_has_$name$().
-      // Oneofs also have has_$name$() but only as a private helper
-      // method, so that generated code is slightly cleaner (vs.  comparing
-      // _oneof_case_[index] against a constant everywhere).
       vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
       vars["oneof_name"] = field->containing_oneof()->name();
       vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
-      printer->Print(vars,
-        "$inline$ bool $classname$::has_$name$() const {\n"
-        "  return $oneof_name$_case() == k$field_name$;\n"
-        "}\n");
-      printer->Print(vars,
-        "$inline$ void $classname$::set_has_$name$() {\n"
-        "  _oneof_case_[$oneof_index$] = k$field_name$;\n"
-        "}\n");
+      if (!use_dependent_base_ || !IsFieldDependent(field)) {
+        GenerateOneofMemberHasBits(field, vars, printer);
+      }
     } else {
       // Singular field.
-      if (HasFieldPresence(descriptor_->file())) {
-        // N.B.: without field presence, we do not use has-bits or generate
-        // has_$name$() methods.
-        char buffer[kFastToBufferSize];
-        vars["has_array_index"] = SimpleItoa(field->index() / 32);
-        vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
-                                             buffer);
-        printer->Print(vars,
-          "$inline$ bool $classname$::has_$name$() const {\n"
-          "  return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
-          "}\n"
-          "$inline$ void $classname$::set_has_$name$() {\n"
-          "  _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
-          "}\n"
-          "$inline$ void $classname$::clear_has_$name$() {\n"
-          "  _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
-          "}\n"
-          );
-      } else {
-        // Message fields have a has_$name$() method.
-        if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-          bool is_lazy = false;
-          if (is_lazy) {
-            printer->Print(vars,
-              "$inline$ bool $classname$::has_$name$() const {\n"
-              "  return !$name$_.IsCleared();\n"
-              "}\n");
-          } else {
-            printer->Print(vars,
-              "$inline$ bool $classname$::has_$name$() const {\n"
-              "  return !_is_default_instance_ && $name$_ != NULL;\n"
-              "}\n");
-          }
-        }
+      if (!use_dependent_base_ || !IsFieldDependent(field)) {
+        GenerateSingularFieldHasBits(field, vars, printer);
       }
     }
 
-    // Generate clear_$name$()
-    printer->Print(vars,
-      "$inline$ void $classname$::clear_$name$() {\n");
-
-    printer->Indent();
-
-    if (field->containing_oneof()) {
-      // Clear this field only if it is the active field in this oneof,
-      // otherwise ignore
-      printer->Print(vars,
-        "if (has_$name$()) {\n");
-      printer->Indent();
-      field_generators_.get(field).GenerateClearingCode(printer);
-      printer->Print(vars,
-        "clear_has_$oneof_name$();\n");
-      printer->Outdent();
-      printer->Print("}\n");
-    } else {
-      field_generators_.get(field).GenerateClearingCode(printer);
-      if (HasFieldPresence(descriptor_->file())) {
-        if (!field->is_repeated()) {
-          printer->Print(vars,
-                         "clear_has_$name$();\n");
-        }
-      }
+    if (!use_dependent_base_ || !IsFieldDependent(field)) {
+      vars["tmpl"] = "";
+      vars["dependent_classname"] = vars["classname"];
+      vars["this_message"] = "";
+      vars["this_const_message"] = "";
+      GenerateFieldClear(field, vars, printer);
     }
 
-    printer->Outdent();
-    printer->Print("}\n");
-
     // Generate type-specific accessors.
     field_generators_.get(field).GenerateInlineAccessorDefinitions(printer,
                                                                    is_inline);
@@ -602,23 +789,11 @@
     printer->Print("\n");
   }
 
-  // Generate has_$name$() and clear_has_$name$() functions for oneofs
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    map<string, string> vars;
-    vars["oneof_name"] = descriptor_->oneof_decl(i)->name();
-    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
-    vars["cap_oneof_name"] =
-        ToUpper(descriptor_->oneof_decl(i)->name());
-    vars["classname"] = classname_;
-    vars["inline"] = is_inline ? "inline" : "";
-    printer->Print(
-      vars,
-      "$inline$ bool $classname$::has_$oneof_name$() const {\n"
-      "  return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n"
-      "}\n"
-      "$inline$ void $classname$::clear_has_$oneof_name$() {\n"
-      "  _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n"
-      "}\n");
+  if (!use_dependent_base_) {
+    // Generate has_$name$() and clear_has_$name$() functions for oneofs
+    // If we aren't using a dependent base, they can be with the other functions
+    // that are #ifdef-guarded.
+    GenerateOneofHasBits(printer, is_inline);
   }
 }
 
@@ -648,6 +823,34 @@
 }
 
 void MessageGenerator::
+GenerateDependentBaseClassDefinition(io::Printer* printer) {
+  if (!use_dependent_base_) {
+    return;
+  }
+
+  map<string, string> vars;
+  vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+  vars["superclass"] = SuperClassName(descriptor_);
+
+  printer->Print(vars,
+    "template <class T>\n"
+    "class $classname$ : public $superclass$ {\n"
+    " public:\n");
+  printer->Indent();
+
+  printer->Print(vars,
+    "$classname$() {}\n"
+    "virtual ~$classname$() {}\n"
+    "\n");
+
+  // Generate dependent accessor methods for all fields.
+  GenerateDependentFieldAccessorDeclarations(printer);
+
+  printer->Outdent();
+  printer->Print("};\n");
+}
+
+void MessageGenerator::
 GenerateClassDefinition(io::Printer* printer) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // map entry message doesn't need class definition. Since map entry message
@@ -660,6 +863,11 @@
     printer->Print("\n");
   }
 
+  if (use_dependent_base_) {
+    GenerateDependentBaseClassDefinition(printer);
+      printer->Print("\n");
+  }
+
   map<string, string> vars;
   vars["classname"] = classname_;
   vars["field_count"] = SimpleItoa(descriptor_->field_count());
@@ -669,11 +877,18 @@
   } else {
     vars["dllexport"] = options_.dllexport_decl + " ";
   }
-  vars["superclass"] = SuperClassName(descriptor_);
-
+  if (use_dependent_base_) {
+    vars["superclass"] =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
+  } else {
+    vars["superclass"] = SuperClassName(descriptor_);
+  }
   printer->Print(vars,
-    "class $dllexport$$classname$ : public $superclass$ {\n"
-    " public:\n");
+    "class $dllexport$$classname$ : public $superclass$ {\n");
+  if (use_dependent_base_) {
+    printer->Print(vars, "  friend class $superclass$;\n");
+  }
+  printer->Print(" public:\n");
   printer->Indent();
 
   printer->Print(vars,
@@ -782,6 +997,19 @@
     printer->Print(vars,
       "void UnsafeArenaSwap($classname$* other);\n");
   }
+
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(vars,
+      "// implements Any -----------------------------------------------\n"
+      "\n"
+      "void PackFrom(const ::google::protobuf::Message& message);\n"
+      "bool UnpackTo(::google::protobuf::Message* message) const;\n"
+      "template<typename T> bool Is() const {\n"
+      "  return _any_metadata_.Is<T>();\n"
+      "}\n"
+      "\n");
+  }
+
   printer->Print(vars,
     "void Swap($classname$* other);\n"
     "\n"
@@ -973,11 +1201,18 @@
 
   // Generate oneof function declarations
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print(
-        "inline bool has_$oneof_name$() const;\n"
-        "void clear_$oneof_name$();\n"
-        "inline void clear_has_$oneof_name$();\n\n",
-        "oneof_name", descriptor_->oneof_decl(i)->name());
+    if (use_dependent_base_) {
+      printer->Print(
+          "inline bool has_$oneof_name$() const;\n"
+          "inline void clear_has_$oneof_name$();\n\n",
+          "oneof_name", descriptor_->oneof_decl(i)->name());
+    } else {
+      printer->Print(
+          "inline bool has_$oneof_name$() const;\n"
+          "void clear_$oneof_name$();\n"
+          "inline void clear_has_$oneof_name$();\n\n",
+          "oneof_name", descriptor_->oneof_decl(i)->name());
+    }
   }
 
   if (HasGeneratedMethods(descriptor_->file()) &&
@@ -1139,6 +1374,12 @@
       "\n");
   }
 
+  // Generate _any_metadata_ for the Any type.
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(vars,
+      "::google::protobuf::internal::AnyMetadata _any_metadata_;\n");
+  }
+
   // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
   // friends so that they can access private static variables like
   // default_instance_ and reflection_.
@@ -1172,6 +1413,21 @@
 }
 
 void MessageGenerator::
+GenerateDependentInlineMethods(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // map entry message doesn't need inline methods. Since map entry message
+    // cannot be a top level class, we just need to avoid calling
+    // GenerateInlineMethods here.
+    if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
+    nested_generators_[i]->GenerateDependentInlineMethods(printer);
+    printer->Print(kThinSeparator);
+    printer->Print("\n");
+  }
+
+  GenerateDependentFieldAccessorDefinitions(printer);
+}
+
+void MessageGenerator::
 GenerateInlineMethods(io::Printer* printer, bool is_inline) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // map entry message doesn't need inline methods. Since map entry message
@@ -1196,7 +1452,8 @@
     vars["inline"] = is_inline ? "inline " : "";
     printer->Print(
         vars,
-        "$inline$$class_name$::$camel_oneof_name$Case $class_name$::"
+        "$inline$"
+        "$class_name$::$camel_oneof_name$Case $class_name$::"
         "$oneof_name$_case() const {\n"
         "  return $class_name$::$camel_oneof_name$Case("
         "_oneof_case_[$oneof_index$]);\n"
@@ -1494,6 +1751,19 @@
 
 void MessageGenerator::
 GenerateClassMethods(io::Printer* printer) {
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(
+      "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n"
+      "  _any_metadata_.PackFrom(message);\n"
+      "}\n"
+      "\n"
+      "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
+      "  return _any_metadata_.UnpackTo(message);\n"
+      "}\n"
+      "\n",
+      "classname", classname_);
+  }
+
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
     enum_generators_[i]->GenerateMethods(printer);
   }
@@ -1767,7 +2037,7 @@
   if (need_registration) {
     printer->Print(
         "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
-        "  if (arena != NULL) {"
+        "  if (arena != NULL) {\n"
         "    arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
         "  }\n"
         "}\n",
@@ -1782,18 +2052,23 @@
 
 void MessageGenerator::
 GenerateStructors(io::Printer* printer) {
-  string superclass = SuperClassName(descriptor_);
-  string initializer_with_arena;
-  if (UseUnknownFieldSet(descriptor_->file())) {
-    initializer_with_arena = "_internal_metadata_(arena)";
+  string superclass;
+  if (use_dependent_base_) {
+    superclass =
+        DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">";
   } else {
-    initializer_with_arena = "_arena_ptr_(arena)";
+    superclass = SuperClassName(descriptor_);
   }
+  string initializer_with_arena = superclass + "()";
+
   if (descriptor_->extension_range_count() > 0) {
-      initializer_with_arena  = string("\n  _extensions_(arena)") +
-        (!initializer_with_arena.empty() ?  ", " : "") + initializer_with_arena;
+    initializer_with_arena += ",\n  _extensions_(arena)";
+  }
+
+  if (UseUnknownFieldSet(descriptor_->file())) {
+    initializer_with_arena += ",\n  _internal_metadata_(arena)";
   } else {
-    initializer_with_arena  = "\n  " + initializer_with_arena;
+    initializer_with_arena += ",\n  _arena_ptr_(arena)";
   }
 
   // Initialize member variables with arena constructor.
@@ -1804,16 +2079,21 @@
           FieldName(descriptor_->field(i)) + string("_(arena)");
     }
   }
-  initializer_with_arena = superclass + "()" +
-      (!initializer_with_arena.empty() ?  "," : " ") + initializer_with_arena;
+
+  if (IsAnyMessage(descriptor_)) {
+    initializer_with_arena += ",\n  _any_metadata_(&type_url, &value_)";
+  }
 
   string initializer_null;
   initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
-    ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
+    ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)");
+  if (IsAnyMessage(descriptor_)) {
+    initializer_null += ", _any_metadata_(&type_url_, &value_)";
+  }
 
   printer->Print(
       "$classname$::$classname$()\n"
-      "  : $superclass$() $initializer$ {\n"
+      "  : $superclass$()$initializer$ {\n"
       "  SharedCtor();\n"
       "  // @@protoc_insertion_point(constructor:$full_name$)\n"
       "}\n",
@@ -1894,10 +2174,14 @@
     "full_name", descriptor_->full_name());
   if (UseUnknownFieldSet(descriptor_->file())) {
     printer->Print(
-        ",\n    _internal_metadata_(NULL) {\n");
+        ",\n    _internal_metadata_(NULL)");
   } else if (!UseUnknownFieldSet(descriptor_->file())) {
-    printer->Print(",\n    _arena_ptr_(NULL) {\n");
+    printer->Print(",\n    _arena_ptr_(NULL)");
   }
+  if (IsAnyMessage(descriptor_)) {
+    printer->Print(",\n    _any_metadata_(&type_url_, &value_)");
+  }
+  printer->Print(" {\n");
   printer->Print(
     "  SharedCtor();\n"
     "  MergeFrom(from);\n"
@@ -2124,7 +2408,11 @@
       have_enclosing_if = true;
     }
 
-    field_generators_.get(field).GenerateClearingCode(printer);
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      printer->Print("clear_$name$();\n", "name", fieldname);
+    } else {
+      field_generators_.get(field).GenerateClearingCode(printer);
+    }
 
     if (have_enclosing_if) {
       printer->Outdent();
@@ -2147,7 +2435,11 @@
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (field->is_repeated()) {
-      field_generators_.get(field).GenerateClearingCode(printer);
+      if (use_dependent_base_ && IsFieldDependent(field)) {
+        printer->Print("clear_$name$();\n", "name", FieldName(field));
+      } else {
+        field_generators_.get(field).GenerateClearingCode(printer);
+      }
     }
   }
 
@@ -2184,19 +2476,38 @@
 GenerateOneofClear(io::Printer* printer) {
   // Generated function clears the active field and union case (e.g. foo_case_).
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print(
-        "void $classname$::clear_$oneofname$() {\n",
-        "classname", classname_,
-        "oneofname", descriptor_->oneof_decl(i)->name());
+    map<string, string> oneof_vars;
+    oneof_vars["classname"] = classname_;
+    oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name();
+    string message_class;
+
+    if (use_dependent_base_) {
+      oneof_vars["tmpl"] = "template<class T>\n";
+      oneof_vars["inline"] = "inline ";
+      oneof_vars["dependent_classname"] =
+          DependentBaseClassTemplateName(descriptor_) + "<T>";
+      oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->";
+      message_class = "T::";
+    } else {
+      oneof_vars["tmpl"] = "";
+      oneof_vars["inline"] = "";
+      oneof_vars["dependent_classname"] = classname_;
+      oneof_vars["this_message"] = "";
+    }
+
+    printer->Print(oneof_vars,
+        "$tmpl$"
+        "$inline$"
+        "void $dependent_classname$::clear_$oneofname$() {\n");
     printer->Indent();
-    printer->Print(
-        "switch($oneofname$_case()) {\n",
-        "oneofname", descriptor_->oneof_decl(i)->name());
+    printer->Print(oneof_vars,
+        "switch($this_message$$oneofname$_case()) {\n");
     printer->Indent();
     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",
+          "case $message_class$k$field_name$: {\n",
+          "message_class", message_class,
           "field_name", UnderscoresToCamelCase(field->name(), true));
       printer->Indent();
       // We clear only allocated objects in oneofs
@@ -2213,16 +2524,20 @@
           "}\n");
     }
     printer->Print(
-        "case $cap_oneof_name$_NOT_SET: {\n"
+        "case $message_class$$cap_oneof_name$_NOT_SET: {\n"
         "  break;\n"
         "}\n",
+        "message_class", message_class,
         "cap_oneof_name",
         ToUpper(descriptor_->oneof_decl(i)->name()));
     printer->Outdent();
     printer->Print(
         "}\n"
-        "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n",
+        "$this_message$_oneof_case_[$oneof_index$] = "
+        "$message_class$$cap_oneof_name$_NOT_SET;\n",
+        "this_message", oneof_vars["this_message"],
         "oneof_index", SimpleItoa(i),
+        "message_class", message_class,
         "cap_oneof_name",
         ToUpper(descriptor_->oneof_decl(i)->name()));
     printer->Outdent();
@@ -2333,9 +2648,9 @@
     // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
     // for each message.
     printer->Print(
-      "const $classname$* source =\n"
-      "  ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
-      "    &from);\n"
+      "const $classname$* source = \n"
+      "    ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n"
+      "        &from);\n"
       "if (source == NULL) {\n"
       "  ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
       "} else {\n"
@@ -2585,8 +2900,24 @@
 
     printer->Indent();
 
+    // Find repeated messages and groups now, to simplify what follows.
+    hash_set<int> fields_with_parse_loop;
     for (int i = 0; i < descriptor_->field_count(); i++) {
       const FieldDescriptor* field = ordered_fields[i];
+      if (field->is_repeated() &&
+          (field->type() == FieldDescriptor::TYPE_MESSAGE ||
+           field->type() == FieldDescriptor::TYPE_GROUP)) {
+        fields_with_parse_loop.insert(i);
+      }
+    }
+
+    // need_label is true if we generated "goto parse_$name$" while handling the
+    // previous field.
+    bool need_label = false;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      const FieldDescriptor* field = ordered_fields[i];
+      const bool loops = fields_with_parse_loop.count(i) > 0;
+      const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0;
 
       PrintFieldComment(printer, field);
 
@@ -2600,9 +2931,16 @@
       printer->Print("if (tag == $commontag$) {\n",
                      "commontag", SimpleItoa(WireFormat::MakeTag(field)));
 
-      if (i > 0 || (field->is_repeated() && !field->options().packed())) {
+      if (need_label ||
+          (field->is_repeated() && !field->options().packed() && !loops)) {
         printer->Print(
-          " parse_$name$:\n",
+            " parse_$name$:\n",
+            "name", field->name());
+      }
+      if (loops) {
+        printer->Print(
+          "  DO_(input->IncrementRecursionDepth());\n"
+          " parse_loop_$name$:\n",
           "name", field->name());
       }
 
@@ -2644,26 +2982,53 @@
 
       // switch() is slow since it can't be predicted well.  Insert some if()s
       // here that attempt to predict the next tag.
-      if (field->is_repeated() && !field->options().packed()) {
-        // Expect repeats of this field.
+      // For non-packed repeated fields, expect the same tag again.
+      if (loops) {
+        printer->Print(
+          "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n",
+          "tag", SimpleItoa(WireFormat::MakeTag(field)),
+          "name", field->name());
+      } else if (field->is_repeated() && !field->options().packed()) {
         printer->Print(
           "if (input->ExpectTag($tag$)) goto parse_$name$;\n",
           "tag", SimpleItoa(WireFormat::MakeTag(field)),
           "name", field->name());
       }
 
-      if (i + 1 < descriptor_->field_count()) {
-        // Expect the next field in order.
-        const FieldDescriptor* next_field = ordered_fields[i + 1];
+      // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet?
+      bool emitted_goto_next_tag = false;
+
+      // For repeated messages/groups, we need to decrement recursion depth,
+      // unless the next tag is also for a repeated message/group.
+      if (loops) {
+        if (next_field_loops) {
+          const FieldDescriptor* next_field = ordered_fields[i + 1];
+          printer->Print(
+            "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n",
+            "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+            "next_name", next_field->name());
+          emitted_goto_next_tag = true;
+        }
         printer->Print(
-          "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
-          "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
-          "next_name", next_field->name());
-      } else {
-        // Expect EOF.
-        // TODO(kenton):  Expect group end-tag?
-        printer->Print(
-          "if (input->ExpectAtEnd()) goto success;\n");
+          "input->UnsafeDecrementRecursionDepth();\n");
+      }
+
+      // If there are more fields, expect the next one.
+      need_label = false;
+      if (!emitted_goto_next_tag) {
+        if (i + 1 == descriptor_->field_count()) {
+          // Expect EOF.
+          // TODO(kenton):  Expect group end-tag?
+          printer->Print(
+            "if (input->ExpectAtEnd()) goto success;\n");
+        } else {
+          const FieldDescriptor* next_field = ordered_fields[i + 1];
+          printer->Print(
+            "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n",
+            "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)),
+            "next_name", next_field->name());
+          need_label = true;
+        }
       }
 
       printer->Print(
@@ -2999,9 +3364,7 @@
   vector<string> parts;
   for (int i = 0; i < masks.size(); i++) {
     if (masks[i] == 0) continue;
-    char buffer[kFastToBufferSize];
-    FastHex32ToBuffer(masks[i], buffer);
-    string m = StrCat("0x", buffer);
+    string m = StrCat("0x", strings::Hex(masks[i], strings::Hex::ZERO_PAD_8));
     // Each xor evaluates to 0 if the expected bits are present.
     parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
   }
@@ -3293,11 +3656,10 @@
       }
 
       if (mask != 0) {
-        char buffer[kFastToBufferSize];
         printer->Print(
           "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
           "i", SimpleItoa(i),
-          "mask", FastHex32ToBuffer(mask, buffer));
+          "mask", StrCat(strings::Hex(mask, strings::Hex::ZERO_PAD_8)));
       }
     }
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index ea96581..23dad10 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -67,7 +67,8 @@
   // Header stuff.
 
   // Generate foward declarations for this class and all its nested types.
-  void GenerateForwardDeclaration(io::Printer* printer);
+  void GenerateMessageForwardDeclaration(io::Printer* printer);
+  void GenerateEnumForwardDeclaration(io::Printer* printer);
 
   // Generate definitions of all nested enums (must come before class
   // definitions because those classes use the enums definitions).
@@ -84,6 +85,9 @@
   // file).
   void GenerateInlineMethods(io::Printer* printer, bool is_inline);
 
+  // Dependent methods are always inline.
+  void GenerateDependentInlineMethods(io::Printer* printer);
+
   // Source file stuff.
 
   // Generate code which declares all the global descriptor pointers which
@@ -115,7 +119,10 @@
 
  private:
   // Generate declarations and definitions of accessors for fields.
+  void GenerateDependentBaseClassDefinition(io::Printer* printer);
+  void GenerateDependentFieldAccessorDeclarations(io::Printer* printer);
   void GenerateFieldAccessorDeclarations(io::Printer* printer);
+  void GenerateDependentFieldAccessorDefinitions(io::Printer* printer);
   void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline);
 
   // Generate the field offsets array.
@@ -158,6 +165,21 @@
       bool unbounded);
 
 
+  // Generates has_foo() functions and variables for singular field has-bits.
+  void GenerateSingularFieldHasBits(const FieldDescriptor* field,
+                                    map<string, string> vars,
+                                    io::Printer* printer);
+  // Generates has_foo() functions and variables for oneof field has-bits.
+  void GenerateOneofHasBits(io::Printer* printer, bool is_inline);
+  // Generates has_foo_bar() functions for oneof members.
+  void GenerateOneofMemberHasBits(const FieldDescriptor* field,
+                                  const map<string, string>& vars,
+                                  io::Printer* printer);
+  // Generates the clear_foo() method for a field.
+  void GenerateFieldClear(const FieldDescriptor* field,
+                          const map<string, string>& vars,
+                          io::Printer* printer);
+
   const Descriptor* descriptor_;
   string classname_;
   Options options_;
@@ -168,6 +190,7 @@
   google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
   int num_required_fields_;
   bool uses_string_;
+  bool use_dependent_base_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
 };
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 467b6bf..ba318d1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -72,7 +72,8 @@
 MessageFieldGenerator::
 MessageFieldGenerator(const FieldDescriptor* descriptor,
                       const Options& options)
-  : descriptor_(descriptor) {
+  : descriptor_(descriptor),
+    dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
   SetMessageVariables(descriptor, &variables_, options);
 }
 
@@ -84,6 +85,10 @@
 }
 
 void MessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
@@ -144,6 +149,8 @@
       "  return temp;\n"
       "}\n");
     if (SupportsArenas(descriptor_->message_type())) {
+      // NOTE: the same logic is mirrored in weak_message_field.cc. Any
+      // arena-related semantics changes should be made in both places.
         printer->Print(variables_,
           "void $classname$::_slow_set_allocated_$name$(\n"
           "    ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
@@ -181,6 +188,10 @@
 }
 
 void MessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
   map<string, string> variables(variables_);
@@ -294,7 +305,7 @@
     // If we don't have has-bits, message presence is indicated only by ptr !=
     // NULL. Thus on clear, we need to delete the object.
     printer->Print(variables_,
-      "if ($name$_ != NULL) delete $name$_;\n"
+      "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n"
       "$name$_ = NULL;\n");
   } else {
     printer->Print(variables_,
@@ -366,6 +377,10 @@
 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
 
 void MessageOneofFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void MessageOneofFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
   map<string, string> variables(variables_);
@@ -560,6 +575,10 @@
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateDependentAccessorDeclarations(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
     "const $type$& $name$(int index) const$deprecation$;\n"
@@ -573,6 +592,10 @@
 }
 
 void RepeatedMessageFieldGenerator::
+GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+}
+
+void RepeatedMessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
   map<string, string> variables(variables_);
@@ -627,11 +650,13 @@
 GenerateMergeFromCodedStream(io::Printer* printer) const {
   if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::"
+      "ReadMessageNoVirtualNoRecursionDepth(\n"
       "      input, add_$name$()));\n");
   } else {
     printer->Print(variables_,
-      "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
+      "DO_(::google::protobuf::internal::WireFormatLite::"
+      "ReadGroupNoVirtualNoRecursionDepth(\n"
       "      $number$, input, add_$name$()));\n");
   }
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index c1704fc..9ddf964 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -52,7 +52,9 @@
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer,
                                          bool is_inline) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
@@ -67,6 +69,7 @@
 
  protected:
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
   map<string, string> variables_;
 
  private:
@@ -80,6 +83,7 @@
   ~MessageOneofFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer,
                                          bool is_inline) const;
   void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
@@ -99,7 +103,9 @@
 
   // implements FieldGenerator ---------------------------------------
   void GeneratePrivateMembers(io::Printer* printer) const;
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateAccessorDeclarations(io::Printer* printer) const;
+  void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer,
                                          bool is_inline) const;
   void GenerateClearingCode(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 0c99cff..4463f20 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -41,12 +41,13 @@
 namespace compiler {
 namespace cpp {
 
-// Generator options:
+// Generator options (see generator.cc for a description of each):
 struct Options {
-  Options() : safe_boundary_check(false) {
+  Options() : safe_boundary_check(false), proto_h(false) {
   }
   string dllexport_decl;
   bool safe_boundary_check;
+  bool proto_h;
 };
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 329eae3..9f929d3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -262,7 +262,7 @@
   : descriptor_(descriptor) {
   SetPrimitiveVariables(descriptor, &variables_, options);
 
-  if (descriptor->options().packed()) {
+  if (descriptor->is_packed()) {
     variables_["packed_reader"] = "ReadPackedPrimitive";
     variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
   } else {
@@ -277,7 +277,7 @@
 GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_,
     "::google::protobuf::RepeatedField< $type$ > $name$_;\n");
-  if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
+  if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) {
     printer->Print(variables_,
       "mutable int _$name$_cached_byte_size_;\n");
   }
@@ -364,7 +364,7 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizes(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -377,7 +377,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
       "    this->$name$(i), output);\n");
@@ -391,7 +391,7 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // Write the tag and the size.
     printer->Print(variables_,
       "if (this->$name$_size() > 0) {\n"
@@ -405,7 +405,7 @@
   }
   printer->Print(variables_,
       "for (int i = 0; i < this->$name$_size(); i++) {\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "  target = ::google::protobuf::internal::WireFormatLite::\n"
       "    Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
@@ -435,7 +435,7 @@
       "data_size = $fixed_size$ * this->$name$_size();\n");
   }
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (data_size > 0) {\n"
       "  total_size += $tag_size$ +\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 1a1bcd3..1a3896a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -226,7 +226,6 @@
       "  } else {\n"
       "    $clear_hasbit$\n"
       "  }\n"
-      "  $set_hasbit$\n"
       "  $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
       "      $name$, GetArenaNoVirtual());\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 9f63155..4e25b2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -131,23 +131,23 @@
   }                                                              // NO_PROTO3
 }                                                                // NO_PROTO3
 
-message TestConflictingEnumNames {
-  enum NestedConflictingEnum {
-    and = 1;
-    class = 2;
-    int = 3;
-    typedef = 4;
-    XOR = 5;
-  }
+message TestConflictingEnumNames {  // NO_PROTO3
+  enum NestedConflictingEnum {      // NO_PROTO3
+    and = 1;                        // NO_PROTO3
+    class = 2;                      // NO_PROTO3
+    int = 3;                        // NO_PROTO3
+    typedef = 4;                    // NO_PROTO3
+    XOR = 5;                        // NO_PROTO3
+  }                                 // NO_PROTO3
 
-  optional NestedConflictingEnum conflicting_enum = 1;
-}
+  optional NestedConflictingEnum conflicting_enum = 1;  // NO_PROTO3
+}  // NO_PROTO3
 
-enum ConflictingEnum {
-  NOT_EQ = 1;
-  volatile = 2;
-  return = 3;
-}
+enum ConflictingEnum {  // NO_PROTO3
+  NOT_EQ = 1;           // NO_PROTO3
+  volatile = 2;         // NO_PROTO3
+  return = 3;           // NO_PROTO3
+}  // NO_PROTO3
 
 message DummyMessage {}
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 9d14a92..b11fb21 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -941,6 +941,22 @@
   EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51);
 }
 
+TEST(GeneratedMessageTest, ParseFromTruncated) {
+  const string long_string = string(128, 'q');
+  FileDescriptorProto p;
+  p.add_extension()->set_name(long_string);
+  const string msg = p.SerializeAsString();
+  int successful_count = 0;
+  for (int i = 0; i <= msg.size(); i++) {
+    if (p.ParseFromArray(msg.c_str(), i)) {
+      ++successful_count;
+    }
+  }
+  // We don't really care about how often we succeeded.
+  // As long as we didn't crash, we're happy.
+  EXPECT_GE(successful_count, 1);
+}
+
 // ===================================================================
 
 TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
new file mode 100644
index 0000000..cb6ca1b
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that proto2 compiler can generate valid code when the enum value
+// is INT_MAX. Note that this is a compile-only test and this proto is not
+// referenced in any C++ code.
+syntax = "proto2";
+
+package protobuf_unittest;
+
+message TestLargeEnumValue {
+  enum EnumWithLargeValue {
+    VALUE_1 = 1;
+    VALUE_MAX = 0x7fffffff;
+  }
+}
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 71a2ba4..39318a1 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -67,7 +67,13 @@
   (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
   (*variables)["default_number"] = SimpleItoa(
       descriptor->default_value_enum()->number());
-  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  if (descriptor->is_packed()) {
+    (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag(
+        descriptor->number(),
+        internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+  } else {
+    (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  }
   (*variables)["tag_size"] = SimpleItoa(
       internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
   // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
@@ -641,7 +647,7 @@
       "}\n");
   }
 
-  if (descriptor_->options().packed() &&
+  if (descriptor_->is_packed() &&
       HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
@@ -884,7 +890,7 @@
 
 void RepeatedImmutableEnumFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
       "  output.writeRawVarint32($tag$);\n"
@@ -915,7 +921,7 @@
     "}\n");
   printer->Print(
     "size += dataSize;\n");
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (!get$capitalized_name$List().isEmpty()) {"
       "  size += $tag_size$;\n"
@@ -928,7 +934,7 @@
   }
 
   // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "$name$MemoizedSerializedSize = dataSize;\n");
   }
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
new file mode 100644
index 0000000..697a07a
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -0,0 +1,967 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetEnumVariables(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex,
+                      const FieldGeneratorInfo* info,
+                      ClassNameResolver* name_resolver,
+                      map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->enum_type());
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->enum_type());
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_number"] = SimpleItoa(
+      descriptor->default_value_enum()->number());
+  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != " +
+        (*variables)["default"] + ".getNumber()";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+
+  if (SupportUnknownEnumValue(descriptor->file())) {
+    (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED";
+  } else {
+    (*variables)["unknown"] = (*variables)["default"];
+  }
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableEnumFieldLiteGenerator::
+ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                            int messageBitIndex,
+                            int builderBitIndex,
+                            Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex),
+    name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor),
+                   name_resolver_, &variables_);
+}
+
+ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private int $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  $type$ result = $type$.valueOf($name$_);\n"
+    "  return result == null ? $unknown$ : result;\n"
+    "}\n");
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(int value) {\n"
+      "  $set_has_field_bit_message$"
+      "  $name$_ = value;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value.getNumber();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n"
+    "  $name$_ = $default_number$;\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return instance.get$capitalized_name$Value();\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(int value);\n"
+      "  return this;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default_number$;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\n");
+  } else if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "if (other.$name$_ != $default_number$) {\n"
+      "  set$capitalized_name$Value(other.get$capitalized_name$Value());\n"
+      "}\n");
+  } else {
+    GOOGLE_LOG(FATAL) << "Can't reach here.";
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = rawValue;\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.valueOf(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_has_field_bit_message$\n"
+      "  $name$_ = rawValue;\n"
+      "}\n");
+  }
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for enums
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.writeEnum($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSize($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && $name$_ == other.$name$_;\n");
+}
+
+void ImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + $name$_;\n");
+}
+
+string ImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+// ===================================================================
+
+ImmutableEnumOneofFieldLiteGenerator::
+ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutableEnumFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableEnumOneofFieldLiteGenerator::
+~ImmutableEnumOneofFieldLiteGenerator() {}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  if ($has_oneof_case_message$) {\n"
+      "    return (java.lang.Integer) $oneof_name$_;\n"
+      "  }\n"
+      "  return $default_number$;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $type$ result =  $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+    "    return result == null ? $unknown$ : result;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n");
+
+  // Generate private setters for the builder to proxy into.
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(int value) {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = value;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value.getNumber();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value() {\n"
+      "  return instance.get$capitalized_name$Value();\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(value);\n"
+      "  return this;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "set$capitalized_name$Value(other.get$capitalized_name$Value());\n");
+  } else {
+    printer->Print(variables_,
+      "set$capitalized_name$(other.get$capitalized_name$());\n");
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = rawValue;\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.valueOf(rawValue);\n"
+      "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  $set_oneof_case_message$;\n"
+      "  $oneof_name$_ = rawValue;\n"
+      "}\n");
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$Value()\n"
+      "    == other.get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "result = result && get$capitalized_name$()\n"
+      "    .equals(other.get$capitalized_name$());\n");
+  }
+}
+
+void ImmutableEnumOneofFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$Value();\n");
+  } else {
+    printer->Print(variables_,
+      "hash = (37 * hash) + $constant_name$;\n"
+      "hash = (53 * hash) + get$capitalized_name$().getNumber();\n");
+  }
+}
+
+// ===================================================================
+
+RepeatedImmutableEnumFieldLiteGenerator::
+RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                    int messageBitIndex,
+                                    int builderBitIndex,
+                                    Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex,
+                   context->GetFieldGeneratorInfo(descriptor),
+                   name_resolver_, &variables_);
+}
+
+RepeatedImmutableEnumFieldLiteGenerator::
+~RepeatedImmutableEnumFieldLiteGenerator() {}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$int get$capitalized_name$Value(int index);\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    // TODO(dweis): Switch to IntList?
+    "private com.google.protobuf.Internal.ProtobufList<\n"
+    "    java.lang.Integer> $name$_;\n"
+    "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "    java.lang.Integer, $type$> $name$_converter_ =\n"
+    "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
+    "            java.lang.Integer, $type$>() {\n"
+    "          public $type$ convert(java.lang.Integer from) {\n"
+    "            $type$ result = $type$.valueOf(from);\n"
+    "            return result == null ? $unknown$ : result;\n"
+    "          }\n"
+    "        };\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return new com.google.protobuf.Internal.ListAdapter<\n"
+    "      java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_converter_.convert($name$_.get(index));\n"
+    "}\n");
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return $name$_;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n");
+  }
+
+  if (descriptor_->options().packed() &&
+      HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize;\n");
+  }
+
+  // Generate private setters for the builder to proxy into.
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ = newProtobufList($name$_);\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value.getNumber());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value.getNumber());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  for ($type$ value : values) {\n"
+    "    $name$_.add(value.getNumber());\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyProtobufList();\n"
+    "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void set$capitalized_name$Value(\n"
+      "    int index, int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.set(index, value);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void add$capitalized_name$Value(int value) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  $name$_.add(value);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "private void addAll$capitalized_name$Value(\n"
+      "    java.lang.Iterable<java.lang.Integer> values) {\n"
+      "  ensure$capitalized_name$IsMutable();\n"
+      "  for (int value : values) {\n"
+      "    $name$_.add(value);\n"
+      "  }\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return instance.get$capitalized_name$List();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public java.util.List<java.lang.Integer>\n"
+      "get$capitalized_name$ValueList() {\n"
+      "  return java.util.Collections.unmodifiableList(\n"
+      "      instance.get$capitalized_name$ValueList());\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public int get$capitalized_name$Value(int index) {\n"
+      "  return instance.get$capitalized_name$Value(index);\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder set$capitalized_name$Value(\n"
+      "    int index, int value) {\n"
+      "  copyOnWrite();\n"
+      "  instance.set$capitalized_name$Value(index, value);\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder add$capitalized_name$Value(int value) {\n"
+      "  instance.add$capitalized_name$Value(value);\n"
+      "  return this;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public Builder addAll$capitalized_name$Value(\n"
+      "    java.lang.Iterable<java.lang.Integer> values) {\n"
+      "  copyOnWrite();\n"
+      "  instance.addAll$capitalized_name$Value(values);\n"
+      "  return this;\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  // Read and store the enum
+  if (SupportUnknownEnumValue(descriptor_->file())) {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "if (!$is_mutable$) {\n"
+      "  $name$_ = newProtobufList();\n"
+      "}\n"
+      "$name$_.add(rawValue);\n");
+  } else {
+    printer->Print(variables_,
+      "int rawValue = input.readEnum();\n"
+      "$type$ value = $type$.valueOf(rawValue);\n"
+        "if (value == null) {\n");
+    if (PreserveUnknownFields(descriptor_->containing_type())) {
+      printer->Print(variables_,
+        "  unknownFields.mergeVarintField($number$, rawValue);\n");
+    }
+    printer->Print(variables_,
+      "} else {\n"
+      "  if (!$is_mutable$) {\n"
+      "    $name$_ = newProtobufList();\n"
+      "  }\n"
+      "  $name$_.add(rawValue);\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  // Wrap GenerateParsingCode's contents with a while loop.
+
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int oldLimit = input.pushLimit(length);\n"
+    "while(input.getBytesUntilLimit() > 0) {\n");
+  printer->Indent();
+
+  GenerateParsingCode(printer);
+
+  printer->Outdent();
+  printer->Print(variables_,
+    "}\n"
+    "input.popLimit(oldLimit);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (get$capitalized_name$List().size() > 0) {\n"
+      "  output.writeRawVarint32($tag$);\n"
+      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "}\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnumNoTag($name$_.get(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnum($number$, $name$_.get(i));\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  dataSize += com.google.protobuf.CodedOutputStream\n"
+    "    .computeEnumSizeNoTag($name$_.get(i));\n"
+    "}\n");
+  printer->Print(
+    "size += dataSize;\n");
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (!get$capitalized_name$List().isEmpty()) {"
+      "  size += $tag_size$;\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "    .computeRawVarint32Size(dataSize);\n"
+      "}");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * $name$_.size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && $name$_.equals(other.$name$_);\n");
+}
+
+void RepeatedImmutableEnumFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + $name$_.hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h
new file mode 100644
index 0000000..2c41c3e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h
@@ -0,0 +1,159 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;            // context.h
+      class ClassNameResolver;  // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableEnumFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableEnumFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator);
+};
+
+class ImmutableEnumOneofFieldLiteGenerator
+    : public ImmutableEnumFieldLiteGenerator {
+ public:
+  ImmutableEnumOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableEnumOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableEnumFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableEnumFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableEnumFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index af9978e..3f0fa11 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -42,12 +42,18 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
+#include <google/protobuf/compiler/java/java_enum_field_lite.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_lazy_message_field.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
 #include <google/protobuf/compiler/java/java_map_field.h>
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
 #include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
 #include <google/protobuf/compiler/java/java_primitive_field.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
 #include <google/protobuf/compiler/java/java_string_field.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
@@ -133,6 +139,79 @@
   }
 }
 
+ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator(
+    const FieldDescriptor* field, int messageBitIndex, int builderBitIndex,
+    Context* context) {
+  if (field->is_repeated()) {
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        if (IsMapEntry(field->message_type())) {
+          return new ImmutableMapFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        } else {
+          if (IsLazy(field)) {
+            return new RepeatedImmutableLazyMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new RepeatedImmutableMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        }
+      case JAVATYPE_ENUM:
+        return new RepeatedImmutableEnumFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      case JAVATYPE_STRING:
+        return new RepeatedImmutableStringFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+      default:
+        return new RepeatedImmutablePrimitiveFieldLiteGenerator(
+            field, messageBitIndex, builderBitIndex, context);
+    }
+  } else {
+    if (field->containing_oneof()) {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          if (IsLazy(field)) {
+            return new ImmutableLazyMessageOneofFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new ImmutableMessageOneofFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveOneofFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+      }
+    } else {
+      switch (GetJavaType(field)) {
+        case JAVATYPE_MESSAGE:
+          if (IsLazy(field)) {
+            return new ImmutableLazyMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          } else {
+            return new ImmutableMessageFieldLiteGenerator(
+                field, messageBitIndex, builderBitIndex, context);
+          }
+        case JAVATYPE_ENUM:
+          return new ImmutableEnumFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        case JAVATYPE_STRING:
+          return new ImmutableStringFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+        default:
+          return new ImmutablePrimitiveFieldLiteGenerator(
+              field, messageBitIndex, builderBitIndex, context);
+      }
+    }
+  }
+}
+
 
 static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) {
   // Reaching here indicates a bug. Cases are:
@@ -153,6 +232,13 @@
   ReportUnexpectedPackedFieldsCall(printer);
 }
 
+ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {}
+
+void ImmutableFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  ReportUnexpectedPackedFieldsCall(printer);
+}
+
 // ===================================================================
 
 template <>
@@ -178,6 +264,28 @@
 template<>
 FieldGeneratorMap<ImmutableFieldGenerator>::~FieldGeneratorMap() {}
 
+template <>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::FieldGeneratorMap(
+    const Descriptor* descriptor, Context* context)
+    : descriptor_(descriptor),
+      field_generators_(new google::protobuf::scoped_ptr<
+          ImmutableFieldLiteGenerator>[descriptor->field_count()]) {
+  // Construct all the FieldGenerators and assign them bit indices for their
+  // bit fields.
+  int messageBitIndex = 0;
+  int builderBitIndex = 0;
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator(
+        descriptor->field(i), messageBitIndex, builderBitIndex, context);
+    field_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+    builderBitIndex += generator->GetNumBitsForBuilder();
+  }
+}
+
+template<>
+FieldGeneratorMap<ImmutableFieldLiteGenerator>::~FieldGeneratorMap() {}
+
 
 void SetCommonFieldVariables(const FieldDescriptor* descriptor,
                              const FieldGeneratorInfo* info,
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index 1cf360c..00f3c60 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -83,7 +83,6 @@
   virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
   virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
       const = 0;
-  virtual void GenerateStaticInitializationCode(io::Printer* printer) const {}
 
   virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
   virtual void GenerateHashCode(io::Printer* printer) const = 0;
@@ -94,6 +93,37 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator);
 };
 
+class ImmutableFieldLiteGenerator {
+ public:
+  ImmutableFieldLiteGenerator() {}
+  virtual ~ImmutableFieldLiteGenerator();
+
+  virtual int GetNumBitsForMessage() const = 0;
+  virtual int GetNumBitsForBuilder() const = 0;
+  virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
+  virtual void GenerateMembers(io::Printer* printer) const = 0;
+  virtual void GenerateBuilderMembers(io::Printer* printer) const = 0;
+  virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
+  virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+  virtual void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer)
+      const = 0;
+  virtual void GenerateParsingCode(io::Printer* printer) const = 0;
+  virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+  virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer)
+      const = 0;
+
+  virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+  virtual void GenerateHashCode(io::Printer* printer) const = 0;
+
+  virtual string GetBoxedType() const = 0;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator);
+};
+
 
 // Convenience class which constructs FieldGenerators for a Descriptor.
 template<typename FieldGeneratorType>
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 4a1f452..68b47ee 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -35,10 +35,10 @@
 #include <google/protobuf/compiler/java/java_file.h>
 
 #include <memory>
-#include <set>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
+#include <set>
 
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum.h>
@@ -153,6 +153,12 @@
   }
 }
 
+// Compare two field descriptors, returning true if the first should come
+// before the second.
+bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) {
+  return a->full_name() < b->full_name();
+}
+
 // Our static initialization methods can become very, very large.
 // So large that if we aren't careful we end up blowing the JVM's
 // 64K bytes of bytecode/method. Fortunately, since these static
@@ -166,7 +172,6 @@
                             int *method_num,
                             const char *chain_statement,
                             const char *method_decl) {
- 
   // The goal here is to stay under 64K bytes of jvm bytecode/method,
   // since otherwise we hit a hardcoded limit in the jvm and javac will
   // then fail with the error "code too large". This limit lets our
@@ -184,6 +189,7 @@
   }
 }
 
+
 }  // namespace
 
 FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 2d1437f..92ef851 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/compiler/java/java_field.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_message.h>
+#include <google/protobuf/compiler/java/java_message_lite.h>
 #include <google/protobuf/compiler/java/java_service.h>
 
 namespace google {
@@ -57,7 +58,12 @@
 
 MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
     const Descriptor* descriptor) const {
-  return new ImmutableMessageGenerator(descriptor, context_);
+  if (descriptor->file()->options().optimize_for() ==
+      FileOptions::LITE_RUNTIME) {
+    return new ImmutableMessageLiteGenerator(descriptor, context_);
+  } else {
+    return new ImmutableMessageGenerator(descriptor, context_);
+  }
 }
 
 ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 62efbef..96d2545 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -196,12 +196,6 @@
            FileOptions::LITE_RUNTIME;
 }
 
-inline bool HasNestedBuilders(const Descriptor* descriptor) {
-  // The proto-lite version doesn't support nested builders.
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
-}
-
 // Should we generate generic services for this file?
 inline bool HasGenericServices(const FileDescriptor *file) {
   return file->service_count() > 0 &&
@@ -330,6 +324,10 @@
   return descriptor->options().map_entry();
 }
 
+inline bool IsMapField(const FieldDescriptor* descriptor) {
+  return descriptor->is_map();
+}
+
 inline bool PreserveUnknownFields(const Descriptor* descriptor) {
   return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
 }
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
index 6e29a40..0de8cbe 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -72,14 +72,12 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
-   "}\n");
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  return $name$_;\n"
-      "}\n");
-  }
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  return $name$_;\n"
+    "}\n");
 }
 
 void ImmutableLazyMessageFieldGenerator::
@@ -92,14 +90,12 @@
     "private com.google.protobuf.LazyFieldLite $name$_ =\n"
     "    new com.google.protobuf.LazyFieldLite();\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -179,39 +175,37 @@
     "$clear_has_field_bit_builder$;\n"
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  $set_has_field_bit_builder$;\n"
-      "  $on_changed$\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n"
-      "    return $name$_;\n"
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $on_changed$\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    return $name$_;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 
@@ -538,14 +532,12 @@
     "}\n"
     "\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // repeated field of type "Field" called "RepeatedField".
@@ -723,70 +715,68 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index) {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    return $name$_.get(index);"
-      "  } else {\n"
-      "    return $name$Builder_.getMessageOrBuilder(index);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    return $name$_.get(index);"
+    "  } else {\n"
+    "    return $name$Builder_.getMessageOrBuilder(index);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
-      "     get$capitalized_name$OrBuilderList() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilderList();\n"
-      "  } else {\n"
-      "    return java.util.Collections.unmodifiableList($name$_);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "     get$capitalized_name$OrBuilderList() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilderList();\n"
+    "  } else {\n"
+    "    return java.util.Collections.unmodifiableList($name$_);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      index, $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<$type$.Builder> \n"
-      "     get$capitalized_name$BuilderList() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
-      "}\n"
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            $get_mutable_bit_builder$,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      index, $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$.Builder> \n"
+    "     get$capitalized_name$BuilderList() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
+    "}\n"
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            $get_mutable_bit_builder$,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void RepeatedImmutableLazyMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
new file mode 100644
index 0000000..283ba1d
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -0,0 +1,708 @@
+// 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.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_lazy_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableLazyMessageFieldLiteGenerator::
+ImmutableLazyMessageFieldLiteGenerator(
+    const FieldDescriptor* descriptor,
+    int messageBitIndex,
+    int builderBitIndex,
+    Context* context)
+    : ImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+ImmutableLazyMessageFieldLiteGenerator::
+~ImmutableLazyMessageFieldLiteGenerator() {}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.LazyFieldLite $name$_ =\n"
+    "    new com.google.protobuf.LazyFieldLite();\n");
+
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
+   "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $name$_.setValue(value);\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $name$_.setValue(builderForValue.build());\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($get_has_field_bit_message$ &&\n"
+    "      !$name$_.containsDefaultInstance()) {\n"
+    "    $name$_.setValue(\n"
+    "      $type$.newBuilder(\n"
+    "          get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+    "  } else {\n"
+    "    $name$_.setValue(value);\n"
+    "  }\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_.clear();\n"
+    "  $clear_has_field_bit_message$;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_.clear();\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  $name$_.merge(other.$name$_);\n"
+    "  $set_has_field_bit_message$;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.setByteString(input.readBytes(), extensionRegistry);\n");
+  printer->Print(variables_,
+    "$set_has_field_bit_message$;\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Do not de-serialize lazy fields.
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.writeBytes($number$, $name$_.toByteString());\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, $name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+ImmutableLazyMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                            int messageBitIndex,
+                                            int builderBitIndex,
+                                            Context* context)
+    : ImmutableLazyMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+  variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite";
+}
+
+ImmutableLazyMessageOneofFieldLiteGenerator::
+~ImmutableLazyMessageOneofFieldLiteGenerator() {}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case_message$;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n"
+    "        $type$.getDefaultInstance());\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  if (!($has_oneof_case_message$)) {\n"
+    "    $oneof_name$_ = new $lazy_type$();\n"
+    "    $set_oneof_case_message$;\n"
+    "  }\n"
+    "  (($lazy_type$) $oneof_name$_).setValue(value);\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  if (!($has_oneof_case_message$)) {\n"
+    "    $oneof_name$_ = new $lazy_type$();\n"
+    "    $set_oneof_case_message$;\n"
+    "  }\n"
+    "  (($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($has_oneof_case_message$ &&\n"
+    "      !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n"
+    "    (($lazy_type$) $oneof_name$_).setValue(\n"
+    "       $type$.newBuilder(\n"
+    "          get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
+    "  } else {\n"
+    "    if (!($has_oneof_case_message$)) {\n"
+    "      $oneof_name$_ = new $lazy_type$();\n"
+    "      $set_oneof_case_message$;\n"
+    "    }\n"
+    "    (($lazy_type$) $oneof_name$_).setValue(value);\n"
+    "  }\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!($has_oneof_case_message$)) {\n"
+    "  $oneof_name$_ = new $lazy_type$();\n"
+    "}\n"
+    "(($lazy_type$) $oneof_name$_).merge(\n"
+    "    ($lazy_type$) other.$oneof_name$_);\n"
+    "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!($has_oneof_case_message$)) {\n"
+    "  $oneof_name$_ = new $lazy_type$();\n"
+    "}\n"
+    "(($lazy_type$) $oneof_name$_).setByteString(\n"
+    "    input.readBytes(), extensionRegistry);\n"
+    "$set_oneof_case_message$;\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  // Do not de-serialize lazy fields.
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeBytes(\n"
+    "      $number$, (($lazy_type$) $oneof_name$_).toByteString());\n"
+    "}\n");
+}
+
+void ImmutableLazyMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+RepeatedImmutableLazyMessageFieldLiteGenerator(
+    const FieldDescriptor* descriptor,
+    int messageBitIndex,
+    int builderBitIndex,
+    Context* context)
+    : RepeatedImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+}
+
+
+RepeatedImmutableLazyMessageFieldLiteGenerator::
+~RepeatedImmutableLazyMessageFieldLiteGenerator() {}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.ProtobufList<\n"
+    "    com.google.protobuf.LazyFieldLite> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  java.util.List<$type$> list =\n"
+    "      new java.util.ArrayList<$type$>($name$_.size());\n"
+    "  for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n"
+    "    list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n"
+    "  }\n"
+    // TODO(dweis): Make this list immutable?
+    "  return list;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder>\n"
+    "    get$capitalized_name$OrBuilderList() {\n"
+    "  return get$capitalized_name$List();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return ($type$)\n"
+    "      $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  return ($type$OrBuilder)\n"
+    "      $name$_.get(index).getValue($type$.getDefaultInstance());\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ = newProtobufList($name$_);\n"
+    "   }\n"
+    "}\n"
+    "\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(\n"
+    "      index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(\n"
+    "      index, com.google.protobuf.LazyFieldLite.fromValue(value));\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n"
+    "      builderForValue.build()));\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  for (com.google.protobuf.MessageLite v : values) {\n"
+    "    $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n"
+    "  }\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyProtobufList();\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void remove$capitalized_name$(int index) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.remove(index);\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // List<Field> getRepeatedFieldList()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+    "  copyOnWrite();\n"
+    "  instance.remove$capitalized_name$(index);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ = newProtobufList();\n"
+    "}\n"
+    "$name$_.add(new com.google.protobuf.LazyFieldLite(\n"
+    "    extensionRegistry, input.readBytes()));\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.writeBytes($number$, $name$_.get(i).toByteString());\n"
+    "}\n");
+}
+
+void RepeatedImmutableLazyMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeLazyFieldSize($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
new file mode 100644
index 0000000..e85ec0f
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h
@@ -0,0 +1,118 @@
+// 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.
+
+// Author: niwasaki@google.com (Naoki Iwasaki)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;  // context.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableLazyMessageFieldLiteGenerator
+    : public ImmutableMessageFieldLiteGenerator {
+ public:
+  explicit ImmutableLazyMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableLazyMessageFieldLiteGenerator();
+
+  // overroads ImmutableMessageFieldLiteGenerator ------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldLiteGenerator);
+};
+
+class ImmutableLazyMessageOneofFieldLiteGenerator
+    : public ImmutableLazyMessageFieldLiteGenerator {
+ public:
+  ImmutableLazyMessageOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableLazyMessageOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableLazyMessageFieldLiteGenerator
+    : public RepeatedImmutableMessageFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableLazyMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableLazyMessageFieldLiteGenerator();
+
+  // overroads RepeatedImmutableMessageFieldLiteGenerator ----------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index cf1ef58..f25970e 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -133,9 +133,11 @@
   (*variables)["set_mutable_bit_parser"] =
       GenerateSetBitMutableLocal(builderBitIndex);
 
+  (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+      "DefaultEntryHolder.defaultEntry";
   if (HasDescriptorMethods(descriptor->file())) {
     (*variables)["lite"] = "";
-    (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry";
+    (*variables)["map_field_parameter"] = (*variables)["default_entry"];
     (*variables)["descriptor"] =
         name_resolver->GetImmutableClassName(descriptor->file()) +
         ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
@@ -198,26 +200,20 @@
 }
 
 void ImmutableMapFieldGenerator::
-GenerateStaticInitializationCode(io::Printer* printer) const {
-  printer->Print(
-      variables_,
-      "$name$DefaultEntry =\n"
-      "    com.google.protobuf.MapEntry$lite$\n"
-      "    .<$type_parameters$>newDefaultInstance(\n"
-      "        $descriptor$\n"
-      "        $key_wire_type$,\n"
-      "        $key_default_value$,\n"
-      "        $value_wire_type$,\n"
-      "        $value_default_value$);\n"
-      "\n");
-}
-
-void ImmutableMapFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(
       variables_,
-      "private static final com.google.protobuf.MapEntry$lite$<\n"
-      "    $type_parameters$> $name$DefaultEntry;\n");
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntry$lite$\n"
+      "          .<$type_parameters$>newDefaultInstance(\n"
+      "              $descriptor$\n"
+      "              $key_wire_type$,\n"
+      "              $key_default_value$,\n"
+      "              $value_wire_type$,\n"
+      "              $value_default_value$);\n"
+      "}\n");
   printer->Print(
       variables_,
       "private com.google.protobuf.MapField$lite$<\n"
@@ -291,7 +287,10 @@
       "  if ($name$_ == null) {\n"
       "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
       "        $map_field_parameter$);\n"
-      " }\n"
+      "  }\n"
+      "  if (!$name$_.isMutable()) {\n"
+      "    $name$_ = $name$_.copy();\n"
+      "  }\n"
       "  return $name$_;\n"
       "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
@@ -381,10 +380,8 @@
 GenerateBuildingCode(io::Printer* printer) const {
   printer->Print(
       variables_,
-      // We do a copy of the map field to ensure that the built result is
-      // immutable. Implementation of this copy() method can do copy-on-write
-      // to defer this copy until further modifications are made on the field.
-      "result.$name$_ = internalGet$capitalized_name$().copy();\n");
+      "result.$name$_ = internalGet$capitalized_name$();\n"
+      "result.$name$_.makeImmutable();\n");
 }
 
 void ImmutableMapFieldGenerator::
@@ -402,7 +399,7 @@
         variables_,
         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-        "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n");
+        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
     printer->Print(
         variables_,
         "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
@@ -415,7 +412,7 @@
         variables_,
         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
         "$name$ = input.readMessage(\n"
-        "    $name$DefaultEntry.getParserForType(), extensionRegistry);\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
         "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
   }
 }
@@ -432,7 +429,7 @@
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
       "      .build();\n"
@@ -447,7 +444,7 @@
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $name$DefaultEntry.newBuilderForType()\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
       "      .build();\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index 3e6dd97..80a94f4 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -60,7 +60,6 @@
   void GenerateSerializationCode(io::Printer* printer) const;
   void GenerateSerializedSizeCode(io::Printer* printer) const;
   void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
-  void GenerateStaticInitializationCode(io::Printer* printer) const;
   void GenerateEqualsCode(io::Printer* printer) const;
   void GenerateHashCode(io::Printer* printer) const;
 
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
new file mode 100644
index 0000000..ccc1b32
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -0,0 +1,461 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_map_field_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("key");
+}
+
+const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+  const Descriptor* message = descriptor->message_type();
+  GOOGLE_CHECK(message->options().map_entry());
+  return message->FindFieldByName("value");
+}
+
+string TypeName(const FieldDescriptor* field,
+                ClassNameResolver* name_resolver,
+                bool boxed) {
+  if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+    return name_resolver->GetImmutableClassName(field->message_type());
+  } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+    return name_resolver->GetImmutableClassName(field->enum_type());
+  } else {
+    return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
+                 : PrimitiveTypeName(GetJavaType(field));
+  }
+}
+
+string WireType(const FieldDescriptor* field) {
+  return "com.google.protobuf.WireFormat.FieldType." +
+      string(FieldTypeName(field->type()));
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
+                         const FieldGeneratorInfo* info,
+                         ClassNameResolver* name_resolver,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  const FieldDescriptor* key = KeyField(descriptor);
+  const FieldDescriptor* value = ValueField(descriptor);
+  (*variables)["key_type"] = TypeName(key, name_resolver, false);
+  (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+  (*variables)["key_wire_type"] = WireType(key);
+  (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  if (GetJavaType(value) == JAVATYPE_ENUM) {
+    // We store enums as Integers internally.
+    (*variables)["value_type"] = "int";
+    (*variables)["boxed_value_type"] = "java.lang.Integer";
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver) + ".getNumber()";
+
+    (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
+
+    if (SupportUnknownEnumValue(descriptor->file())) {
+      // Map unknown values to a special UNRECOGNIZED value if supported.
+      (*variables)["unrecognized_value"] =
+          (*variables)["value_enum_type"] + ".UNRECOGNIZED";
+    } else {
+      // Map unknown values to the default value if we don't have UNRECOGNIZED.
+      (*variables)["unrecognized_value"] =
+          DefaultValue(value, true, name_resolver);
+    }
+  } else {
+    (*variables)["value_type"] = TypeName(value, name_resolver, false);
+    (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
+    (*variables)["value_wire_type"] = WireType(value);
+    (*variables)["value_default_value"] =
+        DefaultValue(value, true, name_resolver);
+  }
+  (*variables)["type_parameters"] =
+      (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  (*variables)["default_entry"] = (*variables)["capitalized_name"] +
+      "DefaultEntryHolder.defaultEntry";
+  (*variables)["lite"] = "Lite";
+  (*variables)["descriptor"] = "";
+}
+
+}  // namespace
+
+ImmutableMapFieldLiteGenerator::
+ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex,
+                                       int builderBitIndex,
+                                       Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver())  {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      name_resolver_, &variables_);
+}
+
+ImmutableMapFieldLiteGenerator::
+~ImmutableMapFieldLiteGenerator() {}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$();\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$java.util.Map<$type_parameters$>\n"
+          "get$capitalized_name$Value();\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$java.util.Map<$type_parameters$>\n"
+        "get$capitalized_name$();\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "private static final class $capitalized_name$DefaultEntryHolder {\n"
+      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "      $type_parameters$> defaultEntry =\n"
+      "          com.google.protobuf.MapEntry$lite$\n"
+      "          .<$type_parameters$>newDefaultInstance(\n"
+      "              $descriptor$\n"
+      "              $key_wire_type$,\n"
+      "              $key_default_value$,\n"
+      "              $value_wire_type$,\n"
+      "              $value_default_value$);\n"
+      "}\n");
+  printer->Print(
+      variables_,
+      "private com.google.protobuf.MapField$lite$<\n"
+      "    $type_parameters$> $name$_ =\n"
+      "        com.google.protobuf.MapField$lite$.emptyMapField();\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGet$capitalized_name$() {\n"
+      "  return $name$_;\n"
+      "}\n"
+      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "internalGetMutable$capitalized_name$() {\n"
+      "  if (!$name$_.isMutable()) {\n"
+      "    $name$_ = $name$_.copy();\n"
+      "  }\n"
+      "  return $name$_;\n"
+      "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "private static final\n"
+        "com.google.protobuf.Internal.MapAdapter.Converter<\n"
+        "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
+        "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
+        "            $value_enum_type$.internalGetValueMap(),\n"
+        "            $unrecognized_value$);\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
+        "}\n");
+  }
+
+  // Generate private setters for the builder to proxy into.
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "private java.util.Map<$type_parameters$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return instance.get$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  copyOnWrite();\n"
+        "  return instance.getMutable$capitalized_name$();\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return instance.get$capitalized_name$Value();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  copyOnWrite();\n"
+          "  return instance.getMutable$capitalized_name$Value();\n"
+          "}\n");
+    }
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return instance.get$capitalized_name$();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "public java.util.Map<$type_parameters$>\n"
+        "getMutable$capitalized_name$() {\n"
+        "  copyOnWrite();\n"
+        "  return instance.getMutable$capitalized_name$();\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  // Nothing to initialize.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "internalGetMutable$capitalized_name$().mergeFrom(\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!$name$_.isMutable()) {\n"
+      "  $name$_ = $name$_.copy();\n"
+      "}\n");
+  if (!SupportUnknownEnumValue(descriptor_->file()) &&
+      GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.ByteString bytes = input.readBytes();\n"
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+    printer->Print(
+        variables_,
+        "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+        "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
+        "} else {\n"
+        "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+        "}\n");
+  } else {
+    printer->Print(
+        variables_,
+        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "$name$ = input.readMessage(\n"
+        "    $default_entry$.getParserForType(), extensionRegistry);\n"
+        "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+  }
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // Nothing to do here.
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  output.writeMessage($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "for (java.util.Map.Entry<$type_parameters$> entry\n"
+      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
+      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  $name$ = $default_entry$.newBuilderForType()\n"
+      "      .setKey(entry.getKey())\n"
+      "      .setValue(entry.getValue())\n"
+      "      .build();\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeMessageSize($number$, $name$);\n"
+      "}\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "result = result && internalGet$capitalized_name$().equals(\n"
+      "    other.internalGet$capitalized_name$());\n");
+}
+
+void ImmutableMapFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+      "  hash = (37 * hash) + $constant_name$;\n"
+      "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
+      "}\n");
+}
+
+string ImmutableMapFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h
new file mode 100644
index 0000000..8247260
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.h
@@ -0,0 +1,81 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
+
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMapFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMapFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 63df10b..09b0fd9 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -49,6 +49,8 @@
 #include <google/protobuf/compiler/java/java_extension.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
 #include <google/protobuf/compiler/java/java_name_resolver.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/printer.h>
@@ -93,43 +95,46 @@
   : MessageGenerator(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
+  GOOGLE_CHECK_NE(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
 }
 
 ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
 
 void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
-    // used in the construction of descriptors, we have a tricky bootstrapping
-    // problem.  To help control static initialization order, we make sure all
-    // descriptors and other static data that depends on them are members of
-    // the outermost class in the file.  This way, they will be initialized in
-    // a deterministic order.
+  // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
+  // used in the construction of descriptors, we have a tricky bootstrapping
+  // problem.  To help control static initialization order, we make sure all
+  // descriptors and other static data that depends on them are members of
+  // the outermost class in the file.  This way, they will be initialized in
+  // a deterministic order.
 
-    map<string, string> vars;
-    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-    vars["index"] = SimpleItoa(descriptor_->index());
-    vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
-    if (descriptor_->containing_type() != NULL) {
-      vars["parent"] = UniqueFileScopeIdentifier(
-          descriptor_->containing_type());
-    }
-    if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
-      // We can only make these package-private since the classes that use them
-      // are in separate files.
-      vars["private"] = "";
-    } else {
-      vars["private"] = "private ";
-    }
-
-    // The descriptor for this type.
-    printer->Print(vars,
-      "$private$static com.google.protobuf.Descriptors.Descriptor\n"
-      "  internal_$identifier$_descriptor;\n");
-
-    // And the FieldAccessorTable.
-    GenerateFieldAccessorTable(printer);
+  map<string, string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = SimpleItoa(descriptor_->index());
+  vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+  if (descriptor_->containing_type() != NULL) {
+    vars["parent"] = UniqueFileScopeIdentifier(
+        descriptor_->containing_type());
   }
+  if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
+    // We can only make these package-private since the classes that use them
+    // are in separate files.
+    vars["private"] = "";
+  } else {
+    vars["private"] = "private ";
+  }
+
+  // The descriptor for this type.
+  printer->Print(vars,
+    // TODO(teboring): final needs to be added back. The way to fix it is to
+    // generate methods that can construct the types, and then still declare the
+    // types, and then init them in clinit with the new method calls.
+    "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+    "  internal_$identifier$_descriptor;\n");
+
+  // And the FieldAccessorTable.
+  GenerateFieldAccessorTable(printer);
 
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -142,38 +147,37 @@
 int ImmutableMessageGenerator::GenerateStaticVariableInitializers(
     io::Printer* printer) {
   int bytecode_estimate = 0;
-  if (HasDescriptorMethods(descriptor_)) {
-    map<string, string> vars;
-    vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
-    vars["index"] = SimpleItoa(descriptor_->index());
-    vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
-    if (descriptor_->containing_type() != NULL) {
-      vars["parent"] = UniqueFileScopeIdentifier(
-          descriptor_->containing_type());
-    }
-
-    // The descriptor for this type.
-    if (descriptor_->containing_type() == NULL) {
-      printer->Print(vars,
-        "internal_$identifier$_descriptor =\n"
-        "  getDescriptor().getMessageTypes().get($index$);\n");
-      bytecode_estimate += 30;
-    } else {
-      printer->Print(vars,
-        "internal_$identifier$_descriptor =\n"
-        "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
-      bytecode_estimate += 30;
-    }
-
-    // And the FieldAccessorTable.
-    bytecode_estimate += GenerateFieldAccessorTableInitializer(printer);
+  map<string, string> vars;
+  vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
+  vars["index"] = SimpleItoa(descriptor_->index());
+  vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_);
+  if (descriptor_->containing_type() != NULL) {
+    vars["parent"] = UniqueFileScopeIdentifier(
+        descriptor_->containing_type());
   }
 
+  // The descriptor for this type.
+  if (descriptor_->containing_type() == NULL) {
+    printer->Print(vars,
+      "internal_$identifier$_descriptor =\n"
+      "  getDescriptor().getMessageTypes().get($index$);\n");
+    bytecode_estimate += 30;
+  } else {
+    printer->Print(vars,
+      "internal_$identifier$_descriptor =\n"
+      "  internal_$parent$_descriptor.getNestedTypes().get($index$);\n");
+    bytecode_estimate += 30;
+  }
+
+  // And the FieldAccessorTable.
+  bytecode_estimate += GenerateFieldAccessorTableInitializer(printer);
+
   // Generate static member initializers for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
-    bytecode_estimate += ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
-      .GenerateStaticVariableInitializers(printer);
+    bytecode_estimate +=
+        ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
   }
   return bytecode_estimate;
 }
@@ -229,40 +233,20 @@
 
 void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
   if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.GeneratedMessage.\n"
-        "        ExtendableMessageOrBuilder<$classname$> {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    } else {
-      printer->Print(
-        "public interface $classname$OrBuilder extends \n"
-        "    $extra_interfaces$\n"
-        "     com.google.protobuf.GeneratedMessageLite.\n"
-        "          ExtendableMessageOrBuilder<\n"
-        "              $classname$, $classname$.Builder> {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    }
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.GeneratedMessage.\n"
+      "        ExtendableMessageOrBuilder<$classname$> {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
   } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.MessageOrBuilder {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    } else {
-      printer->Print(
-        "public interface $classname$OrBuilder extends\n"
-        "    $extra_interfaces$\n"
-        "    com.google.protobuf.MessageLiteOrBuilder {\n",
-        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-        "classname", descriptor_->name());
-    }
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.MessageOrBuilder {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
   }
 
   printer->Indent();
@@ -287,98 +271,71 @@
   variables["static"] = is_own_file ? " " : " static ";
   variables["classname"] = descriptor_->name();
   variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
-  variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite";
 
   WriteMessageDocComment(printer, descriptor_);
 
   // The builder_type stores the super type name of the nested Builder class.
   string builder_type;
   if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(variables,
-        "public $static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-        "      $classname$> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n");
-    } else {
-      printer->Print(variables,
-        "public $static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
-        "      $classname$, $classname$.Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n");
-    }
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+      "      $classname$> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
     builder_type = strings::Substitute(
-             "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>",
-             name_resolver_->GetImmutableClassName(descriptor_),
-             variables["lite"]);
+             "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
+             name_resolver_->GetImmutableClassName(descriptor_));
   } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(variables,
-        "public $static$final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n");
-    } else {
-      printer->Print(variables,
-              "public $static$final class $classname$ extends\n"
-              "    com.google.protobuf.GeneratedMessageLite<\n"
-              "        $classname$, $classname$.Builder> implements\n"
-              "    $extra_interfaces$\n"
-              "    $classname$OrBuilder {\n");
-    }
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessage implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
 
-    builder_type = strings::Substitute(
-        "com.google.protobuf.GeneratedMessage$0.Builder",
-        variables["lite"]);
+    builder_type = "com.google.protobuf.GeneratedMessage.Builder";
   }
   printer->Indent();
-  if (HasDescriptorMethods(descriptor_)) {
-    // Using builder_type, instead of Builder, prevents the Builder class from
-    // being loaded into PermGen space when the default instance is created.
-    // This optimizes the PermGen space usage for clients that do not modify
-    // messages.
-    printer->Print(
-      "// Use $classname$.newBuilder() to construct.\n"
-      "private $classname$($buildertype$ builder) {\n"
-      "  super(builder);\n"
-      "}\n",
-      "classname", descriptor_->name(),
-      "buildertype", builder_type);
-    printer->Print(
-      "private $classname$() {\n",
-      "classname", descriptor_->name());
-    printer->Indent();
-    GenerateInitializers(printer);
-    printer->Outdent();
-    printer->Print(
-      "}\n"
-      "\n");
-  }
+  // Using builder_type, instead of Builder, prevents the Builder class from
+  // being loaded into PermGen space when the default instance is created.
+  // This optimizes the PermGen space usage for clients that do not modify
+  // messages.
+  printer->Print(
+    "// Use $classname$.newBuilder() to construct.\n"
+    "private $classname$($buildertype$ builder) {\n"
+    "  super(builder);\n"
+    "}\n",
+    "classname", descriptor_->name(),
+    "buildertype", builder_type);
+  printer->Print(
+    "private $classname$() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+  GenerateInitializers(printer);
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public final com.google.protobuf.UnknownFieldSet\n"
+    "getUnknownFields() {\n");
+  if (PreserveUnknownFields(descriptor_)) {
     printer->Print(
-      "@java.lang.Override\n"
-      "public final com.google.protobuf.UnknownFieldSet\n"
-      "getUnknownFields() {\n");
-    if (PreserveUnknownFields(descriptor_)) {
-      printer->Print(
-        "  return this.unknownFields;\n");
-    } else {
-      printer->Print(
-        "  return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
-    }
+      "  return this.unknownFields;\n");
+  } else {
     printer->Print(
-      "}\n");
+      "  return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n");
   }
+  printer->Print(
+    "}\n");
 
   if (HasGeneratedMethods(descriptor_)) {
     GenerateParsingConstructor(printer);
   }
 
-  GenerateDescriptorMethods(printer, false);
-  GenerateParser(printer);
+  GenerateDescriptorMethods(printer);
 
   // Nested types
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
@@ -488,7 +445,7 @@
   }
 
   if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer, MEMOIZE);
+    GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
   }
 
@@ -509,78 +466,39 @@
   // Carefully initialize the default instance in such a way that it doesn't
   // conflict with other initialization.
   printer->Print(
-    "private static final $classname$ defaultInstance;\n",
+    "private static final $classname$ DEFAULT_INSTANCE;\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "static {\n"
-      "  defaultInstance = new $classname$();\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME only has one constructor.
-    printer->Print(
-      "static {\n"
-      "  defaultInstance = new $classname$(\n"
-      "      com.google.protobuf.Internal\n"
-      "          .EMPTY_CODED_INPUT_STREAM,\n"
-      "      com.google.protobuf.ExtensionRegistryLite\n"
-      "          .getEmptyRegistry());\n"
-      "}\n"
-      "\n",
-      "classname", descriptor_->name());
-  }
+  printer->Print(
+    "static {\n"
+    "  DEFAULT_INSTANCE = new $classname$();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
   printer->Print(
       "public static $classname$ getDefaultInstance() {\n"
-      "  return defaultInstance;\n"
+      "  return DEFAULT_INSTANCE;\n"
       "}\n"
       "\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-      "public $classname$ getDefaultInstanceForType() {\n"
-      "  return defaultInstance;\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME uses this to implement the *ForType methods at the
-    // GeneratedMessageLite level.
-    printer->Print(
-      "static {"
-      "  com.google.protobuf.GeneratedMessageLite.onLoad(\n"
-      "      $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
-      "          .PrototypeHolder<$classname$, Builder>(\n"
-      "              defaultInstance, PARSER));"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
+  GenerateParser(printer);
 
-  // Extensions must be declared after the defaultInstance is initialized
-  // because the defaultInstance is used by the extension to lazily retrieve
+  printer->Print(
+    "public $classname$ getDefaultInstanceForType() {\n"
+    "  return DEFAULT_INSTANCE;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+  // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
   // the outer class's FileDescriptor.
   for (int i = 0; i < descriptor_->extension_count(); i++) {
     ImmutableExtensionGenerator(descriptor_->extension(i), context_)
         .Generate(printer);
   }
 
-  // Some fields also have static members that must be initialized after we
-  // have the default instance available.
-  printer->Print(
-      "static {\n");
-  printer->Indent();
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    field_generators_.get(descriptor_->field(i))
-        .GenerateStaticInitializationCode(printer);
-  }
-  printer->Outdent();
-  printer->Print(
-      "}\n");
-
   printer->Outdent();
   printer->Print("}\n\n");
 }
@@ -617,35 +535,17 @@
 
   if (descriptor_->extension_range_count() > 0) {
     if (descriptor_->options().message_set_wire_format()) {
-      if (HasDescriptorMethods(descriptor_)) {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessage\n"
-          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
-          "    extensionWriter = newMessageSetExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      } else {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessageLite\n"
-          "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
-          "    .ExtensionWriter extensionWriter =\n"
-          "      newMessageSetExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      }
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newMessageSetExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
     } else {
-      if (HasDescriptorMethods(descriptor_)) {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessage\n"
-          "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
-          "    extensionWriter = newExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      } else {
-        printer->Print(
-          "com.google.protobuf.GeneratedMessageLite\n"
-          "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
-          "    .ExtensionWriter extensionWriter =\n"
-          "      newExtensionWriter();\n",
-          "classname", name_resolver_->GetImmutableClassName(descriptor_));
-      }
+      printer->Print(
+        "com.google.protobuf.GeneratedMessage\n"
+        "  .ExtendableMessage<$classname$>.ExtensionWriter\n"
+        "    extensionWriter = newExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
     }
   }
 
@@ -665,8 +565,7 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (descriptor_->options().message_set_wire_format()
-        && HasDescriptorMethods(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
         "unknownFields.writeAsMessageSetTo(output);\n");
     } else {
@@ -702,8 +601,7 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (descriptor_->options().message_set_wire_format()
-        && HasDescriptorMethods(descriptor_)) {
+    if (descriptor_->options().message_set_wire_format()) {
       printer->Print(
         "size += unknownFields.getSerializedSizeAsMessageSet();\n");
     } else {
@@ -800,609 +698,115 @@
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-      "public Builder newBuilderForType() { return newBuilder(); }\n");
-  }
+  // LITE_RUNTIME implements this at the GeneratedMessageLite level.
+  printer->Print(
+    "public Builder newBuilderForType() { return newBuilder(); }\n");
 
   printer->Print(
     "public static Builder newBuilder() {\n"
-    "  return defaultInstance.toBuilder();\n"
+    "  return DEFAULT_INSTANCE.toBuilder();\n"
     "}\n"
     "public static Builder newBuilder($classname$ prototype) {\n"
-    "  return defaultInstance.toBuilder().mergeFrom(prototype);\n"
+    "  return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
     "}\n"
     "public Builder toBuilder() {\n"
-    "  return this == defaultInstance\n"
+    "  return this == DEFAULT_INSTANCE\n"
     "      ? new Builder() : new Builder().mergeFrom(this);\n"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
-  if (HasNestedBuilders(descriptor_)) {
-     printer->Print(
-      "@java.lang.Override\n"
-      "protected Builder newBuilderForType(\n"
-      "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
-      "  Builder builder = new Builder(parent);\n"
-      "  return builder;\n"
-      "}\n");
-  }
-
-  WriteMessageDocComment(printer, descriptor_);
-
-  if (descriptor_->extension_range_count() > 0) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
-        "      $classname$, Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    } else {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
-        "      $classname$, Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    }
-  } else {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    } else {
-      printer->Print(
-        "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessageLite.Builder<\n"
-        "      $classname$, Builder>\n"
-        "    implements\n"
-        "    $extra_interfaces$\n"
-        "    $classname$OrBuilder {\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_),
-        "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
-    }
-  }
-  printer->Indent();
-
-  GenerateDescriptorMethods(printer, true);
-  GenerateCommonBuilderMethods(printer);
-
-  if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer, DONT_MEMOIZE);
-    GenerateBuilderParsingMethods(printer);
-  }
-
-  // oneof
-  map<string, string> vars;
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
-        descriptor_->oneof_decl(i))->name;
-    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
-        descriptor_->oneof_decl(i))->capitalized_name;
-    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
-    // oneofCase_ and oneof_
-    printer->Print(vars,
-      "private int $oneof_name$Case_ = 0;\n"
-      "private java.lang.Object $oneof_name$_;\n");
-    // oneofCase() and clearOneof()
-    printer->Print(vars,
-      "public $oneof_capitalized_name$Case\n"
-      "    get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
-      "      $oneof_name$Case_);\n"
-      "}\n"
-      "\n"
-      "public Builder clear$oneof_capitalized_name$() {\n"
-      "  $oneof_name$Case_ = 0;\n"
-      "  $oneof_name$_ = null;\n");
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print("  onChanged();\n");
-    }
-    printer->Print(
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-
-  if (GenerateHasBits(descriptor_)) {
-    // Integers for bit fields.
-    int totalBits = 0;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      totalBits += field_generators_.get(descriptor_->field(i))
-          .GetNumBitsForBuilder();
-    }
-    int totalInts = (totalBits + 31) / 32;
-    for (int i = 0; i < totalInts; i++) {
-      printer->Print("private int $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-  }
-
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    printer->Print("\n");
-    field_generators_.get(descriptor_->field(i))
-                     .GenerateBuilderMembers(printer);
-  }
-
-  if (!PreserveUnknownFields(descriptor_)) {
-    printer->Print(
-      "public final Builder setUnknownFields(\n"
-      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
-      "  return this;\n"
-      "}\n"
-      "\n"
-      "public final Builder mergeUnknownFields(\n"
-      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-
   printer->Print(
-    "\n"
-    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
-    "full_name", descriptor_->full_name());
+    "@java.lang.Override\n"
+    "protected Builder newBuilderForType(\n"
+    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "  Builder builder = new Builder(parent);\n"
+    "  return builder;\n"
+    "}\n");
 
-  printer->Outdent();
-  printer->Print("}\n");
+  MessageBuilderGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
 }
 
 void ImmutableMessageGenerator::
-GenerateDescriptorMethods(io::Printer* printer, bool is_builder) {
-  if (HasDescriptorMethods(descriptor_)) {
-    if (!descriptor_->options().no_standard_descriptor_accessor()) {
-      printer->Print(
-        "public static final com.google.protobuf.Descriptors.Descriptor\n"
-        "    getDescriptor() {\n"
-        "  return $fileclass$.internal_$identifier$_descriptor;\n"
-        "}\n"
-        "\n",
-        "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-        "identifier", UniqueFileScopeIdentifier(descriptor_));
-    }
-    vector<const FieldDescriptor*> map_fields;
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      const FieldDescriptor* field = descriptor_->field(i);
-      if (GetJavaType(field) == JAVATYPE_MESSAGE &&
-          IsMapEntry(field->message_type())) {
-        map_fields.push_back(field);
-      }
-    }
-    if (!map_fields.empty()) {
-      printer->Print(
-        "@SuppressWarnings({\"rawtypes\"})\n"
-        "protected com.google.protobuf.MapField internalGetMapField(\n"
-        "    int number) {\n"
-        "  switch (number) {\n");
-      printer->Indent();
-      printer->Indent();
-      for (int i = 0; i < map_fields.size(); ++i) {
-        const FieldDescriptor* field = map_fields[i];
-        const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-        printer->Print(
-          "case $number$:\n"
-          "  return internalGet$capitalized_name$();\n",
-          "number", SimpleItoa(field->number()),
-          "capitalized_name", info->capitalized_name);
-      }
-      printer->Print(
-          "default:\n"
-          "  throw new RuntimeException(\n"
-          "      \"Invalid map field number: \" + number);\n");
-      printer->Outdent();
-      printer->Outdent();
-      printer->Print(
-          "  }\n"
-          "}\n");
-      if (is_builder) {
-        printer->Print(
-          "@SuppressWarnings({\"rawtypes\"})\n"
-          "protected com.google.protobuf.MapField internalGetMutableMapField(\n"
-          "    int number) {\n"
-          "  switch (number) {\n");
-        printer->Indent();
-        printer->Indent();
-        for (int i = 0; i < map_fields.size(); ++i) {
-          const FieldDescriptor* field = map_fields[i];
-          const FieldGeneratorInfo* info =
-              context_->GetFieldGeneratorInfo(field);
-          printer->Print(
-            "case $number$:\n"
-            "  return internalGetMutable$capitalized_name$();\n",
-            "number", SimpleItoa(field->number()),
-            "capitalized_name", info->capitalized_name);
-        }
-        printer->Print(
-            "default:\n"
-            "  throw new RuntimeException(\n"
-            "      \"Invalid map field number: \" + number);\n");
-        printer->Outdent();
-        printer->Outdent();
-        printer->Print(
-            "  }\n"
-            "}\n");
-      }
-    }
+GenerateDescriptorMethods(io::Printer* printer) {
+  if (!descriptor_->options().no_standard_descriptor_accessor()) {
     printer->Print(
-      "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
-      "    internalGetFieldAccessorTable() {\n"
-      "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
-      "      .ensureFieldAccessorsInitialized(\n"
-      "          $classname$.class, $classname$.Builder.class);\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_),
-      "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
-      "identifier", UniqueFileScopeIdentifier(descriptor_));
-  }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateCommonBuilderMethods(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-        "// Construct using $classname$.newBuilder()\n"
-        "private Builder() {\n"
-        "  maybeForceBuilderInitialization();\n"
-        "}\n"
-        "\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-    printer->Print(
-      "private Builder(\n"
-      "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
-      "  super(parent);\n"
-      "  maybeForceBuilderInitialization();\n"
-      "}\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE runtime passes along the default instance to implement
-    // getDefaultInstanceForType() at the GeneratedMessageLite level.
-    printer->Print(
-        "// Construct using $classname$.newBuilder()\n"
-        "private Builder() {\n"
-        "  super(defaultInstance);\n"
-        "  maybeForceBuilderInitialization();\n"
-        "}\n"
-        "\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
-
-
-  if (HasNestedBuilders(descriptor_)) {
-    printer->Print(
-      "private void maybeForceBuilderInitialization() {\n"
-      "  if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
-
-    printer->Indent();
-    printer->Indent();
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      if (!descriptor_->field(i)->containing_oneof()) {
-        field_generators_.get(descriptor_->field(i))
-            .GenerateFieldBuilderInitializationCode(printer);
-      }
-    }
-    printer->Outdent();
-    printer->Outdent();
-
-    printer->Print(
-      "  }\n"
-      "}\n");
-  } else {
-    printer->Print(
-      "private void maybeForceBuilderInitialization() {\n"
-      "}\n");
-  }
-
-  printer->Print(
-    "public Builder clear() {\n"
-    "  super.clear();\n");
-
-  printer->Indent();
-
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    if (!descriptor_->field(i)->containing_oneof()) {
-      field_generators_.get(descriptor_->field(i))
-          .GenerateBuilderClearCode(printer);
-    }
-  }
-
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print(
-      "$oneof_name$Case_ = 0;\n"
-      "$oneof_name$_ = null;\n",
-      "oneof_name", context_->GetOneofGeneratorInfo(
-          descriptor_->oneof_decl(i))->name);
-  }
-
-  printer->Outdent();
-
-  printer->Print(
-    "  return this;\n"
-    "}\n"
-    "\n");
-
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public com.google.protobuf.Descriptors.Descriptor\n"
-      "    getDescriptorForType() {\n"
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
       "  return $fileclass$.internal_$identifier$_descriptor;\n"
       "}\n"
       "\n",
       "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
       "identifier", UniqueFileScopeIdentifier(descriptor_));
-
-    // LITE runtime implements this in GeneratedMessageLite.
-    printer->Print(
-      "public $classname$ getDefaultInstanceForType() {\n"
-      "  return $classname$.getDefaultInstance();\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
   }
-
-  // -----------------------------------------------------------------
-
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE implements build in GeneratedMessageLite to save methods.
-    printer->Print(
-      "public $classname$ build() {\n"
-      "  $classname$ result = buildPartial();\n"
-      "  if (!result.isInitialized()) {\n"
-      "    throw newUninitializedMessageException(result);\n"
-      "  }\n"
-      "  return result;\n"
-      "}\n"
-      "\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+  vector<const FieldDescriptor*> map_fields;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        IsMapEntry(field->message_type())) {
+      map_fields.push_back(field);
+    }
   }
-
-  if (HasDescriptorMethods(descriptor_)) {
+  if (!map_fields.empty()) {
     printer->Print(
-        "public $classname$ buildPartial() {\n"
-        "  $classname$ result = new $classname$(this);\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  } else {
-    // LITE_RUNTIME only provides a single message constructor.
-    printer->Print(
-        "public $classname$ buildPartial() {\n"
-        "  $classname$ result = new $classname$(\n"
-        "      com.google.protobuf.Internal\n"
-        "          .EMPTY_CODED_INPUT_STREAM,\n"
-        "      com.google.protobuf.ExtensionRegistryLite\n"
-        "          .getEmptyRegistry());\n"
-        "  result.unknownFields = this.unknownFields;\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-    if (descriptor_->extension_range_count() > 0) {
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
       printer->Print(
-        "  result.extensions = this.buildExtensions();\n");
+        "case $number$:\n"
+        "  return internalGet$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
     }
-  }
-
-  printer->Indent();
-
-  int totalBuilderBits = 0;
-  int totalMessageBits = 0;
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    const ImmutableFieldGenerator& field =
-        field_generators_.get(descriptor_->field(i));
-    totalBuilderBits += field.GetNumBitsForBuilder();
-    totalMessageBits += field.GetNumBitsForMessage();
-  }
-  int totalBuilderInts = (totalBuilderBits + 31) / 32;
-  int totalMessageInts = (totalMessageBits + 31) / 32;
-
-  if (GenerateHasBits(descriptor_)) {
-    // Local vars for from and to bit fields to avoid accessing the builder and
-    // message over and over for these fields. Seems to provide a slight
-    // perforamance improvement in micro benchmark and this is also what proto1
-    // code does.
-    for (int i = 0; i < totalBuilderInts; i++) {
-      printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("int to_$bit_field_name$ = 0;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-  }
-
-  // Output generation code for each field.
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
-  }
-
-  if (GenerateHasBits(descriptor_)) {
-    // Copy the bit field results to the generated message
-    for (int i = 0; i < totalMessageInts; i++) {
-      printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
-        "bit_field_name", GetBitFieldName(i));
-    }
-  }
-
-  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
-    printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
-                   "oneof_name", context_->GetOneofGeneratorInfo(
-                       descriptor_->oneof_decl(i))->name);
-  }
-
-  printer->Outdent();
-
-  if (HasDescriptorMethods(descriptor_)) {
     printer->Print(
-    "  onBuilt();\n");
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
   }
-
   printer->Print(
-    "  return result;\n"
+    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "    internalGetFieldAccessorTable() {\n"
+    "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+    "      .ensureFieldAccessorsInitialized(\n"
+    "          $classname$.class, $classname$.Builder.class);\n"
     "}\n"
     "\n",
-    "classname", name_resolver_->GetImmutableClassName(descriptor_));
-
-  // -----------------------------------------------------------------
-
-  if (HasGeneratedMethods(descriptor_)) {
-    // MergeFrom(Message other) requires the ability to distinguish the other
-    // messages type by its descriptor.
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
-        "  if (other instanceof $classname$) {\n"
-        "    return mergeFrom(($classname$)other);\n"
-        "  } else {\n"
-        "    super.mergeFrom(other);\n"
-        "    return this;\n"
-        "  }\n"
-        "}\n"
-        "\n",
-        "classname", name_resolver_->GetImmutableClassName(descriptor_));
-    }
-
-    printer->Print(
-      "public Builder mergeFrom($classname$ other) {\n"
-      // Optimization:  If other is the default instance, we know none of its
-      //   fields are set so we can skip the merge.
-      "  if (other == $classname$.getDefaultInstance()) return this;\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-    printer->Indent();
-
-    for (int i = 0; i < descriptor_->field_count(); i++) {
-      if (!descriptor_->field(i)->containing_oneof()) {
-        field_generators_.get(
-            descriptor_->field(i)).GenerateMergingCode(printer);
-      }
-    }
-
-    // Merge oneof fields.
-    for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
-      printer->Print(
-        "switch (other.get$oneof_capitalized_name$Case()) {\n",
-        "oneof_capitalized_name",
-        context_->GetOneofGeneratorInfo(
-            descriptor_->oneof_decl(i))->capitalized_name);
-      printer->Indent();
-      for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
-        const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
-        printer->Print(
-          "case $field_name$: {\n",
-          "field_name",
-          ToUpper(field->name()));
-        printer->Indent();
-        field_generators_.get(field).GenerateMergingCode(printer);
-        printer->Print(
-            "break;\n");
-        printer->Outdent();
-        printer->Print(
-            "}\n");
-      }
-      printer->Print(
-        "case $cap_oneof_name$_NOT_SET: {\n"
-        "  break;\n"
-        "}\n",
-        "cap_oneof_name",
-        ToUpper(context_->GetOneofGeneratorInfo(
-            descriptor_->oneof_decl(i))->name));
-      printer->Outdent();
-      printer->Print(
-          "}\n");
-    }
-
-    printer->Outdent();
-
-    // if message type has extensions
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "  this.mergeExtensionFields(other);\n");
-    }
-
-    if (PreserveUnknownFields(descriptor_)) {
-      printer->Print(
-        "  this.mergeUnknownFields(other.unknownFields);\n");
-    }
-
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print("  onChanged();\n");
-    }
-
-    printer->Print(
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-}
-
-// ===================================================================
-
-void ImmutableMessageGenerator::
-GenerateBuilderParsingMethods(io::Printer* printer) {
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-      "public Builder mergeFrom(\n"
-      "    com.google.protobuf.CodedInputStream input,\n"
-      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
-      "    throws java.io.IOException {\n"
-      "  $classname$ parsedMessage = null;\n"
-      "  try {\n"
-      "    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
-      "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-      "    parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
-      "    throw e;\n"
-      "  } finally {\n"
-      "    if (parsedMessage != null) {\n"
-      "      mergeFrom(parsedMessage);\n"
-      "    }\n"
-      "  }\n"
-      "  return this;\n"
-      "}\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
 }
 
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateIsInitialized(
-    io::Printer* printer, UseMemoization useMemoization) {
-  // LITE_RUNTIME avoids generating isInitialized if it's not needed.
-  if (!HasDescriptorMethods(descriptor_)
-      && !HasRequiredFields(descriptor_)) {
-    return;
-  }
-
-  bool memoization = useMemoization == MEMOIZE;
-  if (memoization) {
-    // Memoizes whether the protocol buffer is fully initialized (has all
-    // required fields). -1 means not yet computed. 0 means false and 1 means
-    // true.
-    printer->Print(
-      "private byte memoizedIsInitialized = -1;\n");
-  }
+    io::Printer* printer) {
+  // Memoizes whether the protocol buffer is fully initialized (has all
+  // required fields). -1 means not yet computed. 0 means false and 1 means
+  // true.
+  printer->Print(
+    "private byte memoizedIsInitialized = -1;\n");
   printer->Print(
     "public final boolean isInitialized() {\n");
   printer->Indent();
 
-  if (memoization) {
-    // Don't directly compare to -1 to avoid an Android x86 JIT bug.
-    printer->Print(
-      "byte isInitialized = memoizedIsInitialized;\n"
-      "if (isInitialized == 1) return true;\n"
-      "if (isInitialized == 0) return false;\n"
-      "\n");
-  }
+  // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+  printer->Print(
+    "byte isInitialized = memoizedIsInitialized;\n"
+    "if (isInitialized == 1) return true;\n"
+    "if (isInitialized == 0) return false;\n"
+    "\n");
 
   // Check that all required fields in this message are set.
   // TODO(kenton):  We can optimize this when we switch to putting all the
@@ -1414,11 +818,10 @@
     if (field->is_required()) {
       printer->Print(
         "if (!has$name$()) {\n"
-        "  $memoize$\n"
+        "  memoizedIsInitialized = 0;\n"
         "  return false;\n"
         "}\n",
-        "name", info->capitalized_name,
-        "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+        "name", info->capitalized_name);
     }
   }
 
@@ -1432,13 +835,12 @@
         case FieldDescriptor::LABEL_REQUIRED:
           printer->Print(
             "if (!get$name$().isInitialized()) {\n"
-             "  $memoize$\n"
+             "  memoizedIsInitialized = 0;\n"
              "  return false;\n"
              "}\n",
             "type", name_resolver_->GetImmutableClassName(
                 field->message_type()),
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+            "name", info->capitalized_name);
           break;
         case FieldDescriptor::LABEL_OPTIONAL:
           if (!SupportFieldPresence(descriptor_->file()) &&
@@ -1457,38 +859,35 @@
           }
           printer->Print(
             "  if (!get$name$().isInitialized()) {\n"
-            "    $memoize$\n"
+            "    memoizedIsInitialized = 0;\n"
             "    return false;\n"
             "  }\n"
             "}\n",
-            "name", info->capitalized_name,
-            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+            "name", info->capitalized_name);
           break;
         case FieldDescriptor::LABEL_REPEATED:
           if (IsMapEntry(field->message_type())) {
             printer->Print(
               "for ($type$ item : get$name$().values()) {\n"
               "  if (!item.isInitialized()) {\n"
-              "    $memoize$\n"
+              "    memoizedIsInitialized = 0;\n"
               "    return false;\n"
               "  }\n"
               "}\n",
               "type", MapValueImmutableClassdName(field->message_type(),
                                                   name_resolver_),
-              "name", info->capitalized_name,
-              "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+              "name", info->capitalized_name);
           } else {
             printer->Print(
               "for (int i = 0; i < get$name$Count(); i++) {\n"
               "  if (!get$name$(i).isInitialized()) {\n"
-              "    $memoize$\n"
+              "    memoizedIsInitialized = 0;\n"
               "    return false;\n"
               "  }\n"
               "}\n",
               "type", name_resolver_->GetImmutableClassName(
                   field->message_type()),
-              "name", info->capitalized_name,
-              "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+              "name", info->capitalized_name);
           }
           break;
       }
@@ -1498,18 +897,15 @@
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
       "if (!extensionsAreInitialized()) {\n"
-      "  $memoize$\n"
+      "  memoizedIsInitialized = 0;\n"
       "  return false;\n"
-      "}\n",
-      "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
+      "}\n");
   }
 
   printer->Outdent();
 
-  if (memoization) {
-    printer->Print(
-      "  memoizedIsInitialized = 1;\n");
-  }
+  printer->Print(
+    "  memoizedIsInitialized = 1;\n");
 
   printer->Print(
     "  return true;\n"
@@ -1575,12 +971,10 @@
     printer->Print(
       "result = result && unknownFields.equals(other.unknownFields);\n");
   }
-  if (HasDescriptorMethods(descriptor_)) {
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "result = result &&\n"
-        "    getExtensionFields().equals(other.getExtensionFields());\n");
-    }
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "result = result &&\n"
+      "    getExtensionFields().equals(other.getExtensionFields());\n");
   }
   printer->Print(
     "return result;\n");
@@ -1603,14 +997,7 @@
     "}\n"
     "int hash = 41;\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
-  } else {
-    // Include the hash of the class so that two objects with different types
-    // but the same field values will probably have different hashes.
-    printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
-      "classname", name_resolver_->GetImmutableClassName(descriptor_));
-  }
+  printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
@@ -1628,11 +1015,9 @@
       printer->Print("}\n");
     }
   }
-  if (HasDescriptorMethods(descriptor_)) {
-    if (descriptor_->extension_range_count() > 0) {
-      printer->Print(
-        "hash = hashFields(hash, getExtensionFields());\n");
-    }
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "hash = hashFields(hash, getExtensionFields());\n");
   }
 
   printer->Print(
@@ -1675,13 +1060,8 @@
   printer->Indent();
 
   // Initialize all fields to default.
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-        "this();\n");
-  } else {
-    // LITE_RUNTIME only has one constructor.
-    GenerateInitializers(printer);
-  }
+  printer->Print(
+      "this();\n");
 
   // Use builder bits to track mutable repeated fields.
   int totalBuilderBits = 0;
@@ -1697,15 +1077,9 @@
   }
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (HasDescriptorMethods(descriptor_)) {
-      printer->Print(
-        "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
-        "    com.google.protobuf.UnknownFieldSet.newBuilder();\n");
-    } else {
-      printer->Print(
-        "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
-        "    com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
-    }
+    printer->Print(
+      "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n"
+      "    com.google.protobuf.UnknownFieldSet.newBuilder();\n");
   }
 
   printer->Print(
@@ -1728,29 +1102,14 @@
     "  break;\n");
 
   if (PreserveUnknownFields(descriptor_)) {
-    if (!HasDescriptorMethods(descriptor_)
-        && descriptor_->extension_range_count() > 0) {
-      // Lite runtime directly invokes parseUnknownField to reduce method
-      // counts.
-      printer->Print(
-        "default: {\n"
-        "  if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
-        "                         input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
-        "    done = true;\n"  // it's an endgroup tag
-        "  }\n"
-        "  break;\n"
-        "}\n");
-    } else {
-      printer->Print(
-        "default: {\n"
-        "  if (!parseUnknownField(input, unknownFields,\n"
-        "                         extensionRegistry, tag)) {\n"
-        "    done = true;\n"  // it's an endgroup tag
-        "  }\n"
-        "  break;\n"
-        "}\n");
-    }
+    printer->Print(
+      "default: {\n"
+      "  if (!parseUnknownField(input, unknownFields,\n"
+      "                         extensionRegistry, tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
   } else {
     printer->Print(
       "default: {\n"
@@ -1825,18 +1184,9 @@
     printer->Print("this.unknownFields = unknownFields.build();\n");
   }
 
-  if (!HasDescriptorMethods(descriptor_)) {
-    // LITE runtime uses a static method to reduce method count.
-    if (descriptor_->extension_range_count() > 0) {
-      // Make extensions immutable.
-      printer->Print(
-          "makeExtensionsImmutable(extensions);\n");
-    }
-  } else {
-    // Make extensions immutable.
-    printer->Print(
-        "makeExtensionsImmutable();\n");
-  }
+  // Make extensions immutable.
+  printer->Print(
+      "makeExtensionsImmutable();\n");
 
   printer->Outdent();
   printer->Outdent();
@@ -1874,9 +1224,9 @@
         "  }\n",
         "classname", descriptor_->name());
   } else {
-    // When parsing constructor isn't generated, use builder to parse messages.
-    // Note, will fallback to use reflection based mergeFieldFrom() in
-    // AbstractMessage.Builder.
+    // When parsing constructor isn't generated, use builder to parse
+    // messages. Note, will fallback to use reflection based mergeFieldFrom()
+    // in AbstractMessage.Builder.
     printer->Indent();
     printer->Print(
         "Builder builder = newBuilder();\n"
@@ -1886,7 +1236,8 @@
         "  throw e.setUnfinishedMessage(builder.buildPartial());\n"
         "} catch (java.io.IOException e) {\n"
         "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
-        "      e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n"
+        "      e.getMessage()).setUnfinishedMessage(\n"
+        "          builder.buildPartial());\n"
         "}\n"
         "return builder.buildPartial();\n");
     printer->Outdent();
@@ -1898,16 +1249,13 @@
       "};\n"
       "\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
-    // LITE_RUNTIME implements this at the GeneratedMessageLite level.
-    printer->Print(
-        "@java.lang.Override\n"
-        "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
-        "  return PARSER;\n"
-        "}\n"
-        "\n",
-        "classname", descriptor_->name());
-  }
+  printer->Print(
+      "@java.lang.Override\n"
+      "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
+      "  return PARSER;\n"
+      "}\n"
+      "\n",
+      "classname", descriptor_->name());
 }
 
 // ===================================================================
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 58dd5f9..c3c3776 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -102,10 +102,6 @@
   virtual int GenerateStaticVariableInitializers(io::Printer* printer);
 
  private:
-  enum UseMemoization {
-    MEMOIZE,
-    DONT_MEMOIZE
-  };
 
   void GenerateFieldAccessorTable(io::Printer* printer);
 
@@ -120,11 +116,8 @@
       io::Printer* printer, const Descriptor::ExtensionRange* range);
 
   void GenerateBuilder(io::Printer* printer);
-  void GenerateCommonBuilderMethods(io::Printer* printer);
-  void GenerateDescriptorMethods(io::Printer* printer, bool is_builder);
-  void GenerateBuilderParsingMethods(io::Printer* printer);
-  void GenerateIsInitialized(io::Printer* printer,
-      UseMemoization useMemoization);
+  void GenerateIsInitialized(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer);
   void GenerateInitializers(io::Printer* printer);
   void GenerateEqualsAndHashCode(io::Printer* printer);
   void GenerateParser(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
new file mode 100644
index 0000000..7269411
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -0,0 +1,661 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+MessageBuilderGenerator::MessageBuilderGenerator(
+    const Descriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK_NE(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+MessageBuilderGenerator::~MessageBuilderGenerator() {}
+
+void MessageBuilderGenerator::
+Generate(io::Printer* printer) {
+  WriteMessageDocComment(printer, descriptor_);
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "public static final class Builder extends\n"
+      "    com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n"
+      "      $classname$, Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_),
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+  } else {
+    printer->Print(
+      "public static final class Builder extends\n"
+      "    com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_),
+      "extra_interfaces", ExtraBuilderInterfaces(descriptor_));
+  }
+  printer->Indent();
+
+  GenerateDescriptorMethods(printer);
+  GenerateCommonBuilderMethods(printer);
+
+  if (HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer);
+    GenerateBuilderParsingMethods(printer);
+  }
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+      "private int $oneof_name$Case_ = 0;\n"
+      "private java.lang.Object $oneof_name$_;\n");
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "    get$oneof_capitalized_name$Case() {\n"
+      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "      $oneof_name$Case_);\n"
+      "}\n"
+      "\n"
+      "public Builder clear$oneof_capitalized_name$() {\n"
+      "  $oneof_name$Case_ = 0;\n"
+      "  $oneof_name$_ = null;\n");
+    printer->Print("  onChanged();\n");
+    printer->Print(
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForBuilder();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+                     .GenerateBuilderMembers(printer);
+  }
+
+  if (!PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "public final Builder setUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n"
+      "public final Builder mergeUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateDescriptorMethods(io::Printer* printer) {
+  if (!descriptor_->options().no_standard_descriptor_accessor()) {
+    printer->Print(
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
+      "  return $fileclass$.internal_$identifier$_descriptor;\n"
+      "}\n"
+      "\n",
+      "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+      "identifier", UniqueFileScopeIdentifier(descriptor_));
+  }
+  vector<const FieldDescriptor*> map_fields;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        IsMapEntry(field->message_type())) {
+      map_fields.push_back(field);
+    }
+  }
+  if (!map_fields.empty()) {
+    printer->Print(
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      printer->Print(
+        "case $number$:\n"
+        "  return internalGet$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
+    }
+    printer->Print(
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
+    printer->Print(
+      "@SuppressWarnings({\"rawtypes\"})\n"
+      "protected com.google.protobuf.MapField internalGetMutableMapField(\n"
+      "    int number) {\n"
+      "  switch (number) {\n");
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < map_fields.size(); ++i) {
+      const FieldDescriptor* field = map_fields[i];
+      const FieldGeneratorInfo* info =
+          context_->GetFieldGeneratorInfo(field);
+      printer->Print(
+        "case $number$:\n"
+        "  return internalGetMutable$capitalized_name$();\n",
+        "number", SimpleItoa(field->number()),
+        "capitalized_name", info->capitalized_name);
+    }
+    printer->Print(
+        "default:\n"
+        "  throw new RuntimeException(\n"
+        "      \"Invalid map field number: \" + number);\n");
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+        "  }\n"
+        "}\n");
+  }
+  printer->Print(
+    "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+    "    internalGetFieldAccessorTable() {\n"
+    "  return $fileclass$.internal_$identifier$_fieldAccessorTable\n"
+    "      .ensureFieldAccessorsInitialized(\n"
+    "          $classname$.class, $classname$.Builder.class);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+  printer->Print(
+      "// Construct using $classname$.newBuilder()\n"
+      "private Builder() {\n"
+      "  maybeForceBuilderInitialization();\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "private Builder(\n"
+    "    com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n"
+    "  super(parent);\n"
+    "  maybeForceBuilderInitialization();\n"
+    "}\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "private void maybeForceBuilderInitialization() {\n"
+    "  if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n");
+
+  printer->Indent();
+  printer->Indent();
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateFieldBuilderInitializationCode(printer);
+    }
+  }
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+    "  }\n"
+    "}\n");
+
+  printer->Print(
+    "public Builder clear() {\n"
+    "  super.clear();\n");
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateBuilderClearCode(printer);
+    }
+  }
+
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "$oneof_name$Case_ = 0;\n"
+      "$oneof_name$_ = null;\n",
+      "oneof_name", context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  return this;\n"
+    "}\n"
+    "\n");
+
+  printer->Print(
+    "public com.google.protobuf.Descriptors.Descriptor\n"
+    "    getDescriptorForType() {\n"
+    "  return $fileclass$.internal_$identifier$_descriptor;\n"
+    "}\n"
+    "\n",
+    "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()),
+    "identifier", UniqueFileScopeIdentifier(descriptor_));
+
+  // LITE runtime implements this in GeneratedMessageLite.
+  printer->Print(
+    "public $classname$ getDefaultInstanceForType() {\n"
+    "  return $classname$.getDefaultInstance();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "public $classname$ build() {\n"
+    "  $classname$ result = buildPartial();\n"
+    "  if (!result.isInitialized()) {\n"
+    "    throw newUninitializedMessageException(result);\n"
+    "  }\n"
+    "  return result;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "public $classname$ buildPartial() {\n"
+    "  $classname$ result = new $classname$(this);\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Indent();
+
+  int totalBuilderBits = 0;
+  int totalMessageBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const ImmutableFieldGenerator& field =
+        field_generators_.get(descriptor_->field(i));
+    totalBuilderBits += field.GetNumBitsForBuilder();
+    totalMessageBits += field.GetNumBitsForMessage();
+  }
+  int totalBuilderInts = (totalBuilderBits + 31) / 32;
+  int totalMessageInts = (totalMessageBits + 31) / 32;
+
+  if (GenerateHasBits(descriptor_)) {
+    // Local vars for from and to bit fields to avoid accessing the builder and
+    // message over and over for these fields. Seems to provide a slight
+    // perforamance improvement in micro benchmark and this is also what proto1
+    // code does.
+    for (int i = 0; i < totalBuilderInts; i++) {
+      printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+    for (int i = 0; i < totalMessageInts; i++) {
+      printer->Print("int to_$bit_field_name$ = 0;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  // Output generation code for each field.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer);
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Copy the bit field results to the generated message
+    for (int i = 0; i < totalMessageInts; i++) {
+      printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n",
+                   "oneof_name", context_->GetOneofGeneratorInfo(
+                       descriptor_->oneof_decl(i))->name);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  onBuilt();\n");
+
+  printer->Print(
+    "  return result;\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // -----------------------------------------------------------------
+
+  if (HasGeneratedMethods(descriptor_)) {
+    printer->Print(
+      "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
+      "  if (other instanceof $classname$) {\n"
+      "    return mergeFrom(($classname$)other);\n"
+      "  } else {\n"
+      "    super.mergeFrom(other);\n"
+      "    return this;\n"
+      "  }\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+    printer->Print(
+      "public Builder mergeFrom($classname$ other) {\n"
+      // Optimization:  If other is the default instance, we know none of its
+      //   fields are set so we can skip the merge.
+      "  if (other == $classname$.getDefaultInstance()) return this;\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    printer->Indent();
+
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      if (!descriptor_->field(i)->containing_oneof()) {
+        field_generators_.get(
+            descriptor_->field(i)).GenerateMergingCode(printer);
+      }
+    }
+
+    // Merge oneof fields.
+    for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+      printer->Print(
+        "switch (other.get$oneof_capitalized_name$Case()) {\n",
+        "oneof_capitalized_name",
+        context_->GetOneofGeneratorInfo(
+            descriptor_->oneof_decl(i))->capitalized_name);
+      printer->Indent();
+      for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+        const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+        printer->Print(
+          "case $field_name$: {\n",
+          "field_name",
+          ToUpper(field->name()));
+        printer->Indent();
+        field_generators_.get(field).GenerateMergingCode(printer);
+        printer->Print(
+            "break;\n");
+        printer->Outdent();
+        printer->Print(
+            "}\n");
+      }
+      printer->Print(
+        "case $cap_oneof_name$_NOT_SET: {\n"
+        "  break;\n"
+        "}\n",
+        "cap_oneof_name",
+        ToUpper(context_->GetOneofGeneratorInfo(
+            descriptor_->oneof_decl(i))->name));
+      printer->Outdent();
+      printer->Print(
+          "}\n");
+    }
+
+    printer->Outdent();
+
+    // if message type has extensions
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print(
+        "  this.mergeExtensionFields(other);\n");
+    }
+
+    if (PreserveUnknownFields(descriptor_)) {
+      printer->Print(
+        "  this.mergeUnknownFields(other.unknownFields);\n");
+    }
+
+    printer->Print(
+      "  onChanged();\n");
+
+    printer->Print(
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::
+GenerateBuilderParsingMethods(io::Printer* printer) {
+  printer->Print(
+    "public Builder mergeFrom(\n"
+    "    com.google.protobuf.CodedInputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  $classname$ parsedMessage = null;\n"
+    "  try {\n"
+    "    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n"
+    "  } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+    "    parsedMessage = ($classname$) e.getUnfinishedMessage();\n"
+    "    throw e;\n"
+    "  } finally {\n"
+    "    if (parsedMessage != null) {\n"
+    "      mergeFrom(parsedMessage);\n"
+    "    }\n"
+    "  }\n"
+    "  return this;\n"
+    "}\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+void MessageBuilderGenerator::GenerateIsInitialized(
+    io::Printer* printer) {
+  printer->Print(
+    "public final boolean isInitialized() {\n");
+  printer->Indent();
+
+  // Check that all required fields in this message are set.
+  // TODO(kenton):  We can optimize this when we switch to putting all the
+  //   "has" fields into a single bitfield.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+    if (field->is_required()) {
+      printer->Print(
+        "if (!has$name$()) {\n"
+        "  return false;\n"
+        "}\n",
+        "name", info->capitalized_name);
+    }
+  }
+
+  // Now check that all embedded messages are initialized.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        HasRequiredFields(field->message_type())) {
+      switch (field->label()) {
+        case FieldDescriptor::LABEL_REQUIRED:
+          printer->Print(
+            "if (!get$name$().isInitialized()) {\n"
+             "  return false;\n"
+             "}\n",
+            "type", name_resolver_->GetImmutableClassName(
+                field->message_type()),
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          if (!SupportFieldPresence(descriptor_->file()) &&
+              field->containing_oneof() != NULL) {
+            const OneofDescriptor* oneof = field->containing_oneof();
+            const OneofGeneratorInfo* oneof_info =
+                context_->GetOneofGeneratorInfo(oneof);
+            printer->Print(
+              "if ($oneof_name$Case_ == $field_number$) {\n",
+              "oneof_name", oneof_info->name,
+              "field_number", SimpleItoa(field->number()));
+          } else {
+            printer->Print(
+              "if (has$name$()) {\n",
+              "name", info->capitalized_name);
+          }
+          printer->Print(
+            "  if (!get$name$().isInitialized()) {\n"
+            "    return false;\n"
+            "  }\n"
+            "}\n",
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_REPEATED:
+          if (IsMapEntry(field->message_type())) {
+            printer->Print(
+              "for ($type$ item : get$name$().values()) {\n"
+              "  if (!item.isInitialized()) {\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", MapValueImmutableClassdName(field->message_type(),
+                                                  name_resolver_),
+              "name", info->capitalized_name);
+          } else {
+            printer->Print(
+              "for (int i = 0; i < get$name$Count(); i++) {\n"
+              "  if (!get$name$(i).isInitialized()) {\n"
+              "    return false;\n"
+              "  }\n"
+              "}\n",
+              "type", name_resolver_->GetImmutableClassName(
+                  field->message_type()),
+              "name", info->capitalized_name);
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "if (!extensionsAreInitialized()) {\n"
+      "  return false;\n"
+      "}\n");
+  }
+
+  printer->Outdent();
+
+  printer->Print(
+    "  return true;\n"
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h
new file mode 100644
index 0000000..015ea06
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder.h
@@ -0,0 +1,86 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderGenerator {
+ public:
+  explicit MessageBuilderGenerator(const Descriptor* descriptor,
+                                   Context* context);
+  virtual ~MessageBuilderGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+ private:
+  void GenerateCommonBuilderMethods(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer);
+  void GenerateBuilderParsingMethods(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer);
+
+  const Descriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
new file mode 100644
index 0000000..8719d00
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -0,0 +1,192 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+MessageBuilderLiteGenerator::MessageBuilderLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK_EQ(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {}
+
+void MessageBuilderLiteGenerator::
+Generate(io::Printer* printer) {
+  WriteMessageDocComment(printer, descriptor_);
+  printer->Print(
+    "public static final class Builder extends\n"
+    "    com.google.protobuf.GeneratedMessageLite.$extendible$Builder<\n"
+    "      $classname$, Builder> implements\n"
+    "    $extra_interfaces$\n"
+    "    $classname$OrBuilder {\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_),
+    "extra_interfaces", ExtraBuilderInterfaces(descriptor_),
+    "extendible",
+    descriptor_->extension_range_count() > 0 ? "Extendable" : "");
+  printer->Indent();
+
+  GenerateCommonBuilderMethods(printer);
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+
+    // oneofCase() and clearOneof()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "    get$oneof_capitalized_name$Case() {\n"
+      "  return instance.get$oneof_capitalized_name$Case();\n"
+      "}\n"
+      "\n"
+      "public Builder clear$oneof_capitalized_name$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.clear$oneof_capitalized_name$();\n"
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForBuilder();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("\n");
+    field_generators_.get(descriptor_->field(i))
+                     .GenerateBuilderMembers(printer);
+  }
+
+  if (!PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "public final Builder setUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n"
+      "public final Builder mergeUnknownFields(\n"
+      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
+      "  return this;\n"
+      "}\n"
+      "\n");
+  }
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageBuilderLiteGenerator::
+GenerateCommonBuilderMethods(io::Printer* printer) {
+  printer->Print(
+    "// Construct using $classname$.newBuilder()\n"
+    "private Builder() {\n"
+    "  super(DEFAULT_INSTANCE);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+// ===================================================================
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.h b/src/google/protobuf/compiler/java/java_message_builder_lite.h
new file mode 100644
index 0000000..8597b2e
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.h
@@ -0,0 +1,83 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class MessageBuilderLiteGenerator {
+ public:
+  explicit MessageBuilderLiteGenerator(const Descriptor* descriptor,
+                                   Context* context);
+  virtual ~MessageBuilderLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+ private:
+  void GenerateCommonBuilderMethods(io::Printer* printer);
+
+  const Descriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index a2d12a3..b180b4a 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -157,11 +157,9 @@
   printer->Print(variables_,
     "$deprecation$$type$ get$capitalized_name$();\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
 }
 
 void ImmutableMessageFieldGenerator::
@@ -182,14 +180,12 @@
       "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
       "}\n");
 
-    if (HasNestedBuilders(descriptor_->containing_type())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(variables_,
-        "$deprecation$public $type$OrBuilder "
-        "get$capitalized_name$OrBuilder() {\n"
-        "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
-        "}\n");
-    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$OrBuilder "
+      "get$capitalized_name$OrBuilder() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
   } else {
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(variables_,
@@ -202,14 +198,12 @@
       "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
       "}\n");
 
-    if (HasNestedBuilders(descriptor_->containing_type())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(variables_,
-        "$deprecation$public $type$OrBuilder "
-        "get$capitalized_name$OrBuilder() {\n"
-        "  return get$capitalized_name$();\n"
-        "}\n");
-    }
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$OrBuilder "
+      "get$capitalized_name$OrBuilder() {\n"
+      "  return get$capitalized_name$();\n"
+      "}\n");
   }
 }
 
@@ -217,19 +211,15 @@
     io::Printer* printer,
     const char* regular_case,
     const char* nested_builder_case) const {
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-     printer->Print(variables_, "if ($name$Builder_ == null) {\n");
-     printer->Indent();
-     printer->Print(variables_, regular_case);
-     printer->Outdent();
-     printer->Print("} else {\n");
-     printer->Indent();
-     printer->Print(variables_, nested_builder_case);
-     printer->Outdent();
-     printer->Print("}\n");
-   } else {
-     printer->Print(variables_, regular_case);
-   }
+  printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+  printer->Indent();
+  printer->Print(variables_, regular_case);
+  printer->Outdent();
+  printer->Print("} else {\n");
+  printer->Indent();
+  printer->Print(variables_, nested_builder_case);
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -260,14 +250,12 @@
   printer->Print(variables_,
     "private $type$ $name$_ = null;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
+  printer->Print(variables_,
       // If this builder is non-null, it is used and the other fields are
       // ignored.
       "private com.google.protobuf.SingleFieldBuilder<\n"
       "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
       "\n");
-  }
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -368,40 +356,38 @@
     "$clear_has_field_bit_builder$\n"
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  $set_has_field_bit_builder$\n"
-      "  $on_changed$\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n"
-      "    return $name$_ == null ?\n"
-      "        $type$.getDefaultInstance() : $name$_;\n"
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            get$capitalized_name$(),\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  $set_has_field_bit_builder$\n"
+    "  $on_changed$\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    return $name$_ == null ?\n"
+    "        $type$.getDefaultInstance() : $name$_;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            get$capitalized_name$(),\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void ImmutableMessageFieldGenerator::
@@ -557,16 +543,14 @@
     "  return $type$.getDefaultInstance();\n"
     "}\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if ($has_oneof_case_message$) {\n"
-      "     return ($type$) $oneof_name$_;\n"
-      "  }\n"
-      "  return $type$.getDefaultInstance();\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "     return ($type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
 }
 
 void ImmutableMessageOneofFieldGenerator::
@@ -574,14 +558,12 @@
   // When using nested-builders, the code initially works just like the
   // non-nested builder case. It only creates a nested builder lazily on
   // demand and then forever delegates to it after creation.
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // field of type "Field" called "Field".
@@ -683,45 +665,43 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
-      "  if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
-      "    return $name$Builder_.getMessageOrBuilder();\n"
-      "  } else {\n"
-      "    if ($has_oneof_case_message$) {\n"
-      "      return ($type$) $oneof_name$_;\n"
-      "    }\n"
-      "    return $type$.getDefaultInstance();\n"
-      "  }\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "private com.google.protobuf.SingleFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    if (!($has_oneof_case_message$)) {\n"
-      "      $oneof_name$_ = $type$.getDefaultInstance();\n"
-      "    }\n"
-      "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            ($type$) $oneof_name$_,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $oneof_name$_ = null;\n"
-      "  }\n"
-      "  $set_oneof_case_message$;\n"
-      "  $on_changed$;\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+    "  if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n"
+    "    return $name$Builder_.getMessageOrBuilder();\n"
+    "  } else {\n"
+    "    if ($has_oneof_case_message$) {\n"
+    "      return ($type$) $oneof_name$_;\n"
+    "    }\n"
+    "    return $type$.getDefaultInstance();\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    if (!($has_oneof_case_message$)) {\n"
+    "      $oneof_name$_ = $type$.getDefaultInstance();\n"
+    "    }\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            ($type$) $oneof_name$_,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "  $on_changed$;\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void ImmutableMessageOneofFieldGenerator::
@@ -831,16 +811,15 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$int get$capitalized_name$Count();\n");
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
-      "    get$capitalized_name$OrBuilderList();\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index);\n");
-  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
+    "    get$capitalized_name$OrBuilderList();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index);\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::
@@ -882,19 +861,15 @@
     io::Printer* printer,
     const char* regular_case,
     const char* nested_builder_case) const {
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-     printer->Print(variables_, "if ($name$Builder_ == null) {\n");
-     printer->Indent();
-     printer->Print(variables_, regular_case);
-     printer->Outdent();
-     printer->Print("} else {\n");
-     printer->Indent();
-     printer->Print(variables_, nested_builder_case);
-     printer->Outdent();
-     printer->Print("}\n");
-   } else {
-     printer->Print(variables_, regular_case);
-   }
+  printer->Print(variables_, "if ($name$Builder_ == null) {\n");
+  printer->Indent();
+  printer->Print(variables_, regular_case);
+  printer->Outdent();
+  printer->Print("} else {\n");
+  printer->Indent();
+  printer->Print(variables_, nested_builder_case);
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction(
@@ -942,14 +917,12 @@
     "}\n"
     "\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    printer->Print(variables_,
-      // If this builder is non-null, it is used and the other fields are
-      // ignored.
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
-      "\n");
-  }
+  printer->Print(variables_,
+    // If this builder is non-null, it is used and the other fields are
+    // ignored.
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
+    "\n");
 
   // The comments above the methods below are based on a hypothetical
   // repeated field of type "Field" called "RepeatedField".
@@ -1116,70 +1089,68 @@
 
     "return this;\n");
 
-  if (HasNestedBuilders(descriptor_->containing_type())) {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(variables_,
-      "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
-      "    int index) {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    return $name$_.get(index);"
-      "  } else {\n"
-      "    return $name$Builder_.getMessageOrBuilder(index);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    return $name$_.get(index);"
+    "  } else {\n"
+    "    return $name$Builder_.getMessageOrBuilder(index);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
-      "     get$capitalized_name$OrBuilderList() {\n"
-      "  if ($name$Builder_ != null) {\n"
-      "    return $name$Builder_.getMessageOrBuilderList();\n"
-      "  } else {\n"
-      "    return java.util.Collections.unmodifiableList($name$_);\n"
-      "  }\n"
-      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "     get$capitalized_name$OrBuilderList() {\n"
+    "  if ($name$Builder_ != null) {\n"
+    "    return $name$Builder_.getMessageOrBuilderList();\n"
+    "  } else {\n"
+    "    return java.util.Collections.unmodifiableList($name$_);\n"
+    "  }\n"
+    "}\n");
 
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
-      "    int index) {\n"
-      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
-      "      index, $type$.getDefaultInstance());\n"
-      "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-        printer->Print(variables_,
-      "$deprecation$public java.util.List<$type$.Builder> \n"
-      "     get$capitalized_name$BuilderList() {\n"
-      "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
-      "}\n"
-      "private com.google.protobuf.RepeatedFieldBuilder<\n"
-      "    $type$, $type$.Builder, $type$OrBuilder> \n"
-      "    get$capitalized_name$FieldBuilder() {\n"
-      "  if ($name$Builder_ == null) {\n"
-      "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
-      "        $type$, $type$.Builder, $type$OrBuilder>(\n"
-      "            $name$_,\n"
-      "            $get_mutable_bit_builder$,\n"
-      "            getParentForChildren(),\n"
-      "            isClean());\n"
-      "    $name$_ = null;\n"
-      "  }\n"
-      "  return $name$Builder_;\n"
-      "}\n");
-  }
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+    "    int index) {\n"
+    "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+    "      index, $type$.getDefaultInstance());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+      printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$.Builder> \n"
+    "     get$capitalized_name$BuilderList() {\n"
+    "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
+    "}\n"
+    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $type$, $type$.Builder, $type$OrBuilder> \n"
+    "    get$capitalized_name$FieldBuilder() {\n"
+    "  if ($name$Builder_ == null) {\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "        $type$, $type$.Builder, $type$OrBuilder>(\n"
+    "            $name$_,\n"
+    "            $get_mutable_bit_builder$,\n"
+    "            getParentForChildren(),\n"
+    "            isClean());\n"
+    "    $name$_ = null;\n"
+    "  }\n"
+    "  return $name$Builder_;\n"
+    "}\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
new file mode 100644
index 0000000..8332202
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -0,0 +1,944 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_message_field_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+namespace {
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
+                         const FieldGeneratorInfo* info,
+                         ClassNameResolver* name_resolver,
+                         map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] =
+      name_resolver->GetImmutableClassName(descriptor->message_type());
+  (*variables)["mutable_type"] =
+      name_resolver->GetMutableClassName(descriptor->message_type());
+  (*variables)["group_or_message"] =
+    (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ?
+    "Group" : "Message";
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        (*variables)["name"] + "_ != null";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableMessageFieldLiteGenerator::
+ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex,
+                      Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+    SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  // TODO(jonp): In the future, consider having a method specific to the
+  // interface so that builders can choose dynamically to either return a
+  // message or a nested builder, so that asking for the interface doesn't
+  // cause a message to ever be built.
+  if (SupportFieldPresence(descriptor_->file()) ||
+      descriptor_->containing_oneof() == NULL) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$ get$capitalized_name$() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
+  } else {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $name$_ != null;\n"
+      "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public $type$ get$capitalized_name$() {\n"
+      "  return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n"
+      "}\n");
+  }
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $name$_ = value;\n"
+    "  $set_has_field_bit_message$\n"
+    "  }\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $name$_ = builderForValue.build();\n"
+    "  $set_has_field_bit_message$\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($name$_ != null &&\n"
+    "      $name$_ != $type$.getDefaultInstance()) {\n"
+    "    $name$_ =\n"
+    "      $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+    "  } else {\n"
+    "    $name$_ = value;\n"
+    "  }\n"
+    "  $set_has_field_bit_message$\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {"
+    "  $name$_ = null;\n"
+    "  $clear_has_field_bit_message$\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  // boolean hasField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return instance.has$capitalized_name$();\n"
+    "}\n");
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "  }\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "get$capitalized_name$FieldBuilder();\n");
+  }
+}
+
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  merge$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$type$.Builder subBuilder = null;\n"
+    "if ($is_field_present_message$) {\n"
+    "  subBuilder = $name$_.toBuilder();\n"
+    "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$name$_ = input.readGroup($number$, $type$.PARSER,\n"
+        "    extensionRegistry);\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+    }
+
+  printer->Print(variables_,
+    "if (subBuilder != null) {\n"
+    "  subBuilder.mergeFrom($name$_);\n"
+    "  $name$_ = subBuilder.buildPartial();\n"
+    "}\n"
+    "$set_has_field_bit_message$\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for messages.
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+// ===================================================================
+
+ImmutableMessageOneofFieldLiteGenerator::
+ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutableMessageFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableMessageOneofFieldLiteGenerator::
+~ImmutableMessageOneofFieldLiteGenerator() {}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "     return ($type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $type$.getDefaultInstance();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  $oneof_name$_ = value;\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  $oneof_name$_ = builderForValue.build();\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void merge$capitalized_name$($type$ value) {\n"
+    "  if ($has_oneof_case_message$ &&\n"
+    "      $oneof_name$_ != $type$.getDefaultInstance()) {\n"
+    "    $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n"
+    "        .mergeFrom(value).buildPartial();\n"
+    "  } else {\n"
+    "    $oneof_name$_ = value;\n"
+    "  }\n"
+    "  $set_oneof_case_message$;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    // boolean hasField()
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  // Field getField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  // Field.Builder setField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder mergeField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.merge$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Field.Builder clearField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "merge$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$type$.Builder subBuilder = null;\n"
+    "if ($has_oneof_case_message$) {\n"
+    "  subBuilder = (($type$) $oneof_name$_).toBuilder();\n"
+    "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n"
+        "    extensionRegistry);\n");
+    } else {
+      printer->Print(variables_,
+        "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n");
+    }
+
+  printer->Print(variables_,
+    "if (subBuilder != null) {\n"
+    "  subBuilder.mergeFrom(($type$) $oneof_name$_);\n"
+    "  $oneof_name$_ = subBuilder.buildPartial();\n"
+    "}\n");
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+void ImmutableMessageOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableMessageFieldLiteGenerator::
+RepeatedImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                       int messageBitIndex,
+                                       int builderBitIndex,
+                                       Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver())  {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      context->GetFieldGeneratorInfo(descriptor),
+                      name_resolver_, &variables_);
+}
+
+RepeatedImmutableMessageFieldLiteGenerator::
+~RepeatedImmutableMessageFieldLiteGenerator() {}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  // TODO(jonp): In the future, consider having methods specific to the
+  // interface so that builders can choose dynamically to either return a
+  // message or a nested builder, so that asking for the interface doesn't
+  // cause a message to ever be built.
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> \n"
+    "    get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.Internal.ProtobufList<$type$> $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "    get$capitalized_name$OrBuilderList() {\n"
+    "  return $name$_;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ = newProtobufList($name$_);\n"
+    "   }\n"
+    "}\n"
+    "\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, builderForValue.build());\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, value);\n"
+    "}\n");
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(builderForValue.build());\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(index, builderForValue.build());\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = emptyProtobufList();\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void remove$capitalized_name$(int index) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.remove(index);\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // The comments above the methods below are based on a hypothetical
+  // repeated field of type "Field" called "RepeatedField".
+
+  // List<Field> getRepeatedFieldList()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+
+  // int getRepeatedFieldCount()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}");
+
+  // Field getRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(index, builderForValue);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder clearAllRepeatedField()
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  // Builder removeRepeatedField(int index)
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder remove$capitalized_name$(int index) {\n"
+    "  copyOnWrite();\n"
+    "  instance.remove$capitalized_name$(index);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  printer->Print(variables_,
+    "get$capitalized_name$FieldBuilder();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = emptyProtobufList();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations (non-nested builder case):
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ = newProtobufList();\n"
+    "}\n");
+
+    if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+      printer->Print(variables_,
+        "$name$_.add(input.readGroup($number$, $type$.PARSER,\n"
+        "    extensionRegistry));\n");
+    } else {
+      printer->Print(variables_,
+        "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n");
+    }
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.write$group_or_message$($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$group_or_message$Size($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableMessageFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const {
+  return name_resolver_->GetImmutableClassName(descriptor_->message_type());
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
new file mode 100644
index 0000000..ae26c06
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -0,0 +1,157 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMessageFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator);
+};
+
+class ImmutableMessageOneofFieldLiteGenerator
+    : public ImmutableMessageFieldLiteGenerator {
+ public:
+  ImmutableMessageOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableMessageOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableMessageFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableMessageFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableMessageFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
new file mode 100644
index 0000000..3accee9
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -0,0 +1,1174 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/java/java_message_lite.h>
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <map>
+#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
+#include <vector>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_enum.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_generator_factory.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_message_builder.h>
+#include <google/protobuf/compiler/java/java_message_builder_lite.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+bool GenerateHasBits(const Descriptor* descriptor) {
+  return SupportFieldPresence(descriptor->file()) ||
+      HasRepeatedFields(descriptor);
+}
+
+string MapValueImmutableClassdName(const Descriptor* descriptor,
+                                   ClassNameResolver* name_resolver) {
+  const FieldDescriptor* value_field = descriptor->FindFieldByName("value");
+  GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
+  return name_resolver->GetImmutableClassName(value_field->message_type());
+}
+}  // namespace
+
+// ===================================================================
+ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator(
+    const Descriptor* descriptor, Context* context)
+  : MessageGenerator(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()),
+    field_generators_(descriptor, context_) {
+  GOOGLE_CHECK_EQ(
+      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+}
+
+ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
+
+void ImmutableMessageLiteGenerator::GenerateStaticVariables(
+    io::Printer* printer) {
+  // Generate static members for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+      .GenerateStaticVariables(printer);
+  }
+}
+
+int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers(
+    io::Printer* printer) {
+  int bytecode_estimate = 0;
+  // Generate static member initializers for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    bytecode_estimate +=
+        ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+            .GenerateStaticVariableInitializers(printer);
+  }
+  return bytecode_estimate;
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "public interface $classname$OrBuilder extends \n"
+      "    $extra_interfaces$\n"
+      "     com.google.protobuf.GeneratedMessageLite.\n"
+      "          ExtendableMessageOrBuilder<\n"
+      "              $classname$, $classname$.Builder> {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "public interface $classname$OrBuilder extends\n"
+      "    $extra_interfaces$\n"
+      "    com.google.protobuf.MessageLiteOrBuilder {\n",
+      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+      "classname", descriptor_->name());
+  }
+
+  printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      printer->Print("\n");
+      field_generators_.get(descriptor_->field(i))
+                       .GenerateInterfaceMembers(printer);
+    }
+  printer->Outdent();
+
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
+  bool is_own_file =
+    descriptor_->containing_type() == NULL &&
+    MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+
+  map<string, string> variables;
+  variables["static"] = is_own_file ? " " : " static ";
+  variables["classname"] = descriptor_->name();
+  variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
+
+  WriteMessageDocComment(printer, descriptor_);
+
+  // The builder_type stores the super type name of the nested Builder class.
+  string builder_type;
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(variables,
+      "public $static$final class $classname$ extends\n"
+      "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
+      "      $classname$, $classname$.Builder> implements\n"
+      "    $extra_interfaces$\n"
+      "    $classname$OrBuilder {\n");
+    builder_type = strings::Substitute(
+        "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>",
+        name_resolver_->GetImmutableClassName(descriptor_));
+  } else {
+    printer->Print(variables,
+        "public $static$final class $classname$ extends\n"
+        "    com.google.protobuf.GeneratedMessageLite<\n"
+        "        $classname$, $classname$.Builder> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
+
+    builder_type = "com.google.protobuf.GeneratedMessageLite.Builder";
+  }
+  printer->Indent();
+
+  GenerateParsingConstructor(printer);
+
+  // Nested types
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumGenerator(descriptor_->enum_type(i), true, context_)
+        .Generate(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // Don't generate Java classes for map entry messages.
+    if (IsMapEntry(descriptor_->nested_type(i))) continue;
+    ImmutableMessageLiteGenerator messageGenerator(
+        descriptor_->nested_type(i), context_);
+    messageGenerator.GenerateInterface(printer);
+    messageGenerator.Generate(printer);
+  }
+
+  if (GenerateHasBits(descriptor_)) {
+    // Integers for bit fields.
+    int totalBits = 0;
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      totalBits += field_generators_.get(descriptor_->field(i))
+          .GetNumBitsForMessage();
+    }
+    int totalInts = (totalBits + 31) / 32;
+    for (int i = 0; i < totalInts; i++) {
+      printer->Print("private int $bit_field_name$;\n",
+        "bit_field_name", GetBitFieldName(i));
+    }
+  }
+
+  // oneof
+  map<string, string> vars;
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    vars["oneof_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->name;
+    vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo(
+        descriptor_->oneof_decl(i))->capitalized_name;
+    vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index());
+    // oneofCase_ and oneof_
+    printer->Print(vars,
+      "private int $oneof_name$Case_ = 0;\n"
+      "private java.lang.Object $oneof_name$_;\n");
+    // OneofCase enum
+    printer->Print(vars,
+      "public enum $oneof_capitalized_name$Case\n"
+      "    implements com.google.protobuf.Internal.EnumLite {\n");
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "$field_name$($field_number$),\n",
+        "field_name",
+        ToUpper(field->name()),
+        "field_number",
+        SimpleItoa(field->number()));
+    }
+    printer->Print(
+      "$cap_oneof_name$_NOT_SET(0);\n",
+      "cap_oneof_name",
+      ToUpper(vars["oneof_name"]));
+    printer->Print(vars,
+      "private int value = 0;\n"
+      "private $oneof_capitalized_name$Case(int value) {\n"
+      "  this.value = value;\n"
+      "}\n");
+    printer->Print(vars,
+      "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+      "  switch (value) {\n");
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "    case $field_number$: return $field_name$;\n",
+        "field_number",
+        SimpleItoa(field->number()),
+        "field_name",
+        ToUpper(field->name()));
+    }
+    printer->Print(
+      "    case 0: return $cap_oneof_name$_NOT_SET;\n"
+      "    default: throw new java.lang.IllegalArgumentException(\n"
+      "      \"Value is undefined for this oneof enum.\");\n"
+      "  }\n"
+      "}\n"
+      "public int getNumber() {\n"
+      "  return this.value;\n"
+      "}\n",
+      "cap_oneof_name", ToUpper(vars["oneof_name"]));
+    printer->Outdent();
+    printer->Print("};\n\n");
+    // oneofCase()
+    printer->Print(vars,
+      "public $oneof_capitalized_name$Case\n"
+      "get$oneof_capitalized_name$Case() {\n"
+      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "      $oneof_name$Case_);\n"
+      "}\n"
+      "\n"
+      "private void clear$oneof_capitalized_name$() {\n"
+      "  $oneof_name$Case_ = 0;\n"
+      "  $oneof_name$_ = null;\n"
+      "}\n"
+      "\n");
+  }
+
+  // Fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    printer->Print("public static final int $constant_name$ = $number$;\n",
+      "constant_name", FieldConstantName(descriptor_->field(i)),
+      "number", SimpleItoa(descriptor_->field(i)->number()));
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  GenerateMessageSerializationMethods(printer);
+
+  if (HasEqualsAndHashCode(descriptor_)) {
+    GenerateEqualsAndHashCode(printer);
+  }
+
+
+  GenerateParseFromMethods(printer);
+  GenerateBuilder(printer);
+
+  if (HasRequiredFields(descriptor_)) {
+    // Memoizes whether the protocol buffer is fully initialized (has all
+    // required fields). -1 means not yet computed. 0 means false and 1 means
+    // true.
+    printer->Print(
+      "private byte memoizedIsInitialized = -1;\n");
+  }
+
+  printer->Print(
+    "protected final Object dynamicMethod(\n"
+    "    com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n"
+    "    Object... args) {\n"
+    "  switch (method) {\n"
+    "    case PARSE_PARTIAL_FROM: {\n"
+    "      return new $classname$("
+    "          (com.google.protobuf.CodedInputStream) args[0],\n"
+    "          (com.google.protobuf.ExtensionRegistryLite) args[1]);\n"
+    "    }\n"
+    "    case NEW_INSTANCE: {\n"
+    "      return new $classname$(\n"
+    "          com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n"
+    "          com.google.protobuf.ExtensionRegistryLite\n"
+    "              .getEmptyRegistry());\n"
+    "    }\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Indent();
+  printer->Indent();
+
+  printer->Print(
+    "case IS_INITIALIZED: {\n");
+  printer->Indent();
+  GenerateDynamicMethodIsInitialized(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case MAKE_IMMUTABLE: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodMakeImmutable(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case NEW_BUILDER: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodNewBuilder(printer);
+  printer->Outdent();
+
+  printer->Print(
+    "}\n"
+    "case MERGE_FROM: {\n");
+
+  printer->Indent();
+  GenerateDynamicMethodMergeFrom(printer);
+  printer->Outdent();
+
+  printer->Print(
+      "}\n");
+
+  printer->Outdent();
+  printer->Outdent();
+
+  printer->Print(
+    "  }\n"
+    "  throw new UnsupportedOperationException();\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+    "full_name", descriptor_->full_name());
+
+
+  // Carefully initialize the default instance in such a way that it doesn't
+  // conflict with other initialization.
+  printer->Print(
+    "private static final $classname$ DEFAULT_INSTANCE;\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print(
+    "static {\n"
+    "  DEFAULT_INSTANCE = new $classname$(\n"
+    "      com.google.protobuf.Internal\n"
+    "          .EMPTY_CODED_INPUT_STREAM,\n"
+    "      com.google.protobuf.ExtensionRegistryLite\n"
+    "          .getEmptyRegistry());\n"
+    "}\n"
+    "\n",
+    "classname", descriptor_->name());
+  printer->Print(
+      "public static $classname$ getDefaultInstance() {\n"
+      "  return DEFAULT_INSTANCE;\n"
+      "}\n"
+      "\n",
+      "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  GenerateParser(printer);
+
+  // LITE_RUNTIME uses this to implement the *ForType methods at the
+  // GeneratedMessageLite level.
+  printer->Print(
+    "static {\n"
+    "  com.google.protobuf.GeneratedMessageLite.onLoad(\n"
+    "      $classname$.class, new com.google.protobuf.GeneratedMessageLite\n"
+    "          .PrototypeHolder<$classname$, Builder>(\n"
+    "              DEFAULT_INSTANCE, PARSER));"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  // Extensions must be declared after the DEFAULT_INSTANCE is initialized
+  // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
+  // the outer class's FileDescriptor.
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+        .Generate(printer);
+  }
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+      SortFieldsByNumber(descriptor_));
+
+  vector<const Descriptor::ExtensionRange*> sorted_extensions;
+  for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
+    sorted_extensions.push_back(descriptor_->extension_range(i));
+  }
+  std::sort(sorted_extensions.begin(), sorted_extensions.end(),
+            ExtensionRangeOrdering());
+
+  printer->Print(
+    "public void writeTo(com.google.protobuf.CodedOutputStream output)\n"
+    "                    throws java.io.IOException {\n");
+  printer->Indent();
+  if (HasPackedFields(descriptor_)) {
+    // writeTo(CodedOutputStream output) might be invoked without
+    // getSerializedSize() ever being called, but we need the memoized
+    // sizes in case this message has packed fields. Rather than emit checks for
+    // each packed field, just call getSerializedSize() up front.
+    // In most cases, getSerializedSize() will have already been called anyway
+    // by one of the wrapper writeTo() methods, making this call cheap.
+    printer->Print(
+      "getSerializedSize();\n");
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessageLite\n"
+        "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+        "    .ExtensionWriter extensionWriter =\n"
+        "      newMessageSetExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    } else {
+      printer->Print(
+        "com.google.protobuf.GeneratedMessageLite\n"
+        "  .ExtendableMessage<$classname$, $classname$.Builder>\n"
+        "    .ExtensionWriter extensionWriter =\n"
+        "      newExtensionWriter();\n",
+        "classname", name_resolver_->GetImmutableClassName(descriptor_));
+    }
+  }
+
+  // Merge the fields and the extension ranges, both sorted by field number.
+  for (int i = 0, j = 0;
+       i < descriptor_->field_count() || j < sorted_extensions.size();
+       ) {
+    if (i == descriptor_->field_count()) {
+      GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+    } else if (j == sorted_extensions.size()) {
+      GenerateSerializeOneField(printer, sorted_fields[i++]);
+    } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) {
+      GenerateSerializeOneField(printer, sorted_fields[i++]);
+    } else {
+      GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]);
+    }
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "unknownFields.writeTo(output);\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n"
+    "public int getSerializedSize() {\n"
+    "  int size = memoizedSerializedSize;\n"
+    "  if (size != -1) return size;\n"
+    "\n"
+    "  size = 0;\n");
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    if (descriptor_->options().message_set_wire_format()) {
+      printer->Print(
+        "size += extensionsSerializedSizeAsMessageSet();\n");
+    } else {
+      printer->Print(
+        "size += extensionsSerializedSize();\n");
+    }
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "size += unknownFields.getSerializedSize();\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  memoizedSerializedSize = size;\n"
+    "  return size;\n"
+    "}\n"
+    "\n");
+
+  printer->Print(
+    "private static final long serialVersionUID = 0L;\n");
+}
+
+void ImmutableMessageLiteGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+  // Note:  These are separate from GenerateMessageSerializationMethods()
+  //   because they need to be generated even for messages that are optimized
+  //   for code size.
+  printer->Print(
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.ByteString data)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return PARSER.parseFrom(data);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.ByteString data,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return PARSER.parseFrom(data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(byte[] data)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return PARSER.parseFrom(data);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    byte[] data,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
+    "  return PARSER.parseFrom(data, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseFrom(input);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    java.io.InputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseDelimitedFrom(input);\n"
+    "}\n"
+    "public static $classname$ parseDelimitedFrom(\n"
+    "    java.io.InputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseDelimitedFrom(input, extensionRegistry);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.CodedInputStream input)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseFrom(input);\n"
+    "}\n"
+    "public static $classname$ parseFrom(\n"
+    "    com.google.protobuf.CodedInputStream input,\n"
+    "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+    "    throws java.io.IOException {\n"
+    "  return PARSER.parseFrom(input, extensionRegistry);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneField(
+    io::Printer* printer, const FieldDescriptor* field) {
+  field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void ImmutableMessageLiteGenerator::GenerateSerializeOneExtensionRange(
+    io::Printer* printer, const Descriptor::ExtensionRange* range) {
+  printer->Print(
+    "extensionWriter.writeUntil($end$, output);\n",
+    "end", SimpleItoa(range->end));
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) {
+  printer->Print(
+    "public static Builder newBuilder() {\n"
+    "  return DEFAULT_INSTANCE.toBuilder();\n"
+    "}\n"
+    "public static Builder newBuilder($classname$ prototype) {\n"
+    "  return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n"
+    "}\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  MessageBuilderLiteGenerator builderGenerator(descriptor_, context_);
+  builderGenerator.Generate(printer);
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized(
+    io::Printer* printer) {
+  // Returns null for false, DEFAULT_INSTANCE for true.
+  if (!HasRequiredFields(descriptor_)) {
+    printer->Print("return DEFAULT_INSTANCE;\n");
+    return;
+  }
+
+  // Don't directly compare to -1 to avoid an Android x86 JIT bug.
+  printer->Print(
+    "byte isInitialized = memoizedIsInitialized;\n"
+    "if (isInitialized == 1) return DEFAULT_INSTANCE;\n"
+    "if (isInitialized == 0) return null;\n"
+    "\n"
+    "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n");
+
+  // Check that all required fields in this message are set.
+  // TODO(kenton):  We can optimize this when we switch to putting all the
+  //   "has" fields into a single bitfield.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+
+    if (field->is_required()) {
+      printer->Print(
+        "if (!has$name$()) {\n"
+        "  if (shouldMemoize) {\n"
+        "    memoizedIsInitialized = 0;\n"
+        "  }\n"
+        "  return null;\n"
+        "}\n",
+        "name", info->capitalized_name);
+    }
+  }
+
+  // Now check that all embedded messages are initialized.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    if (GetJavaType(field) == JAVATYPE_MESSAGE &&
+        HasRequiredFields(field->message_type())) {
+      switch (field->label()) {
+        case FieldDescriptor::LABEL_REQUIRED:
+          printer->Print(
+            "if (!get$name$().isInitialized()) {\n"
+            "  if (shouldMemoize) {\n"
+            "    memoizedIsInitialized = 0;\n"
+            "  }\n"
+            "  return null;\n"
+            "}\n",
+            "type", name_resolver_->GetImmutableClassName(
+                field->message_type()),
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          if (!SupportFieldPresence(descriptor_->file()) &&
+              field->containing_oneof() != NULL) {
+            const OneofDescriptor* oneof = field->containing_oneof();
+            const OneofGeneratorInfo* oneof_info =
+                context_->GetOneofGeneratorInfo(oneof);
+            printer->Print(
+              "if ($oneof_name$Case_ == $field_number$) {\n",
+              "oneof_name", oneof_info->name,
+              "field_number", SimpleItoa(field->number()));
+          } else {
+            printer->Print(
+              "if (has$name$()) {\n",
+              "name", info->capitalized_name);
+          }
+          printer->Print(
+            "  if (!get$name$().isInitialized()) {\n"
+            "    if (shouldMemoize) {\n"
+            "      memoizedIsInitialized = 0;\n"
+            "    }\n"
+            "    return null;\n"
+            "  }\n"
+            "}\n",
+            "name", info->capitalized_name);
+          break;
+        case FieldDescriptor::LABEL_REPEATED:
+          if (IsMapEntry(field->message_type())) {
+            printer->Print(
+              "for ($type$ item : get$name$().values()) {\n"
+              "  if (!item.isInitialized()) {\n"
+              "    if (shouldMemoize) {\n"
+              "      memoizedIsInitialized = 0;\n"
+              "    }\n"
+              "    return null;\n"
+              "  }\n"
+              "}\n",
+              "type", MapValueImmutableClassdName(field->message_type(),
+                                                  name_resolver_),
+              "name", info->capitalized_name);
+          } else {
+            printer->Print(
+              "for (int i = 0; i < get$name$Count(); i++) {\n"
+              "  if (!get$name$(i).isInitialized()) {\n"
+              "    if (shouldMemoize) {\n"
+              "      memoizedIsInitialized = 0;\n"
+              "    }\n"
+              "    return null;\n"
+              "  }\n"
+              "}\n",
+              "type", name_resolver_->GetImmutableClassName(
+                  field->message_type()),
+              "name", info->capitalized_name);
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "if (!extensionsAreInitialized()) {\n"
+      "  if (shouldMemoize) {\n"
+      "    memoizedIsInitialized = 0;\n"
+      "  }\n"
+      "  return null;\n"
+      "}\n");
+  }
+
+  printer->Print(
+    "if (shouldMemoize) memoizedIsInitialized = 1;\n");
+
+  printer->Print(
+    "return DEFAULT_INSTANCE;\n"
+    "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable(
+    io::Printer* printer) {
+  // Output generation code for each field.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateDynamicMethodMakeImmutableCode(printer);
+  }
+  printer->Print(
+    "return null;");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder(
+    io::Printer* printer) {
+  printer->Print(
+    "return new Builder();");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom(
+    io::Printer* printer) {
+  printer->Print(
+    // Optimization:  If other is the default instance, we know none of its
+    //   fields are set so we can skip the merge.
+    "Object arg = args[0];\n"
+    "if (arg == $classname$.getDefaultInstance()) return this;\n"
+    "$classname$ other = ($classname$) arg;\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(
+          descriptor_->field(i)).GenerateMergingCode(printer);
+    }
+  }
+
+  // Merge oneof fields.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
+    printer->Print(
+      "switch (other.get$oneof_capitalized_name$Case()) {\n",
+      "oneof_capitalized_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->capitalized_name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_name$: {\n",
+        "field_name",
+        ToUpper(field->name()));
+      printer->Indent();
+      field_generators_.get(field).GenerateMergingCode(printer);
+      printer->Print(
+          "break;\n");
+      printer->Outdent();
+      printer->Print(
+          "}\n");
+    }
+    printer->Print(
+      "case $cap_oneof_name$_NOT_SET: {\n"
+      "  break;\n"
+      "}\n",
+      "cap_oneof_name",
+      ToUpper(context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name));
+    printer->Outdent();
+    printer->Print(
+      "}\n");
+  }
+
+  // if message type has extensions
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "this.mergeExtensionFields(other);\n");
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "this.mergeUnknownFields(other.unknownFields);\n");
+  }
+
+  printer->Print(
+    "return this;\n");
+}
+
+// ===================================================================
+
+namespace {
+bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
+  if (field->is_repeated()) {
+    return false;
+  }
+  if (SupportFieldPresence(field->file())) {
+    return true;
+  }
+  return GetJavaType(field) == JAVATYPE_MESSAGE &&
+      field->containing_oneof() == NULL;
+}
+}  // namespace
+
+void ImmutableMessageLiteGenerator::
+GenerateEqualsAndHashCode(io::Printer* printer) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public boolean equals(final java.lang.Object obj) {\n");
+  printer->Indent();
+  printer->Print(
+    "if (obj == this) {\n"
+    " return true;\n"
+    "}\n"
+    "if (!(obj instanceof $classname$)) {\n"
+    "  return super.equals(obj);\n"
+    "}\n"
+    "$classname$ other = ($classname$) obj;\n"
+    "\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  printer->Print("boolean result = true;\n");
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+    if (check_has_bits) {
+      printer->Print(
+        "result = result && (has$name$() == other.has$name$());\n"
+        "if (has$name$()) {\n",
+        "name", info->capitalized_name);
+      printer->Indent();
+    }
+    field_generators_.get(field).GenerateEqualsCode(printer);
+    if (check_has_bits) {
+      printer->Outdent();
+      printer->Print(
+        "}\n");
+    }
+  }
+  if (PreserveUnknownFields(descriptor_)) {
+    // Always consider unknown fields for equality. This will sometimes return
+    // false for non-canonical ordering when running in LITE_RUNTIME but it's
+    // the best we can do.
+    printer->Print(
+      "result = result && unknownFields.equals(other.unknownFields);\n");
+  }
+  printer->Print(
+    "return result;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
+
+  printer->Print(
+    "@java.lang.Override\n"
+    "public int hashCode() {\n");
+  printer->Indent();
+  printer->Print(
+    "if (memoizedHashCode != 0) {\n");
+  printer->Indent();
+  printer->Print(
+    "return memoizedHashCode;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "int hash = 41;\n");
+
+  // Include the hash of the class so that two objects with different types
+  // but the same field values will probably have different hashes.
+  printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
+    "classname", name_resolver_->GetImmutableClassName(descriptor_));
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+    if (check_has_bits) {
+      printer->Print(
+        "if (has$name$()) {\n",
+        "name", info->capitalized_name);
+      printer->Indent();
+    }
+    field_generators_.get(field).GenerateHashCode(printer);
+    if (check_has_bits) {
+      printer->Outdent();
+      printer->Print("}\n");
+    }
+  }
+
+  printer->Print(
+    "hash = (29 * hash) + unknownFields.hashCode();\n");
+  printer->Print(
+    "memoizedHashCode = hash;\n"
+    "return hash;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
+void ImmutableMessageLiteGenerator::
+GenerateExtensionRegistrationCode(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+      .GenerateRegistrationCode(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+      .GenerateExtensionRegistrationCode(printer);
+  }
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::
+GenerateParsingConstructor(io::Printer* printer) {
+  google::protobuf::scoped_array<const FieldDescriptor * > sorted_fields(
+      SortFieldsByNumber(descriptor_));
+
+  printer->Print(
+      "private $classname$(\n"
+      "    com.google.protobuf.CodedInputStream input,\n"
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+      "classname", descriptor_->name());
+  printer->Indent();
+
+  // Initialize all fields to default.
+  GenerateInitializers(printer);
+
+  // Use builder bits to track mutable repeated fields.
+  int totalBuilderBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const ImmutableFieldLiteGenerator& field =
+        field_generators_.get(descriptor_->field(i));
+    totalBuilderBits += field.GetNumBitsForBuilder();
+  }
+  int totalBuilderInts = (totalBuilderBits + 31) / 32;
+  for (int i = 0; i < totalBuilderInts; i++) {
+    printer->Print("int mutable_$bit_field_name$ = 0;\n",
+      "bit_field_name", GetBitFieldName(i));
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    printer->Print(
+      "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
+      "    com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
+  }
+
+  printer->Print(
+      "try {\n");
+  printer->Indent();
+
+  printer->Print(
+    "boolean done = false;\n"
+    "while (!done) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "int tag = input.readTag();\n"
+    "switch (tag) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "case 0:\n"          // zero signals EOF / limit reached
+    "  done = true;\n"
+    "  break;\n");
+
+  if (PreserveUnknownFields(descriptor_)) {
+    if (descriptor_->extension_range_count() > 0) {
+      // Lite runtime directly invokes parseUnknownField to reduce method
+      // counts.
+      printer->Print(
+        "default: {\n"
+        "  if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
+        "                         input, unknownFields,\n"
+        "                         extensionRegistry, tag)) {\n"
+        "    done = true;\n"  // it's an endgroup tag
+        "  }\n"
+        "  break;\n"
+        "}\n");
+    } else {
+      printer->Print(
+        "default: {\n"
+        "  if (!parseUnknownField(input, unknownFields,\n"
+        "                         extensionRegistry, tag)) {\n"
+        "    done = true;\n"  // it's an endgroup tag
+        "  }\n"
+        "  break;\n"
+        "}\n");
+    }
+  } else {
+    printer->Print(
+      "default: {\n"
+      "  if (!input.skipField(tag)) {\n"
+      "    done = true;\n"  // it's an endgroup tag
+      "  }\n"
+      "  break;\n"
+      "}\n");
+  }
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    uint32 tag = WireFormatLite::MakeTag(field->number(),
+      WireFormat::WireTypeForFieldType(field->type()));
+
+    printer->Print(
+      "case $tag$: {\n",
+      "tag", SimpleItoa(tag));
+    printer->Indent();
+
+    field_generators_.get(field).GenerateParsingCode(printer);
+
+    printer->Outdent();
+    printer->Print(
+      "  break;\n"
+      "}\n");
+
+    if (field->is_packable()) {
+      // To make packed = true wire compatible, we generate parsing code from a
+      // packed version of this field regardless of field->options().packed().
+      uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+        WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+      printer->Print(
+        "case $tag$: {\n",
+        "tag", SimpleItoa(packed_tag));
+      printer->Indent();
+
+      field_generators_.get(field).GenerateParsingCodeFromPacked(printer);
+
+      printer->Outdent();
+      printer->Print(
+        "  break;\n"
+        "}\n");
+    }
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "  }\n"     // switch (tag)
+      "}\n");     // while (!done)
+
+  printer->Outdent();
+  printer->Print(
+      "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
+      "  throw new RuntimeException(e.setUnfinishedMessage(this));\n"
+      "} catch (java.io.IOException e) {\n"
+      "  throw new RuntimeException(\n"
+      "      new com.google.protobuf.InvalidProtocolBufferException(\n"
+      "          e.getMessage()).setUnfinishedMessage(this));\n"
+      "} finally {\n");
+  printer->Indent();
+
+  // Make repeated field list immutable.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    field_generators_.get(field).GenerateParsingDoneCode(printer);
+  }
+
+  if (PreserveUnknownFields(descriptor_)) {
+    // Make unknown fields immutable.
+    printer->Print("this.unknownFields = unknownFields.build();\n");
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    // Make extensions immutable.
+    printer->Print(
+        "makeExtensionsImmutable(extensions);\n");
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+      "  }\n"     // finally
+      "}\n");
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) {
+  printer->Print(
+      "public static final com.google.protobuf.Parser<$classname$> PARSER =\n"
+      "    new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n"
+      "\n",
+      "classname", descriptor_->name());
+}
+
+// ===================================================================
+void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->containing_oneof()) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitializationCode(printer);
+    }
+  }
+}
+
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
new file mode 100644
index 0000000..2bd3cdd
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -0,0 +1,91 @@
+// 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.
+
+// Author: dweis@google.com (Daniel Weis)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
+
+#include <string>
+#include <map>
+#include <google/protobuf/compiler/java/java_field.h>
+#include <google/protobuf/compiler/java/java_message.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableMessageLiteGenerator : public MessageGenerator {
+ public:
+  explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor,
+                                     Context* context);
+  virtual ~ImmutableMessageLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+  virtual void GenerateInterface(io::Printer* printer);
+  virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
+  virtual void GenerateStaticVariables(io::Printer* printer);
+  virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+
+ private:
+
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateParseFromMethods(io::Printer* printer);
+  void GenerateSerializeOneField(io::Printer* printer,
+                                 const FieldDescriptor* field);
+  void GenerateSerializeOneExtensionRange(
+      io::Printer* printer, const Descriptor::ExtensionRange* range);
+
+  void GenerateBuilder(io::Printer* printer);
+  void GenerateDynamicMethodIsInitialized(io::Printer* printer);
+  void GenerateDynamicMethodMakeImmutable(io::Printer* printer);
+  void GenerateDynamicMethodMergeFrom(io::Printer* printer);
+  void GenerateDynamicMethodNewBuilder(io::Printer* printer);
+  void GenerateInitializers(io::Printer* printer);
+  void GenerateEqualsAndHashCode(io::Printer* printer);
+  void GenerateParser(io::Printer* printer);
+  void GenerateParsingConstructor(io::Printer* printer);
+
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  FieldGeneratorMap<ImmutableFieldLiteGenerator> field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 48757c6..7bebe12 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -74,7 +74,12 @@
       "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
   (*variables)["capitalized_type"] =
       GetCapitalizedType(descriptor, /* immutable = */ true);
-  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  if (descriptor->is_packed()) {
+    (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag(
+        descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+  } else {
+    (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  }
   (*variables)["tag_size"] = SimpleItoa(
       WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
   if (IsReferenceType(GetJavaType(descriptor))) {
@@ -599,7 +604,7 @@
     "  return $name$_.get(index);\n"
     "}\n");
 
-  if (descriptor_->options().packed() &&
+  if (descriptor_->is_packed() &&
       HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
@@ -771,7 +776,7 @@
 
 void RepeatedImmutablePrimitiveFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     // We invoke getSerializedSize in writeTo for messages that have packed
     // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
     // That makes it safe to rely on the memoized size here.
@@ -812,7 +817,7 @@
   printer->Print(
       "size += dataSize;\n");
 
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (!get$capitalized_name$List().isEmpty()) {\n"
       "  size += $tag_size$;\n"
@@ -825,7 +830,7 @@
   }
 
   // cache the data size for packed fields.
-  if (descriptor_->options().packed()) {
+  if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "$name$MemoizedSerializedSize = dataSize;\n");
   }
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
new file mode 100644
index 0000000..217ff9b
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -0,0 +1,892 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_primitive_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["field_type"] = (*variables)["type"];
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
+      "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
+  (*variables)["capitalized_type"] =
+      GetCapitalizedType(descriptor, /* immutable = */ true);
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+
+  string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(
+        GetJavaType(descriptor)), true /* cap_next_letter */);
+  switch (GetJavaType(descriptor)) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_FLOAT:
+    case JAVATYPE_DOUBLE:
+    case JAVATYPE_BOOLEAN:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal." + capitalized_type + "List";
+      (*variables)["new_list"] = "new" + capitalized_type + "List";
+      (*variables)["empty_list"] = "empty" + capitalized_type + "List()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_index_get"] =
+          (*variables)["name"] + "_.get" + capitalized_type + "(index)";
+      (*variables)["repeated_add"] =
+          (*variables)["name"] + "_.add" + capitalized_type;
+      (*variables)["repeated_set"] =
+          (*variables)["name"] + "_.set" + capitalized_type;
+      break;
+    default:
+      (*variables)["field_list_type"] =
+          "com.google.protobuf.Internal.ProtobufList<" +
+          (*variables)["boxed_type"] + ">";
+      (*variables)["new_list"] = "newProtobufList";
+      (*variables)["empty_list"] = "emptyProtobufList()";
+      (*variables)["make_name_unmodifiable"] =
+          (*variables)["name"] + "_.makeImmutable()";
+      (*variables)["repeated_index_get"] =
+          (*variables)["name"] + "_.get(index)";
+      (*variables)["repeated_add"] = (*variables)["name"] + "_.add";
+      (*variables)["repeated_set"] = (*variables)["name"] + "_.set";
+  }
+
+  if (IsReferenceType(GetJavaType(descriptor))) {
+    (*variables)["null_check"] =
+        "  if (value == null) {\n"
+        "    throw new NullPointerException();\n"
+        "  }\n";
+  } else {
+    (*variables)["null_check"] = "";
+  }
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  int fixed_size = FixedSize(GetType(descriptor));
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+  }
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+      (*variables)["is_field_present_message"] =
+          "!" + (*variables)["name"] + "_.isEmpty()";
+    } else {
+      (*variables)["is_field_present_message"] =
+          (*variables)["name"] + "_ != " + (*variables)["default"];
+    }
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutablePrimitiveFieldLiteGenerator::
+ImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $field_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n");
+  JavaType type = GetJavaType(descriptor_);
+  if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
+    // The default value is not a simple literal so we want to avoid executing
+    // it multiple times.  Instead, get the default out of the default instance.
+    printer->Print(variables_,
+      "  $name$_ = getDefaultInstance().get$capitalized_name$();\n");
+  } else {
+    printer->Print(variables_,
+      "  $name$_ = $default$;\n");
+  }
+  printer->Print(variables_,
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (other.get$capitalized_name$() != $default$) {\n"
+      "  set$capitalized_name$(other.get$capitalized_name$());\n"
+      "}\n");
+  }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$set_has_field_bit_message$\n"
+    "$name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for primitives.
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.write$capitalized_type$($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$capitalized_type$Size($number$, $name$_);\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  switch (GetJavaType(descriptor_)) {
+    case JAVATYPE_INT:
+    case JAVATYPE_LONG:
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+        "result = result && (get$capitalized_name$()\n"
+        "    == other.get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(variables_,
+        "result = result && (\n"
+        "    java.lang.Float.floatToIntBits(get$capitalized_name$())\n"
+        "    == java.lang.Float.floatToIntBits(\n"
+        "        other.get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "result = result && (\n"
+        "    java.lang.Double.doubleToLongBits(get$capitalized_name$())\n"
+        "    == java.lang.Double.doubleToLongBits(\n"
+        "        other.get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+      printer->Print(variables_,
+        "result = result && get$capitalized_name$()\n"
+        "    .equals(other.get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_ENUM:
+    case JAVATYPE_MESSAGE:
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      break;
+  }
+}
+
+void ImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n");
+  switch (GetJavaType(descriptor_)) {
+    case JAVATYPE_INT:
+      printer->Print(variables_,
+        "hash = (53 * hash) + get$capitalized_name$();\n");
+      break;
+
+    case JAVATYPE_LONG:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(variables_,
+        "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n"
+        "    java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_STRING:
+    case JAVATYPE_BYTES:
+      printer->Print(variables_,
+        "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+      break;
+
+    case JAVATYPE_ENUM:
+    case JAVATYPE_MESSAGE:
+    default:
+      GOOGLE_LOG(FATAL) << "Can't get here.";
+      break;
+  }
+}
+
+string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                 int messageBitIndex,
+                                 int builderBitIndex,
+                                 Context* context)
+    : ImmutablePrimitiveFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutablePrimitiveOneofFieldLiteGenerator::
+~ImmutablePrimitiveOneofFieldLiteGenerator() {}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $has_oneof_case_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    return ($boxed_type$) $oneof_name$_;\n"
+    "  }\n"
+    "  return $default$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+}
+
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "set$capitalized_name$(other.get$capitalized_name$());\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n"
+    "$oneof_name$_ = input.read$capitalized_type$();\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.write$capitalized_type$(\n"
+    "      $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+    "}\n");
+}
+
+void ImmutablePrimitiveOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .compute$capitalized_type$Size(\n"
+    "        $number$, ($type$)(($boxed_type$) $oneof_name$_));\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+RepeatedImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                         int messageBitIndex,
+                                         int builderBitIndex,
+                                         Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutablePrimitiveFieldLiteGenerator::
+~RepeatedImmutablePrimitiveFieldLiteGenerator() {}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+}
+
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private $field_list_type$ $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $repeated_index_get$;\n"
+    "}\n");
+
+  if (descriptor_->options().packed() &&
+      HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ = $new_list$($name$_);\n"
+    "   }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $repeated_set$(index, value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$($type$ value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $repeated_add$(value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList(\n"
+    "      instance.get$capitalized_name$List());\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // noop for primitives
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ = $new_list$();\n"
+    "}\n"
+    "$repeated_add$(input.read$capitalized_type$());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int limit = input.pushLimit(length);\n"
+    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
+    "  $name$_ = $new_list$();\n"
+    "}\n"
+    "while (input.getBytesUntilLimit() > 0) {\n"
+    "  $repeated_add$(input.read$capitalized_type$());\n"
+    "}\n"
+    "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $make_name_unmodifiable$;\n"
+    "}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    // We invoke getSerializedSize in writeTo for messages that have packed
+    // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods.
+    // That makes it safe to rely on the memoized size here.
+    printer->Print(variables_,
+      "if (get$capitalized_name$List().size() > 0) {\n"
+      "  output.writeRawVarint32($tag$);\n"
+      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "}\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$NoTag($name$_.get(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$($number$, $name$_.get(i));\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  if (FixedSize(GetType(descriptor_)) == -1) {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  dataSize += com.google.protobuf.CodedOutputStream\n"
+      "    .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  printer->Print(
+      "size += dataSize;\n");
+
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (!get$capitalized_name$List().isEmpty()) {\n"
+      "  size += $tag_size$;\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeInt32SizeNoTag(dataSize);\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutablePrimitiveFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
new file mode 100644
index 0000000..ad603c2
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -0,0 +1,163 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutablePrimitiveFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateBuilderClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator);
+};
+
+class ImmutablePrimitiveOneofFieldLiteGenerator
+    : public ImmutablePrimitiveFieldLiteGenerator {
+ public:
+  ImmutablePrimitiveOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutablePrimitiveOneofFieldLiteGenerator();
+
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutablePrimitiveFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutablePrimitiveFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  virtual ~RepeatedImmutablePrimitiveFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateBuilderClearCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateBuildingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 8aa5699..68e863c 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -208,7 +208,7 @@
 void ImmutableStringFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.lang.Object $name$_;\n");
+    "private volatile java.lang.Object $name$_;\n");
   PrintExtraFieldInfo(variables_, printer);
 
   if (SupportFieldPresence(descriptor_->file())) {
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
new file mode 100644
index 0000000..51bb245
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -0,0 +1,1013 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/compiler/java/java_string_field_lite.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex,
+                           const FieldGeneratorInfo* info,
+                           ClassNameResolver* name_resolver,
+                           map<string, string>* variables) {
+  SetCommonFieldVariables(descriptor, info, variables);
+
+  (*variables)["empty_list"] = "emptyLazyStringArrayList()";
+
+  (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["default_init"] =
+      "= " + ImmutableDefaultValue(descriptor, name_resolver);
+  (*variables)["capitalized_type"] = "String";
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
+  (*variables)["null_check"] =
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n";
+
+  // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
+  // by the proto compiler
+  (*variables)["deprecation"] = descriptor->options().deprecated()
+      ? "@java.lang.Deprecated " : "";
+  (*variables)["on_changed"] =
+      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+
+  if (SupportFieldPresence(descriptor->file())) {
+    // For singular messages and builders, one bit is used for the hasField bit.
+    (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+    // Note that these have a trailing ";".
+    (*variables)["set_has_field_bit_message"] =
+        GenerateSetBit(messageBitIndex) + ";";
+    (*variables)["clear_has_field_bit_message"] =
+        GenerateClearBit(messageBitIndex) + ";";
+
+    (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex);
+  } else {
+    (*variables)["set_has_field_bit_message"] = "";
+    (*variables)["clear_has_field_bit_message"] = "";
+
+    (*variables)["is_field_present_message"] =
+        "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()";
+  }
+
+  // For repeated builders, the underlying list tracks mutability state.
+  (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()";
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+bool CheckUtf8(const FieldDescriptor* descriptor) {
+  return descriptor->file()->options().java_string_check_utf8();
+}
+
+}  // namespace
+
+// ===================================================================
+
+ImmutableStringFieldLiteGenerator::
+ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                              int messageBitIndex,
+                              int builderBitIndex,
+                              Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+// A note about how strings are handled. This code used to just store a String
+// in the Message. This had two issues:
+//
+//  1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded
+//     strings, but rather fields that were raw bytes incorrectly marked
+//     as strings in the proto file. This is common because in the proto1
+//     syntax, string was the way to indicate bytes and C++ engineers can
+//     easily make this mistake without affecting the C++ API. By converting to
+//     strings immediately, some java code might corrupt these byte arrays as
+//     it passes through a java server even if the field was never accessed by
+//     application code.
+//
+//  2. There's a performance hit to converting between bytes and strings and
+//     it many cases, the field is never even read by the application code. This
+//     avoids unnecessary conversions in the common use cases.
+//
+// So now, the field for String is maintained as an Object reference which can
+// either store a String or a ByteString. The code uses an instanceof check
+// to see which one it has and converts to the other one if needed. It remembers
+// the last value requested (in a thread safe manner) as this is most likely
+// the one needed next. The thread safety is such that if two threads both
+// convert the field because the changes made by each thread were not visible to
+// the other, they may cause a conversion to happen more times than would
+// otherwise be necessary. This was deemed better than adding synchronization
+// overhead. It will not cause any corruption issues or affect the behavior of
+// the API. The instanceof check is also highly optimized in the JVM and we
+// decided it was better to reduce the memory overhead by not having two
+// separate fields but rather use dynamic type checking.
+//
+// For single fields, the logic for this is done inside the generated code. For
+// repeated fields, the logic is done in LazyStringArrayList and
+// UnmodifiableLazyStringList.
+void ImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$boolean has$capitalized_name$();\n");
+  }
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.lang.String get$capitalized_name$();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes();\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private java.lang.Object $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  java.lang.Object ref = $name$_;\n"
+    "  if (ref instanceof java.lang.String) {\n"
+    "    return (java.lang.String) ref;\n"
+    "  } else {\n"
+    "    com.google.protobuf.ByteString bs = \n"
+    "        (com.google.protobuf.ByteString) ref;\n"
+      "    java.lang.String s = bs.toStringUtf8();\n");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "    $name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+      "    if (bs.isValidUtf8()) {\n"
+      "      $name$_ = s;\n"
+      "    }\n");
+  }
+  printer->Print(variables_,
+    "    return s;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  java.lang.Object ref = $name$_;\n"
+    "  if (ref instanceof java.lang.String) {\n"
+    "    com.google.protobuf.ByteString b = \n"
+    "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+    "            (java.lang.String) ref);\n"
+    "    $name$_ = b;\n"
+    "    return b;\n"
+    "  } else {\n"
+    "    return (com.google.protobuf.ByteString) ref;\n"
+    "  }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_message$\n"
+    // The default value is not a simple literal so we want to avoid executing
+    // it multiple times.  Instead, get the default out of the default instance.
+    "  $name$_ = getDefaultInstance().get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  $set_has_field_bit_message$\n"
+    "  $name$_ = value;\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  return instance.get$capitalized_name$Bytes();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    // Allow a slight breach of abstraction here in order to avoid forcing
+    // all string fields to Strings when copying fields from a Message.
+    printer->Print(variables_,
+      "if (other.has$capitalized_name$()) {\n"
+      "  $set_has_field_bit_message$\n"
+      "  $name$_ = other.$name$_;\n"
+      "  $on_changed$\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (!other.get$capitalized_name$().isEmpty()) {\n"
+      "  $name$_ = other.$name$_;\n"
+      "  $on_changed$\n"
+      "}\n");
+  }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  // noop for scalars
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "String s = input.readStringRequireUtf8();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = s;\n");
+  } else if (!HasDescriptorMethods(descriptor_->file())) {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+      "String s = input.readString();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+      "com.google.protobuf.ByteString bs = input.readBytes();\n"
+      "$set_has_field_bit_message$\n"
+      "$name$_ = bs;\n");
+  }
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  // noop for strings
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_field_present_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void ImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n");
+  printer->Print(variables_,
+    "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
+string ImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "java.lang.String";
+}
+
+// ===================================================================
+
+ImmutableStringOneofFieldLiteGenerator::
+ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                   int messageBitIndex,
+                                   int builderBitIndex,
+                                   Context* context)
+    : ImmutableStringFieldLiteGenerator(
+          descriptor, messageBitIndex, builderBitIndex, context) {
+  const OneofGeneratorInfo* info =
+      context->GetOneofGeneratorInfo(descriptor->containing_oneof());
+  SetCommonOneofVariables(descriptor, info, &variables_);
+}
+
+ImmutableStringOneofFieldLiteGenerator::
+~ImmutableStringOneofFieldLiteGenerator() {}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  PrintExtraFieldInfo(variables_, printer);
+
+  if (SupportFieldPresence(descriptor_->file())) {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $has_oneof_case_message$;\n"
+    "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  java.lang.Object ref $default_init$;\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    ref = $oneof_name$_;\n"
+    "  }\n"
+    "  if (ref instanceof java.lang.String) {\n"
+    "    return (java.lang.String) ref;\n"
+    "  } else {\n"
+    "    com.google.protobuf.ByteString bs = \n"
+    "        (com.google.protobuf.ByteString) ref;\n"
+    "    java.lang.String s = bs.toStringUtf8();\n");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+    "    if ($has_oneof_case_message$) {\n"
+    "      $oneof_name$_ = s;\n"
+    "    }\n");
+  } else {
+    printer->Print(variables_,
+    "    if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n"
+    "      $oneof_name$_ = s;\n"
+    "    }\n");
+  }
+  printer->Print(variables_,
+    "    return s;\n"
+    "  }\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  java.lang.Object ref $default_init$;\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    ref = $oneof_name$_;\n"
+    "  }\n"
+    "  if (ref instanceof java.lang.String) {\n"
+    "    com.google.protobuf.ByteString b = \n"
+    "        com.google.protobuf.ByteString.copyFromUtf8(\n"
+    "            (java.lang.String) ref);\n"
+    "    if ($has_oneof_case_message$) {\n"
+    "      $oneof_name$_ = b;\n"
+    "    }\n"
+    "    return b;\n"
+    "  } else {\n"
+    "    return (com.google.protobuf.ByteString) ref;\n"
+    "  }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  if ($has_oneof_case_message$) {\n"
+    "    $clear_oneof_case_message$;\n"
+    "    $oneof_name$_ = null;\n"
+    "  }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  $set_oneof_case_message$;\n"
+    "  $oneof_name$_ = value;\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  if (SupportFieldPresence(descriptor_->file())) {
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return instance.has$capitalized_name$();\n"
+      "}\n");
+  }
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$() {\n"
+    "  return instance.get$capitalized_name$();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes() {\n"
+    "  return instance.get$capitalized_name$Bytes();\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  // Allow a slight breach of abstraction here in order to avoid forcing
+  // all string fields to Strings when copying fields from a Message.
+  printer->Print(variables_,
+    "$set_oneof_case_message$;\n"
+    "$oneof_name$_ = other.$oneof_name$_;\n"
+    "$on_changed$\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "String s = input.readStringRequireUtf8();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = s;\n");
+  } else if (!HasDescriptorMethods(descriptor_->file())) {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+      "String s = input.readString();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = s;\n");
+  } else {
+    printer->Print(variables_,
+      "com.google.protobuf.ByteString bs = input.readBytes();\n"
+      "$set_oneof_case_message$;\n"
+      "$oneof_name$_ = bs;\n");
+  }
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+void ImmutableStringOneofFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($has_oneof_case_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+// ===================================================================
+
+RepeatedImmutableStringFieldLiteGenerator::
+RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor,
+                                      int messageBitIndex,
+                                      int builderBitIndex,
+                                      Context* context)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        context->GetFieldGeneratorInfo(descriptor),
+                        name_resolver_, &variables_);
+}
+
+RepeatedImmutableStringFieldLiteGenerator::
+~RepeatedImmutableStringFieldLiteGenerator() {}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const {
+  return 0;
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$com.google.protobuf.ProtocolStringList\n"
+    "    get$capitalized_name$List();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$java.lang.String get$capitalized_name$(int index);\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index);\n");
+}
+
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.LazyStringArrayList $name$_;\n");
+  PrintExtraFieldInfo(variables_, printer);
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+    "    get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index) {\n"
+    "  return $name$_.getByteString(index);\n"
+    "}\n");
+
+  if (descriptor_->options().packed() &&
+      HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$is_mutable$) {\n"
+    "    $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
+    "   }\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void set$capitalized_name$(\n"
+    "    int index, java.lang.String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<java.lang.String> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  com.google.protobuf.AbstractMessageLite.addAll(\n"
+    "      values, $name$_);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "private void add$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "$null_check$");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  checkByteStringIsUtf8(value);\n");
+  }
+  printer->Print(variables_,
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ProtocolStringList\n"
+    "    get$capitalized_name$List() {\n"
+    "  return ((com.google.protobuf.LazyStringList)\n"
+    "      instance.get$capitalized_name$List()).getUnmodifiableView();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return instance.get$capitalized_name$Count();\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n"
+    "  return instance.get$capitalized_name$(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public com.google.protobuf.ByteString\n"
+    "    get$capitalized_name$Bytes(int index) {\n"
+    "  return instance.get$capitalized_name$Bytes(index);\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.set$capitalized_name$(index, value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    java.lang.String value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$(value);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<java.lang.String> values) {\n"
+    "  copyOnWrite();\n"
+    "  instance.addAll$capitalized_name$(values);\n"
+    "  return this;\n"
+    "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  copyOnWrite();\n"
+    "  instance.clear$capitalized_name$();\n"
+    "  return this;\n"
+    "}\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(variables_,
+    "$deprecation$public Builder add$capitalized_name$Bytes(\n"
+    "    com.google.protobuf.ByteString value) {\n"
+    "  copyOnWrite();\n"
+    "  instance.add$capitalized_name$Bytes(value);\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for strings
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  // The code below does two optimizations:
+  //   1. If the other list is empty, there's nothing to do. This ensures we
+  //      don't allocate a new array if we already have an immutable one.
+  //   2. If the other list is non-empty and our current list is empty, we can
+  //      reuse the other list which is guaranteed to be immutable.
+  printer->Print(variables_,
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_.makeImmutable();\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+    "String s = input.readStringRequireUtf8();\n");
+  } else if (!HasDescriptorMethods(descriptor_->file())) {
+    // Lite runtime should attempt to reduce allocations by attempting to
+    // construct the string directly from the input stream buffer. This avoids
+    // spurious intermediary ByteString allocations, cutting overall allocations
+    // in half.
+    printer->Print(variables_,
+    "String s = input.readString();\n");
+  } else {
+    printer->Print(variables_,
+    "com.google.protobuf.ByteString bs = input.readBytes();\n");
+  }
+  printer->Print(variables_,
+    "if (!$is_mutable$) {\n"
+    "  $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+    "}\n");
+  if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+    printer->Print(variables_,
+      "$name$_.add(s);\n");
+  } else {
+    printer->Print(variables_,
+      "$name$_.add(bs);\n");
+  }
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int limit = input.pushLimit(length);\n"
+    "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n"
+    "  $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
+    "}\n"
+    "while (input.getBytesUntilLimit() > 0) {\n");
+  if (CheckUtf8(descriptor_)) {
+    printer->Print(variables_,
+      "  String s = input.readStringRequireUtf8();\n");
+  } else {
+    printer->Print(variables_,
+      "  String s = input.readString();\n");
+  }
+  printer->Print(variables_,
+    "  $name$.add(s);\n");
+  printer->Print(variables_,
+    "}\n"
+    "input.popLimit(limit);\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateParsingDoneCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($is_mutable$) {\n"
+    "  $name$_.makeImmutable();\n"
+    "}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (get$capitalized_name$List().size() > 0) {\n"
+      "  output.writeRawVarint32($tag$);\n"
+      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "}\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$NoTag($name$_.get(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeBytes($number$, $name$_.getByteString(i));\n"
+      "}\n");
+  }
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  printer->Print(variables_,
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  dataSize += com.google.protobuf.CodedOutputStream\n"
+    "    .computeBytesSizeNoTag($name$_.getByteString(i));\n"
+    "}\n");
+
+  printer->Print(
+      "size += dataSize;\n");
+
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "if (!get$capitalized_name$List().isEmpty()) {\n"
+      "  size += $tag_size$;\n"
+      "  size += com.google.protobuf.CodedOutputStream\n"
+      "      .computeInt32SizeNoTag(dataSize);\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedImmutableStringFieldLiteGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + get$capitalized_name$List().hashCode();\n"
+    "}\n");
+}
+
+string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const {
+  return "String";
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
new file mode 100644
index 0000000..9d93b30
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -0,0 +1,158 @@
+// 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Author: jonp@google.com (Jon Perlow)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace compiler {
+    namespace java {
+      class Context;           // context.h
+      class ClassNameResolver; // name_resolver.h
+    }
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator {
+ public:
+  explicit ImmutableStringFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableStringFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ protected:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator);
+};
+
+class ImmutableStringOneofFieldLiteGenerator
+    : public ImmutableStringFieldLiteGenerator {
+ public:
+  ImmutableStringOneofFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~ImmutableStringOneofFieldLiteGenerator();
+
+ private:
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator);
+};
+
+class RepeatedImmutableStringFieldLiteGenerator
+    : public ImmutableFieldLiteGenerator {
+ public:
+  explicit RepeatedImmutableStringFieldLiteGenerator(
+      const FieldDescriptor* descriptor, int messageBitIndex,
+      int builderBitIndex, Context* context);
+  ~RepeatedImmutableStringFieldLiteGenerator();
+
+  // implements ImmutableFieldLiteGenerator ------------------------------------
+  int GetNumBitsForMessage() const;
+  int GetNumBitsForBuilder() const;
+  void GenerateInterfaceMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateBuilderMembers(io::Printer* printer) const;
+  void GenerateInitializationCode(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(io::Printer* printer) const;
+  void GenerateParsingDoneCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+  void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
+  void GenerateEqualsCode(io::Printer* printer) const;
+  void GenerateHashCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+  const int messageBitIndex_;
+  const int builderBitIndex_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index c50cdf5..a2eeee2 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -686,6 +686,8 @@
     LocationRecorder location(message_location,
                               DescriptorProto::kExtensionRangeFieldNumber);
     return ParseExtensions(message, location, containing_file);
+  } else if (LookingAt("reserved")) {
+    return ParseReserved(message, message_location);
   } else if (LookingAt("extend")) {
     LocationRecorder location(message_location,
                               DescriptorProto::kExtensionFieldNumber);
@@ -733,6 +735,13 @@
     FieldDescriptorProto::Label label;
     if (ParseLabel(&label, containing_file)) {
       field->set_label(label);
+      if (label == FieldDescriptorProto::LABEL_OPTIONAL &&
+          syntax_identifier_ == "proto3") {
+        AddError(
+            "Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+            "To define 'optional' fields in Proto3, simply remove the "
+            "'optional' label, as fields are 'optional' by default.");
+      }
     }
   }
 
@@ -1353,6 +1362,77 @@
   return true;
 }
 
+// This is similar to extension range parsing, except that "max" is not
+// supported, and accepts field name literals.
+bool Parser::ParseReserved(DescriptorProto* message,
+                           const LocationRecorder& message_location) {
+  // Parse the declaration.
+  DO(Consume("reserved"));
+  if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedNameFieldNumber);
+    return ParseReservedNames(message, location);
+  } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kReservedRangeFieldNumber);
+    return ParseReservedNumbers(message, location);
+  }
+}
+
+
+bool Parser::ParseReservedNames(DescriptorProto* message,
+                                const LocationRecorder& parent_location) {
+  do {
+    LocationRecorder location(parent_location, message->reserved_name_size());
+    DO(ConsumeString(message->add_reserved_name(), "Expected field name."));
+  } while (TryConsume(","));
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
+bool Parser::ParseReservedNumbers(DescriptorProto* message,
+                                  const LocationRecorder& parent_location) {
+  bool first = true;
+  do {
+    LocationRecorder location(parent_location, message->reserved_range_size());
+
+    DescriptorProto::ReservedRange* range = message->add_reserved_range();
+    int start, end;
+    io::Tokenizer::Token start_token;
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ReservedRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, (first ?
+                                 "Expected field name or number range." :
+                                 "Expected field number range.")));
+    }
+
+    if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      DO(ConsumeInteger(&end, "Expected integer."));
+    } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ReservedRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
+      end = start;
+    }
+
+    // Users like to specify inclusive ranges, but in code we like the end
+    // number to be exclusive.
+    ++end;
+
+    range->set_start(start);
+    range->set_end(end);
+    first = false;
+  } while (TryConsume(","));
+
+  DO(ConsumeEndOfDeclaration(";", &parent_location));
+  return true;
+}
+
 bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
                          RepeatedPtrField<DescriptorProto>* messages,
                          const LocationRecorder& parent_location,
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 7cb1678..16012e9 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -364,6 +364,14 @@
                        const LocationRecorder& extensions_location,
                        const FileDescriptorProto* containing_file);
 
+  // Parse an "reserved" declaration.
+  bool ParseReserved(DescriptorProto* message,
+                     const LocationRecorder& message_location);
+  bool ParseReservedNames(DescriptorProto* message,
+                          const LocationRecorder& parent_location);
+  bool ParseReservedNumbers(DescriptorProto* message,
+                            const LocationRecorder& parent_location);
+
   // Parse an "extend" declaration.  (See also comments for
   // ParseMessageField().)
   bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 1684beb..ddf34bf 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -620,6 +620,36 @@
     "}");
 }
 
+TEST_F(ParseMessageTest, ReservedRange) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  required int32 foo = 1;\n"
+    "  reserved 2, 15, 9 to 11, 3;\n"
+    "}\n",
+
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
+    "  reserved_range { start:2   end:3         }"
+    "  reserved_range { start:15  end:16        }"
+    "  reserved_range { start:9   end:12        }"
+    "  reserved_range { start:3   end:4         }"
+    "}");
+}
+
+TEST_F(ParseMessageTest, ReservedNames) {
+  ExpectParsesTo(
+    "message TestMessage {\n"
+    "  reserved \"foo\", \"bar\";\n"
+    "}\n",
+
+    "message_type {"
+    "  name: \"TestMessage\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "}");
+}
+
 TEST_F(ParseMessageTest, ExtensionRange) {
   ExpectParsesTo(
     "message TestMessage {\n"
@@ -715,19 +745,17 @@
     "            type_name:\"TestMessage\" extendee: \"Extendee1\" }");
 }
 
-TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) {
+TEST_F(ParseMessageTest, OptionalLabelProto3) {
   ExpectParsesTo(
     "syntax = \"proto3\";\n"
     "message TestMessage {\n"
     "  int32 foo = 1;\n"
-    "  optional int32 bar = 2;\n"
     "}\n",
 
     "syntax: \"proto3\" "
     "message_type {"
     "  name: \"TestMessage\""
-    "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }"
-    "  field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }");
+    "  field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }");
 }
 
 // ===================================================================
@@ -1230,6 +1258,18 @@
       "1:0: Unexpected end of stream while parsing aggregate value.\n");
 }
 
+TEST_F(ParseErrorTest, ExplicitOptionalLabelProto3) {
+  ExpectHasErrors(
+      "syntax = 'proto3';\n"
+      "message TestMessage {\n"
+      "  optional int32 foo = 1;\n"
+      "}\n",
+      "2:11: Explicit 'optional' labels are disallowed in the Proto3 syntax. "
+      "To define 'optional' fields in Proto3, simply remove the 'optional' "
+      "label, as fields are 'optional' by default.\n");
+}
+
+
 // -------------------------------------------------------------------
 // Enum errors
 
@@ -1248,6 +1288,33 @@
 }
 
 // -------------------------------------------------------------------
+// Reserved field number errors
+
+TEST_F(ParseErrorTest, ReservedMaxNotAllowed) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved 10 to max;\n"
+    "}\n",
+    "1:17: Expected integer.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMixNameAndNumber) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved 10, \"foo\";\n"
+    "}\n",
+    "1:15: Expected field number range.\n");
+}
+
+TEST_F(ParseErrorTest, ReservedMissingQuotes) {
+  ExpectHasErrors(
+    "message Foo {\n"
+    "  reserved foo;\n"
+    "}\n",
+    "1:11: Expected field name or number range.\n");
+}
+
+// -------------------------------------------------------------------
 // Service errors
 
 TEST_F(ParseErrorTest, EofInService) {
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index ad501ac..cdcaffd 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -134,20 +134,34 @@
   CodeGeneratorResponse response;
   GeneratorResponseContext context(&response, parsed_files);
 
-  for (int i = 0; i < parsed_files.size(); i++) {
-    const FileDescriptor* file = parsed_files[i];
-
+  if (generator->HasGenerateAll()) {
     string error;
-    bool succeeded = generator->Generate(
-        file, request.parameter(), &context, &error);
+    bool succeeded = generator->GenerateAll(
+        parsed_files, request.parameter(), &context, &error);
 
     if (!succeeded && error.empty()) {
       error = "Code generator returned false but provided no error "
               "description.";
     }
     if (!error.empty()) {
-      response.set_error(file->name() + ": " + error);
-      break;
+      response.set_error(error);
+    }
+  } else {
+    for (int i = 0; i < parsed_files.size(); i++) {
+      const FileDescriptor* file = parsed_files[i];
+
+      string error;
+      bool succeeded = generator->Generate(
+          file, request.parameter(), &context, &error);
+
+      if (!succeeded && error.empty()) {
+        error = "Code generator returned false but provided no error "
+                "description.";
+      }
+      if (!error.empty()) {
+        response.set_error(file->name() + ": " + error);
+        break;
+      }
     }
   }
 
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index d78b715..344ed45 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -179,7 +179,7 @@
 #endif  // !_MSC_VER
 
 CodeGeneratorRequest::CodeGeneratorRequest()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest)
 }
@@ -300,12 +300,15 @@
       case 15: {
         if (tag == 122) {
          parse_proto_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_proto_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_proto_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(122)) goto parse_proto_file;
+        if (input->ExpectTag(122)) goto parse_loop_proto_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -445,9 +448,9 @@
 
 void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorRequest* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>(
-      &from);
+  const CodeGeneratorRequest* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorRequest>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -513,10 +516,10 @@
 // CodeGeneratorRequest
 
 // repeated string file_to_generate = 1;
- int CodeGeneratorRequest::file_to_generate_size() const {
+int CodeGeneratorRequest::file_to_generate_size() const {
   return file_to_generate_.size();
 }
- void CodeGeneratorRequest::clear_file_to_generate() {
+void CodeGeneratorRequest::clear_file_to_generate() {
   file_to_generate_.Clear();
 }
  const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
@@ -567,16 +570,16 @@
 }
 
 // optional string parameter = 2;
- bool CodeGeneratorRequest::has_parameter() const {
+bool CodeGeneratorRequest::has_parameter() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void CodeGeneratorRequest::set_has_parameter() {
+void CodeGeneratorRequest::set_has_parameter() {
   _has_bits_[0] |= 0x00000002u;
 }
- void CodeGeneratorRequest::clear_has_parameter() {
+void CodeGeneratorRequest::clear_has_parameter() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void CodeGeneratorRequest::clear_parameter() {
+void CodeGeneratorRequest::clear_parameter() {
   parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_parameter();
 }
@@ -620,10 +623,10 @@
 }
 
 // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
- int CodeGeneratorRequest::proto_file_size() const {
+int CodeGeneratorRequest::proto_file_size() const {
   return proto_file_.size();
 }
- void CodeGeneratorRequest::clear_proto_file() {
+void CodeGeneratorRequest::clear_proto_file() {
   proto_file_.Clear();
 }
  const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
@@ -660,7 +663,7 @@
 #endif  // !_MSC_VER
 
 CodeGeneratorResponse_File::CodeGeneratorResponse_File()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File)
 }
@@ -946,9 +949,9 @@
 
 void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorResponse_File* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>(
-      &from);
+  const CodeGeneratorResponse_File* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse_File>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1024,7 +1027,7 @@
 #endif  // !_MSC_VER
 
 CodeGeneratorResponse::CodeGeneratorResponse()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse)
 }
@@ -1124,12 +1127,15 @@
       case 15: {
         if (tag == 122) {
          parse_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(122)) goto parse_file;
+        if (input->ExpectTag(122)) goto parse_loop_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1242,9 +1248,9 @@
 
 void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const CodeGeneratorResponse* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>(
-      &from);
+  const CodeGeneratorResponse* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const CodeGeneratorResponse>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1307,16 +1313,16 @@
 // CodeGeneratorResponse_File
 
 // optional string name = 1;
- bool CodeGeneratorResponse_File::has_name() const {
+bool CodeGeneratorResponse_File::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_name() {
+void CodeGeneratorResponse_File::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void CodeGeneratorResponse_File::clear_has_name() {
+void CodeGeneratorResponse_File::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void CodeGeneratorResponse_File::clear_name() {
+void CodeGeneratorResponse_File::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -1360,16 +1366,16 @@
 }
 
 // optional string insertion_point = 2;
- bool CodeGeneratorResponse_File::has_insertion_point() const {
+bool CodeGeneratorResponse_File::has_insertion_point() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_insertion_point() {
+void CodeGeneratorResponse_File::set_has_insertion_point() {
   _has_bits_[0] |= 0x00000002u;
 }
- void CodeGeneratorResponse_File::clear_has_insertion_point() {
+void CodeGeneratorResponse_File::clear_has_insertion_point() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void CodeGeneratorResponse_File::clear_insertion_point() {
+void CodeGeneratorResponse_File::clear_insertion_point() {
   insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_insertion_point();
 }
@@ -1413,16 +1419,16 @@
 }
 
 // optional string content = 15;
- bool CodeGeneratorResponse_File::has_content() const {
+bool CodeGeneratorResponse_File::has_content() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void CodeGeneratorResponse_File::set_has_content() {
+void CodeGeneratorResponse_File::set_has_content() {
   _has_bits_[0] |= 0x00000004u;
 }
- void CodeGeneratorResponse_File::clear_has_content() {
+void CodeGeneratorResponse_File::clear_has_content() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void CodeGeneratorResponse_File::clear_content() {
+void CodeGeneratorResponse_File::clear_content() {
   content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_content();
 }
@@ -1470,16 +1476,16 @@
 // CodeGeneratorResponse
 
 // optional string error = 1;
- bool CodeGeneratorResponse::has_error() const {
+bool CodeGeneratorResponse::has_error() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void CodeGeneratorResponse::set_has_error() {
+void CodeGeneratorResponse::set_has_error() {
   _has_bits_[0] |= 0x00000001u;
 }
- void CodeGeneratorResponse::clear_has_error() {
+void CodeGeneratorResponse::clear_has_error() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void CodeGeneratorResponse::clear_error() {
+void CodeGeneratorResponse::clear_error() {
   error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_error();
 }
@@ -1523,10 +1529,10 @@
 }
 
 // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
- int CodeGeneratorResponse::file_size() const {
+int CodeGeneratorResponse::file_size() const {
   return file_.size();
 }
- void CodeGeneratorResponse::clear_file() {
+void CodeGeneratorResponse::clear_file() {
   file_.Clear();
 }
  const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index ea48b8b..6fcaea2 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -796,6 +796,10 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index bfdacd9..2855c37 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1518,6 +1518,18 @@
   return NULL;
 }
 
+const Descriptor::ReservedRange*
+Descriptor::FindReservedRangeContainingNumber(int number) const {
+  // TODO(chrisn): Consider a non-linear search.
+  for (int i = 0; i < reserved_range_count(); i++) {
+    if (number >= reserved_range(i)->start &&
+        number <  reserved_range(i)->end) {
+      return reserved_range(i);
+    }
+  }
+  return NULL;
+}
+
 // -------------------------------------------------------------------
 
 bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
@@ -1741,6 +1753,14 @@
   for (int i = 0; i < extension_count(); i++) {
     extension(i)->CopyTo(proto->add_extension());
   }
+  for (int i = 0; i < reserved_range_count(); i++) {
+    DescriptorProto::ReservedRange* range = proto->add_reserved_range();
+    range->set_start(reserved_range(i)->start);
+    range->set_end(reserved_range(i)->end);
+  }
+  for (int i = 0; i < reserved_name_count(); i++) {
+    proto->add_reserved_name(reserved_name(i));
+  }
 
   if (&options() != &MessageOptions::default_instance()) {
     proto->mutable_options()->CopyFrom(options());
@@ -2186,6 +2206,29 @@
   if (extension_count() > 0)
     strings::SubstituteAndAppend(contents, "$0  }\n", prefix);
 
+  if (reserved_range_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_range_count(); i++) {
+      const Descriptor::ReservedRange* range = reserved_range(i);
+      if (range->end == range->start + 1) {
+        strings::SubstituteAndAppend(contents, "$0, ", range->start);
+      } else {
+        strings::SubstituteAndAppend(contents, "$0 to $1, ",
+                                     range->start, range->end - 1);
+      }
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
+  if (reserved_name_count() > 0) {
+    strings::SubstituteAndAppend(contents, "$0  reserved ", prefix);
+    for (int i = 0; i < reserved_name_count(); i++) {
+      strings::SubstituteAndAppend(contents, "\"$0\", ",
+                                   CEscape(reserved_name(i)));
+    }
+    contents->replace(contents->size() - 2, 2, ";\n");
+  }
+
   strings::SubstituteAndAppend(contents, "$0}\n", prefix);
   comment_printer.AddPostComment(contents);
 }
@@ -2278,8 +2321,12 @@
   }
 
   if (type() == TYPE_GROUP) {
-    message_type()->DebugString(depth, contents, debug_string_options,
-                                /* include_opening_clause */ false);
+    if (debug_string_options.elide_group_body) {
+      contents->append(" { ... };\n");
+    } else {
+      message_type()->DebugString(depth, contents, debug_string_options,
+                                  /* include_opening_clause */ false);
+    }
   } else {
     contents->append(";\n");
   }
@@ -2308,12 +2355,16 @@
       comment_printer(this, prefix, debug_string_options);
   comment_printer.AddPreComment(contents);
   strings::SubstituteAndAppend(
-      contents, "$0 oneof $1 {\n", prefix, name());
-  for (int i = 0; i < field_count(); i++) {
-    field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents,
-                          debug_string_options);
+      contents, "$0 oneof $1 {", prefix, name());
+  if (debug_string_options.elide_oneof_body) {
+    contents->append(" ... }\n");
+  } else {
+    for (int i = 0; i < field_count(); i++) {
+      field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents,
+                            debug_string_options);
+    }
+    strings::SubstituteAndAppend(contents, "$0}\n", prefix);
   }
-  strings::SubstituteAndAppend(contents, "$0}\n", prefix);
   comment_printer.AddPostComment(contents);
 }
 
@@ -2491,7 +2542,12 @@
 }
 
 bool FieldDescriptor::is_packed() const {
-  return is_packable() && (options_ != NULL) && options_->packed();
+  if (!is_packable()) return false;
+  if (file_->syntax() == FileDescriptor::SYNTAX_PROTO2) {
+    return (options_ != NULL) && options_->packed();
+  } else {
+    return options_ == NULL || !options_->has_packed() || options_->packed();
+  }
 }
 
 bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
@@ -2604,7 +2660,7 @@
 namespace {
 
 // Represents an options message to interpret. Extension names in the option
-// name are respolved relative to name_scope. element_name and orig_opt are
+// name are resolved relative to name_scope. element_name and orig_opt are
 // used only for error reporting (since the parser records locations against
 // pointers in the original options, not the mutable copy). The Message must be
 // one of the Options messages in descriptor.proto.
@@ -2830,6 +2886,9 @@
   void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
                            const Descriptor* parent,
                            Descriptor::ExtensionRange* result);
+  void BuildReservedRange(const DescriptorProto::ReservedRange& proto,
+                           const Descriptor* parent,
+                           Descriptor::ReservedRange* result);
   void BuildOneof(const OneofDescriptorProto& proto,
                   Descriptor* parent,
                   OneofDescriptor* result);
@@ -3920,6 +3979,17 @@
   BUILD_ARRAY(proto, result, enum_type      , BuildEnum          , result);
   BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
   BUILD_ARRAY(proto, result, extension      , BuildExtension     , result);
+  BUILD_ARRAY(proto, result, reserved_range , BuildReservedRange , result);
+
+  // Copy reserved names.
+  int reserved_name_count = proto.reserved_name_size();
+  result->reserved_name_count_ = reserved_name_count;
+  result->reserved_names_ =
+      tables_->AllocateArray<const string*>(reserved_name_count);
+  for (int i = 0; i < reserved_name_count; ++i) {
+    result->reserved_names_[i] =
+        tables_->AllocateString(proto.reserved_name(i));
+  }
 
   // Copy options.
   if (!proto.has_options()) {
@@ -3931,7 +4001,34 @@
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 
-  // Check that no fields have numbers in extension ranges.
+  for (int i = 0; i < proto.reserved_range_size(); i++) {
+    const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i);
+    for (int j = i + 1; j < proto.reserved_range_size(); j++) {
+      const DescriptorProto_ReservedRange& range2 = proto.reserved_range(j);
+      if (range1.end() > range2.start() && range2.end() > range1.start()) {
+        AddError(result->full_name(), proto.reserved_range(i),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Reserved range $0 to $1 overlaps with "
+                                     "already-defined range $2 to $3.",
+                                     range2.start(), range2.end() - 1,
+                                     range1.start(), range1.end() - 1));
+      }
+    }
+  }
+
+  hash_set<string> reserved_name_set;
+  for (int i = 0; i < proto.reserved_name_size(); i++) {
+    const string& name = proto.reserved_name(i);
+    if (reserved_name_set.find(name) == reserved_name_set.end()) {
+      reserved_name_set.insert(name);
+    } else {
+      AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute(
+                 "Field name \"$0\" is reserved multiple times.",
+                 name));
+    }
+  }
+
   for (int i = 0; i < result->field_count(); i++) {
     const FieldDescriptor* field = result->field(i);
     for (int j = 0; j < result->extension_range_count(); j++) {
@@ -3945,11 +4042,39 @@
                    field->name(), field->number()));
       }
     }
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range = result->reserved_range(j);
+      if (range->start <= field->number() && field->number() < range->end) {
+        AddError(field->full_name(), proto.reserved_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute(
+                   "Field \"$0\" uses reserved number $1.",
+                   field->name(), field->number()));
+      }
+    }
+    if (reserved_name_set.find(field->name()) != reserved_name_set.end()) {
+      AddError(field->full_name(), proto.field(i),
+               DescriptorPool::ErrorCollector::NAME,
+               strings::Substitute(
+                 "Field name \"$0\" is reserved.", field->name()));
+    }
   }
 
-  // Check that extension ranges don't overlap.
+  // Check that extension ranges don't overlap and don't include
+  // reserved field numbers.
   for (int i = 0; i < result->extension_range_count(); i++) {
     const Descriptor::ExtensionRange* range1 = result->extension_range(i);
+    for (int j = 0; j < result->reserved_range_count(); j++) {
+      const Descriptor::ReservedRange* range2 = result->reserved_range(j);
+      if (range1->end > range2->start && range2->end > range1->start) {
+        AddError(result->full_name(), proto.extension_range(j),
+                 DescriptorPool::ErrorCollector::NUMBER,
+                 strings::Substitute("Extension range $0 to $1 overlaps with "
+                                     "reserved range $2 to $3.",
+                                     range1->start, range1->end - 1,
+                                     range2->start, range2->end - 1));
+      }
+    }
     for (int j = i + 1; j < result->extension_range_count(); j++) {
       const Descriptor::ExtensionRange* range2 = result->extension_range(j);
       if (range1->end > range2->start && range2->end > range1->start) {
@@ -4262,6 +4387,19 @@
   }
 }
 
+void DescriptorBuilder::BuildReservedRange(
+    const DescriptorProto::ReservedRange& proto,
+    const Descriptor* parent,
+    Descriptor::ReservedRange* result) {
+  result->start = proto.start();
+  result->end = proto.end();
+  if (result->start <= 0) {
+    AddError(parent->full_name(), proto,
+             DescriptorPool::ErrorCollector::NUMBER,
+             "Reserved numbers must be positive integers.");
+  }
+}
+
 void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
                                    Descriptor* parent,
                                    OneofDescriptor* result) {
@@ -4503,6 +4641,23 @@
   for (int i = 0; i < message->field_count(); i++) {
     const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
     if (oneof_decl != NULL) {
+      // Make sure fields belonging to the same oneof are defined consecutively.
+      // This enables optimizations in codegens and reflection libraries to
+      // skip fields in the oneof group, as only one of the field can be set.
+      // Note that field_count() returns how many fields in this oneof we have
+      // seen so far. field_count() > 0 guarantees that i > 0, so field(i-1) is
+      // safe.
+      if (oneof_decl->field_count() > 0 &&
+          message->field(i - 1)->containing_oneof() != oneof_decl) {
+        AddWarning(
+            message->full_name() + "." + message->field(i - 1)->name(),
+            proto.field(i - 1), DescriptorPool::ErrorCollector::OTHER,
+            strings::Substitute(
+                "Fields in the same oneof must be defined consecutively. "
+                "\"$0\" cannot be defined before the completion of the "
+                "\"$1\" oneof definition.",
+                message->field(i - 1)->name(), oneof_decl->name()));
+      }
       // Must go through oneof_decls_ array to get a non-const version of the
       // OneofDescriptor.
       ++message->oneof_decls_[oneof_decl->index()].field_count_;
@@ -4933,6 +5088,12 @@
              field->containing_type()->full_name() +
              "\" which is a proto3 message type.");
   }
+  bool allow_groups = false;
+  if (field->type() == FieldDescriptor::TYPE_GROUP && !allow_groups) {
+    AddError(field->full_name(), proto,
+             DescriptorPool::ErrorCollector::TYPE,
+             "Groups are not supported in proto3 syntax.");
+  }
 }
 
 void DescriptorBuilder::ValidateProto3Enum(
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index c0a48ce..ca87d63 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -135,10 +135,14 @@
   // example, the C++ code generation for fields in the proto compiler) rely on
   // DebugString() output being unobstructed by user comments.
   bool include_comments;
+  // If true, elide the braced body in the debug string.
+  bool elide_group_body;
+  bool elide_oneof_body;
 
   DebugStringOptions()
-      : include_comments(false)
-  {}
+      : include_comments(false),
+        elide_group_body(false),
+        elide_oneof_body(false) {}
 };
 
 // Describes a type of protocol message, or a particular group within a
@@ -298,6 +302,36 @@
   // this message type's scope.
   const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
 
+  // Reserved fields -------------------------------------------------
+
+  // A range of reserved field numbers.
+  struct ReservedRange {
+    int start;  // inclusive
+    int end;    // exclusive
+  };
+
+  // The number of reserved ranges in this message type.
+  int reserved_range_count() const;
+  // Gets an reserved range by index, where 0 <= index <
+  // reserved_range_count(). These are returned in the order they were defined
+  // in the .proto file.
+  const ReservedRange* reserved_range(int index) const;
+
+  // Returns true if the number is in one of the reserved ranges.
+  bool IsReservedNumber(int number) const;
+
+  // Returns NULL if no reserved range contains the given number.
+  const ReservedRange* FindReservedRangeContainingNumber(int number) const;
+
+  // The number of reserved field names in this message type.
+  int reserved_name_count() const;
+
+  // Gets a reserved name by index, where 0 <= index < reserved_name_count().
+  const string& reserved_name(int index) const;
+
+  // Returns true if the field name is reserved.
+  bool IsReservedName(const string& name) const;
+
   // Source Location ---------------------------------------------------
 
   // Updates |*out_location| to the source location of the complete
@@ -343,6 +377,10 @@
   ExtensionRange* extension_ranges_;
   int extension_count_;
   FieldDescriptor* extensions_;
+  int reserved_range_count_;
+  ReservedRange* reserved_ranges_;
+  int reserved_name_count_;
+  const string** reserved_names_;
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<Descriptor>() and AllocateArray<Descriptor>() in descriptor.cc
   // and update them to initialize the field.
@@ -1567,6 +1605,12 @@
                                const Descriptor::ExtensionRange*)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension,
                                const FieldDescriptor*)
+
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_range_count, int)
+PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range,
+                               const Descriptor::ReservedRange*)
+PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int)
+
 PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
 PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool)
 
@@ -1667,6 +1711,25 @@
   return FindExtensionRangeContainingNumber(number) != NULL;
 }
 
+inline bool Descriptor::IsReservedNumber(int number) const {
+  return FindReservedRangeContainingNumber(number) != NULL;
+}
+
+inline bool Descriptor::IsReservedName(const string& name) const {
+  for (int i = 0; i < reserved_name_count(); i++) {
+    if (name == reserved_name(i)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because reserved_names_ is actually
+// an array of pointers rather than the usual array of objects.
+inline const string& Descriptor::reserved_name(int index) const {
+  return *reserved_names_[index];
+}
+
 inline bool FieldDescriptor::is_required() const {
   return label() == LABEL_REQUIRED;
 }
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 8968f36..755c261 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -33,6 +33,9 @@
 const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   DescriptorProto_ExtensionRange_reflection_ = NULL;
+const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DescriptorProto_ReservedRange_reflection_ = NULL;
 const ::google::protobuf::Descriptor* FieldDescriptorProto_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   FieldDescriptorProto_reflection_ = NULL;
@@ -64,6 +67,7 @@
 const ::google::protobuf::internal::GeneratedMessageReflection*
   FieldOptions_reflection_ = NULL;
 const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor_ = NULL;
 const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   EnumOptions_reflection_ = NULL;
@@ -140,7 +144,7 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_),
       -1);
   DescriptorProto_descriptor_ = file->message_type(2);
-  static const int DescriptorProto_offsets_[8] = {
+  static const int DescriptorProto_offsets_[10] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_),
@@ -149,6 +153,8 @@
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, oneof_decl_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_range_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_name_),
   };
   DescriptorProto_reflection_ =
     ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -177,6 +183,22 @@
       sizeof(DescriptorProto_ExtensionRange),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_),
       -1);
+  DescriptorProto_ReservedRange_descriptor_ = DescriptorProto_descriptor_->nested_type(1);
+  static const int DescriptorProto_ReservedRange_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, start_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, end_),
+  };
+  DescriptorProto_ReservedRange_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DescriptorProto_ReservedRange_descriptor_,
+      DescriptorProto_ReservedRange::default_instance_,
+      DescriptorProto_ReservedRange_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _has_bits_[0]),
+      -1,
+      -1,
+      sizeof(DescriptorProto_ReservedRange),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_),
+      -1);
   FieldDescriptorProto_descriptor_ = file->message_type(3);
   static const int FieldDescriptorProto_offsets_[9] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_),
@@ -338,9 +360,10 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_),
       -1);
   FieldOptions_descriptor_ = file->message_type(11);
-  static const int FieldOptions_offsets_[6] = {
+  static const int FieldOptions_offsets_[7] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, jstype_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, lazy_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, weak_),
@@ -358,6 +381,7 @@
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_),
       -1);
   FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
+  FieldOptions_JSType_descriptor_ = FieldOptions_descriptor_->enum_type(1);
   EnumOptions_descriptor_ = file->message_type(12);
   static const int EnumOptions_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
@@ -515,6 +539,8 @@
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DescriptorProto_ReservedRange_descriptor_, &DescriptorProto_ReservedRange::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       OneofDescriptorProto_descriptor_, &OneofDescriptorProto::default_instance());
@@ -561,6 +587,8 @@
   delete DescriptorProto_reflection_;
   delete DescriptorProto_ExtensionRange::default_instance_;
   delete DescriptorProto_ExtensionRange_reflection_;
+  delete DescriptorProto_ReservedRange::default_instance_;
+  delete DescriptorProto_ReservedRange_reflection_;
   delete FieldDescriptorProto::default_instance_;
   delete FieldDescriptorProto_reflection_;
   delete OneofDescriptorProto::default_instance_;
@@ -619,7 +647,7 @@
     "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File"
     "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog"
     "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001"
-    "(\t\"\344\003\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
+    "(\t\"\360\004\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005"
     "field\030\002 \003(\0132%.google.protobuf.FieldDescr"
     "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p"
     "rotobuf.FieldDescriptorProto\0225\n\013nested_t"
@@ -630,104 +658,111 @@
     "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo"
     "gle.protobuf.OneofDescriptorProto\0220\n\007opt"
     "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti"
-    "ons\032,\n\016ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003"
-    "end\030\002 \001(\005\"\251\005\n\024FieldDescriptorProto\022\014\n\004na"
-    "me\030\001 \001(\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162"
-    "+.google.protobuf.FieldDescriptorProto.L"
-    "abel\0228\n\004type\030\005 \001(\0162*.google.protobuf.Fie"
-    "ldDescriptorProto.Type\022\021\n\ttype_name\030\006 \001("
-    "\t\022\020\n\010extendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001"
-    "(\t\022\023\n\013oneof_index\030\t \001(\005\022.\n\007options\030\010 \001(\013"
-    "2\035.google.protobuf.FieldOptions\"\266\002\n\004Type"
-    "\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYP"
-    "E_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32"
-    "\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r"
-    "\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_G"
-    "ROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014"
-    "\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE"
-    "_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_S"
-    "INT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LAB"
-    "EL_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LAB"
-    "EL_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n"
-    "\004name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004n"
-    "ame\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protob"
-    "uf.EnumValueDescriptorProto\022-\n\007options\030\003"
-    " \001(\0132\034.google.protobuf.EnumOptions\"l\n\030En"
-    "umValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006"
-    "number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.p"
-    "rotobuf.EnumValueOptions\"\220\001\n\026ServiceDesc"
-    "riptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003("
-    "\0132&.google.protobuf.MethodDescriptorProt"
-    "o\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Ser"
-    "viceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n"
-    "\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outpu"
-    "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p"
-    "rotobuf.MethodOptions\022\037\n\020client_streamin"
-    "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010"
-    ":\005false\"\201\005\n\013FileOptions\022\024\n\014java_package\030"
-    "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j"
-    "ava_multiple_files\030\n \001(\010:\005false\022,\n\035java_"
-    "generate_equals_and_hash\030\024 \001(\010:\005false\022%\n"
-    "\026java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014"
-    "optimize_for\030\t \001(\0162).google.protobuf.Fil"
-    "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa"
-    "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f"
-    "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal"
-    "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031"
-    "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a"
-    "renas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030"
-    "$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024unint"
-    "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
-    ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005"
-    "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003"
-    "*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027messag"
-    "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta"
-    "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031"
-    "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007"
-    " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
-    "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
-    "\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g"
-    "oogle.protobuf.FieldOptions.CType:\006STRIN"
-    "G\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022\031"
-    "\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:"
-    "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
-    "google.protobuf.UninterpretedOption\"/\n\005C"
-    "Type\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIE"
-    "CE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow"
-    "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022"
-    "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google."
-    "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\""
-    "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:"
-    "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$."
-    "google.protobuf.UninterpretedOption*\t\010\350\007"
-    "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!"
+    "ons\022F\n\016reserved_range\030\t \003(\0132..google.pro"
+    "tobuf.DescriptorProto.ReservedRange\022\025\n\rr"
+    "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005"
+    "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang"
+    "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024FieldD"
+    "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003"
+    " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi"
+    "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*"
+    ".google.protobuf.FieldDescriptorProto.Ty"
+    "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022"
+    "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t "
+    "\001(\005\022.\n\007options\030\010 \001(\0132\035.google.protobuf.F"
+    "ieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n"
+    "\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UI"
+    "NT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006"
+    "\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYP"
+    "E_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSA"
+    "GE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n"
+    "\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_"
+    "SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT"
+    "64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LAB"
+    "EL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n\024One"
+    "ofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023Enum"
+    "DescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002"
+    " \003(\0132).google.protobuf.EnumValueDescript"
+    "orProto\022-\n\007options\030\003 \001(\0132\034.google.protob"
+    "uf.EnumOptions\"l\n\030EnumValueDescriptorPro"
+    "to\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007opti"
+    "ons\030\003 \001(\0132!.google.protobuf.EnumValueOpt"
+    "ions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004name\030"
+    "\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.protobuf."
+    "MethodDescriptorProto\0220\n\007options\030\003 \001(\0132\037"
+    ".google.protobuf.ServiceOptions\"\301\001\n\025Meth"
+    "odDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput"
+    "_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007opti"
+    "ons\030\004 \001(\0132\036.google.protobuf.MethodOption"
+    "s\022\037\n\020client_streaming\030\005 \001(\010:\005false\022\037\n\020se"
+    "rver_streaming\030\006 \001(\010:\005false\"\201\005\n\013FileOpti"
+    "ons\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_"
+    "classname\030\010 \001(\t\022\"\n\023java_multiple_files\030\n"
+    " \001(\010:\005false\022,\n\035java_generate_equals_and_"
+    "hash\030\024 \001(\010:\005false\022%\n\026java_string_check_u"
+    "tf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001(\0162)"
+    ".google.protobuf.FileOptions.OptimizeMod"
+    "e:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_gener"
+    "ic_services\030\020 \001(\010:\005false\022$\n\025java_generic"
+    "_services\030\021 \001(\010:\005false\022\"\n\023py_generic_ser"
+    "vices\030\022 \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005"
+    "false\022\037\n\020cc_enable_arenas\030\037 \001(\010:\005false\022\031"
+    "\n\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_name"
+    "space\030% \001(\t\022C\n\024uninterpreted_option\030\347\007 \003"
+    "(\0132$.google.protobuf.UninterpretedOption"
+    "\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE"
+    "\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016Mess"
+    "ageOptions\022&\n\027message_set_wire_format\030\001 "
+    "\001(\010:\005false\022.\n\037no_standard_descriptor_acc"
+    "essor\030\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005"
+    "false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterprete"
+    "d_option\030\347\007 \003(\0132$.google.protobuf.Uninte"
+    "rpretedOption*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOption"
+    "s\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Field"
+    "Options.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n"
+    "\006jstype\030\006 \001(\0162$.google.protobuf.FieldOpt"
+    "ions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005fa"
+    "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n"
     " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
     "(\0132$.google.protobuf.UninterpretedOption"
-    "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat"
-    "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030"
-    "\347\007 \003(\0132$.google.protobuf.UninterpretedOp"
-    "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022"
-    ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp"
-    "retedOption.NamePart\022\030\n\020identifier_value"
-    "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne"
-    "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006"
-    " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_"
-    "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002"
-    "(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceCodeI"
-    "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf."
-    "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004"
-    "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead"
-    "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030"
-    "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t"
-    "BY\n\023com.google.protobufB\020DescriptorProto"
-    "sH\001\242\002\003GPB\252\002\'Google.ProtocolBuffers.Descr"
-    "iptorProtos", 4691);
+    "\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRIN"
+    "G_PIECE\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS"
+    "_STRING\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013"
+    "EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndepr"
+    "ecated\030\003 \001(\010:\005false\022C\n\024uninterpreted_opt"
+    "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret"
+    "edOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions\022"
+    "\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uninterpre"
+    "ted_option\030\347\007 \003(\0132$.google.protobuf.Unin"
+    "terpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOpt"
+    "ions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024unint"
+    "erpreted_option\030\347\007 \003(\0132$.google.protobuf"
+    ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMetho"
+    "dOptions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023"
+    "UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goog"
+    "le.protobuf.UninterpretedOption.NamePart"
+    "\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_i"
+    "nt_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001"
+    "(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_value"
+    "\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NameP"
+    "art\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002"
+    " \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003("
+    "\0132(.google.protobuf.SourceCodeInfo.Locat"
+    "ion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004sp"
+    "an\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031"
+    "\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_det"
+    "ached_comments\030\006 \003(\tBY\n\023com.google.proto"
+    "bufB\020DescriptorProtosH\001\242\002\003GPB\252\002\'Google.P"
+    "rotocolBuffers.DescriptorProtos", 4951);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   FileDescriptorSet::default_instance_ = new FileDescriptorSet();
   FileDescriptorProto::default_instance_ = new FileDescriptorProto();
   DescriptorProto::default_instance_ = new DescriptorProto();
   DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange();
+  DescriptorProto_ReservedRange::default_instance_ = new DescriptorProto_ReservedRange();
   FieldDescriptorProto::default_instance_ = new FieldDescriptorProto();
   OneofDescriptorProto::default_instance_ = new OneofDescriptorProto();
   EnumDescriptorProto::default_instance_ = new EnumDescriptorProto();
@@ -749,6 +784,7 @@
   FileDescriptorProto::default_instance_->InitAsDefaultInstance();
   DescriptorProto::default_instance_->InitAsDefaultInstance();
   DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance();
+  DescriptorProto_ReservedRange::default_instance_->InitAsDefaultInstance();
   FieldDescriptorProto::default_instance_->InitAsDefaultInstance();
   OneofDescriptorProto::default_instance_->InitAsDefaultInstance();
   EnumDescriptorProto::default_instance_->InitAsDefaultInstance();
@@ -793,7 +829,7 @@
 #endif  // !_MSC_VER
 
 FileDescriptorSet::FileDescriptorSet()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorSet)
 }
@@ -870,13 +906,15 @@
       // repeated .google.protobuf.FileDescriptorProto file = 1;
       case 1: {
         if (tag == 10) {
-         parse_file:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_file()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_file;
+        if (input->ExpectTag(10)) goto parse_loop_file;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -961,9 +999,9 @@
 
 void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileDescriptorSet* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorSet*>(
-      &from);
+  const FileDescriptorSet* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorSet>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1020,10 +1058,10 @@
 // FileDescriptorSet
 
 // repeated .google.protobuf.FileDescriptorProto file = 1;
- int FileDescriptorSet::file_size() const {
+int FileDescriptorSet::file_size() const {
   return file_.size();
 }
- void FileDescriptorSet::clear_file() {
+void FileDescriptorSet::clear_file() {
   file_.Clear();
 }
  const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const {
@@ -1069,7 +1107,7 @@
 #endif  // !_MSC_VER
 
 FileDescriptorProto::FileDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorProto)
 }
@@ -1237,54 +1275,63 @@
       case 4: {
         if (tag == 34) {
          parse_message_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_message_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_message_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(34)) goto parse_message_type;
-        if (input->ExpectTag(42)) goto parse_enum_type;
+        if (input->ExpectTag(34)) goto parse_loop_message_type;
+        if (input->ExpectTag(42)) goto parse_loop_enum_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
       case 5: {
         if (tag == 42) {
-         parse_enum_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enum_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_enum_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(42)) goto parse_enum_type;
-        if (input->ExpectTag(50)) goto parse_service;
+        if (input->ExpectTag(42)) goto parse_loop_enum_type;
+        if (input->ExpectTag(50)) goto parse_loop_service;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.ServiceDescriptorProto service = 6;
       case 6: {
         if (tag == 50) {
-         parse_service:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_service:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_service()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(50)) goto parse_service;
-        if (input->ExpectTag(58)) goto parse_extension;
+        if (input->ExpectTag(50)) goto parse_loop_service;
+        if (input->ExpectTag(58)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.FieldDescriptorProto extension = 7;
       case 7: {
         if (tag == 58) {
-         parse_extension:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(58)) goto parse_extension;
+        if (input->ExpectTag(58)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(66)) goto parse_options;
         break;
       }
@@ -1712,9 +1759,9 @@
 
 void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileDescriptorProto*>(
-      &from);
+  const FileDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1816,16 +1863,16 @@
 // FileDescriptorProto
 
 // optional string name = 1;
- bool FileDescriptorProto::has_name() const {
+bool FileDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FileDescriptorProto::set_has_name() {
+void FileDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FileDescriptorProto::clear_has_name() {
+void FileDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FileDescriptorProto::clear_name() {
+void FileDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -1869,16 +1916,16 @@
 }
 
 // optional string package = 2;
- bool FileDescriptorProto::has_package() const {
+bool FileDescriptorProto::has_package() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FileDescriptorProto::set_has_package() {
+void FileDescriptorProto::set_has_package() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FileDescriptorProto::clear_has_package() {
+void FileDescriptorProto::clear_has_package() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FileDescriptorProto::clear_package() {
+void FileDescriptorProto::clear_package() {
   package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_package();
 }
@@ -1922,10 +1969,10 @@
 }
 
 // repeated string dependency = 3;
- int FileDescriptorProto::dependency_size() const {
+int FileDescriptorProto::dependency_size() const {
   return dependency_.size();
 }
- void FileDescriptorProto::clear_dependency() {
+void FileDescriptorProto::clear_dependency() {
   dependency_.Clear();
 }
  const ::std::string& FileDescriptorProto::dependency(int index) const {
@@ -1976,10 +2023,10 @@
 }
 
 // repeated int32 public_dependency = 10;
- int FileDescriptorProto::public_dependency_size() const {
+int FileDescriptorProto::public_dependency_size() const {
   return public_dependency_.size();
 }
- void FileDescriptorProto::clear_public_dependency() {
+void FileDescriptorProto::clear_public_dependency() {
   public_dependency_.Clear();
 }
  ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const {
@@ -2006,10 +2053,10 @@
 }
 
 // repeated int32 weak_dependency = 11;
- int FileDescriptorProto::weak_dependency_size() const {
+int FileDescriptorProto::weak_dependency_size() const {
   return weak_dependency_.size();
 }
- void FileDescriptorProto::clear_weak_dependency() {
+void FileDescriptorProto::clear_weak_dependency() {
   weak_dependency_.Clear();
 }
  ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const {
@@ -2036,10 +2083,10 @@
 }
 
 // repeated .google.protobuf.DescriptorProto message_type = 4;
- int FileDescriptorProto::message_type_size() const {
+int FileDescriptorProto::message_type_size() const {
   return message_type_.size();
 }
- void FileDescriptorProto::clear_message_type() {
+void FileDescriptorProto::clear_message_type() {
   message_type_.Clear();
 }
  const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const {
@@ -2066,10 +2113,10 @@
 }
 
 // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- int FileDescriptorProto::enum_type_size() const {
+int FileDescriptorProto::enum_type_size() const {
   return enum_type_.size();
 }
- void FileDescriptorProto::clear_enum_type() {
+void FileDescriptorProto::clear_enum_type() {
   enum_type_.Clear();
 }
  const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const {
@@ -2096,10 +2143,10 @@
 }
 
 // repeated .google.protobuf.ServiceDescriptorProto service = 6;
- int FileDescriptorProto::service_size() const {
+int FileDescriptorProto::service_size() const {
   return service_.size();
 }
- void FileDescriptorProto::clear_service() {
+void FileDescriptorProto::clear_service() {
   service_.Clear();
 }
  const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const {
@@ -2126,10 +2173,10 @@
 }
 
 // repeated .google.protobuf.FieldDescriptorProto extension = 7;
- int FileDescriptorProto::extension_size() const {
+int FileDescriptorProto::extension_size() const {
   return extension_.size();
 }
- void FileDescriptorProto::clear_extension() {
+void FileDescriptorProto::clear_extension() {
   extension_.Clear();
 }
  const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const {
@@ -2156,16 +2203,16 @@
 }
 
 // optional .google.protobuf.FileOptions options = 8;
- bool FileDescriptorProto::has_options() const {
+bool FileDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000200u) != 0;
 }
- void FileDescriptorProto::set_has_options() {
+void FileDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000200u;
 }
- void FileDescriptorProto::clear_has_options() {
+void FileDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000200u;
 }
- void FileDescriptorProto::clear_options() {
+void FileDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear();
   clear_has_options();
 }
@@ -2199,16 +2246,16 @@
 }
 
 // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
- bool FileDescriptorProto::has_source_code_info() const {
+bool FileDescriptorProto::has_source_code_info() const {
   return (_has_bits_[0] & 0x00000400u) != 0;
 }
- void FileDescriptorProto::set_has_source_code_info() {
+void FileDescriptorProto::set_has_source_code_info() {
   _has_bits_[0] |= 0x00000400u;
 }
- void FileDescriptorProto::clear_has_source_code_info() {
+void FileDescriptorProto::clear_has_source_code_info() {
   _has_bits_[0] &= ~0x00000400u;
 }
- void FileDescriptorProto::clear_source_code_info() {
+void FileDescriptorProto::clear_source_code_info() {
   if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear();
   clear_has_source_code_info();
 }
@@ -2242,16 +2289,16 @@
 }
 
 // optional string syntax = 12;
- bool FileDescriptorProto::has_syntax() const {
+bool FileDescriptorProto::has_syntax() const {
   return (_has_bits_[0] & 0x00000800u) != 0;
 }
- void FileDescriptorProto::set_has_syntax() {
+void FileDescriptorProto::set_has_syntax() {
   _has_bits_[0] |= 0x00000800u;
 }
- void FileDescriptorProto::clear_has_syntax() {
+void FileDescriptorProto::clear_has_syntax() {
   _has_bits_[0] &= ~0x00000800u;
 }
- void FileDescriptorProto::clear_syntax() {
+void FileDescriptorProto::clear_syntax() {
   syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_syntax();
 }
@@ -2304,7 +2351,7 @@
 #endif  // !_MSC_VER
 
 DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ExtensionRange)
 }
@@ -2516,9 +2563,9 @@
 
 void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const DescriptorProto_ExtensionRange* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto_ExtensionRange*>(
-      &from);
+  const DescriptorProto_ExtensionRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ExtensionRange>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2582,6 +2629,289 @@
 // -------------------------------------------------------------------
 
 #ifndef _MSC_VER
+const int DescriptorProto_ReservedRange::kStartFieldNumber;
+const int DescriptorProto_ReservedRange::kEndFieldNumber;
+#endif  // !_MSC_VER
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+void DescriptorProto_ReservedRange::InitAsDefaultInstance() {
+}
+
+DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+void DescriptorProto_ReservedRange::SharedCtor() {
+  _cached_size_ = 0;
+  start_ = 0;
+  end_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() {
+  // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange)
+  SharedDtor();
+}
+
+void DescriptorProto_ReservedRange::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void DescriptorProto_ReservedRange::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DescriptorProto_ReservedRange_descriptor_;
+}
+
+const DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::default_instance_ = NULL;
+
+DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::New(::google::protobuf::Arena* arena) const {
+  DescriptorProto_ReservedRange* n = new DescriptorProto_ReservedRange;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DescriptorProto_ReservedRange::Clear() {
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DescriptorProto_ReservedRange*>(16)->f)
+
+#define ZR_(first, last) do {\
+  ::memset(&first, 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(start_, end_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DescriptorProto_ReservedRange::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ReservedRange)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 start = 1;
+      case 1: {
+        if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &start_)));
+          set_has_start();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_end;
+        break;
+      }
+
+      // optional int32 end = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_end:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &end_)));
+          set_has_end();
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.DescriptorProto.ReservedRange)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.DescriptorProto.ReservedRange)
+  return false;
+#undef DO_
+}
+
+void DescriptorProto_ReservedRange::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ReservedRange)
+  // optional int32 start = 1;
+  if (has_start()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output);
+  }
+
+  // optional int32 end = 2;
+  if (has_end()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange)
+}
+
+::google::protobuf::uint8* DescriptorProto_ReservedRange::SerializeWithCachedSizesToArray(
+    ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
+  // optional int32 start = 1;
+  if (has_start()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target);
+  }
+
+  // optional int32 end = 2;
+  if (has_end()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange)
+  return target;
+}
+
+int DescriptorProto_ReservedRange::ByteSize() const {
+  int total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3) {
+    // optional int32 start = 1;
+    if (has_start()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->start());
+    }
+
+    // optional int32 end = 2;
+    if (has_end()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->end());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DescriptorProto_ReservedRange* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto_ReservedRange>(
+          &from);
+  if (source == NULL) {
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+    MergeFrom(*source);
+  }
+}
+
+void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) {
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_start()) {
+      set_start(from.start());
+    }
+    if (from.has_end()) {
+      set_end(from.end());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const ::google::protobuf::Message& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) {
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool DescriptorProto_ReservedRange::IsInitialized() const {
+
+  return true;
+}
+
+void DescriptorProto_ReservedRange::Swap(DescriptorProto_ReservedRange* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* other) {
+  std::swap(start_, other->start_);
+  std::swap(end_, other->end_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DescriptorProto_ReservedRange_descriptor_;
+  metadata.reflection = DescriptorProto_ReservedRange_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#ifndef _MSC_VER
 const int DescriptorProto::kNameFieldNumber;
 const int DescriptorProto::kFieldFieldNumber;
 const int DescriptorProto::kExtensionFieldNumber;
@@ -2590,10 +2920,12 @@
 const int DescriptorProto::kExtensionRangeFieldNumber;
 const int DescriptorProto::kOneofDeclFieldNumber;
 const int DescriptorProto::kOptionsFieldNumber;
+const int DescriptorProto::kReservedRangeFieldNumber;
+const int DescriptorProto::kReservedNameFieldNumber;
 #endif  // !_MSC_VER
 
 DescriptorProto::DescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto)
 }
@@ -2670,6 +3002,8 @@
   enum_type_.Clear();
   extension_range_.Clear();
   oneof_decl_.Clear();
+  reserved_range_.Clear();
+  reserved_name_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   if (_internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->Clear();
@@ -2706,68 +3040,79 @@
       case 2: {
         if (tag == 18) {
          parse_field:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_field:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_field()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_field;
-        if (input->ExpectTag(26)) goto parse_nested_type;
+        if (input->ExpectTag(18)) goto parse_loop_field;
+        if (input->ExpectTag(26)) goto parse_loop_nested_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.DescriptorProto nested_type = 3;
       case 3: {
         if (tag == 26) {
-         parse_nested_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_nested_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_nested_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(26)) goto parse_nested_type;
-        if (input->ExpectTag(34)) goto parse_enum_type;
+        if (input->ExpectTag(26)) goto parse_loop_nested_type;
+        if (input->ExpectTag(34)) goto parse_loop_enum_type;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
       case 4: {
         if (tag == 34) {
-         parse_enum_type:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enum_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_enum_type()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(34)) goto parse_enum_type;
-        if (input->ExpectTag(42)) goto parse_extension_range;
+        if (input->ExpectTag(34)) goto parse_loop_enum_type;
+        if (input->ExpectTag(42)) goto parse_loop_extension_range;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
       case 5: {
         if (tag == 42) {
-         parse_extension_range:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension_range:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension_range()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(42)) goto parse_extension_range;
-        if (input->ExpectTag(50)) goto parse_extension;
+        if (input->ExpectTag(42)) goto parse_loop_extension_range;
+        if (input->ExpectTag(50)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.FieldDescriptorProto extension = 6;
       case 6: {
         if (tag == 50) {
-         parse_extension:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_extension:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_extension()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(50)) goto parse_extension;
+        if (input->ExpectTag(50)) goto parse_loop_extension;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(58)) goto parse_options;
         break;
       }
@@ -2789,12 +3134,50 @@
       case 8: {
         if (tag == 66) {
          parse_oneof_decl:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_oneof_decl:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_oneof_decl()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(66)) goto parse_oneof_decl;
+        if (input->ExpectTag(66)) goto parse_loop_oneof_decl;
+        if (input->ExpectTag(74)) goto parse_loop_reserved_range;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+      case 9: {
+        if (tag == 74) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_reserved_range:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_reserved_range()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(74)) goto parse_loop_reserved_range;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(82)) goto parse_reserved_name;
+        break;
+      }
+
+      // repeated string reserved_name = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_reserved_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_reserved_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->reserved_name(this->reserved_name_size() - 1).data(),
+            this->reserved_name(this->reserved_name_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "google.protobuf.DescriptorProto.reserved_name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(82)) goto parse_reserved_name;
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -2876,6 +3259,22 @@
       8, this->oneof_decl(i), output);
   }
 
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      9, this->reserved_range(i), output);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+  ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+    this->reserved_name(i).data(), this->reserved_name(i).length(),
+    ::google::protobuf::internal::WireFormat::SERIALIZE,
+    "google.protobuf.DescriptorProto.reserved_name");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      10, this->reserved_name(i), output);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
@@ -2946,6 +3345,23 @@
         8, this->oneof_decl(i), target);
   }
 
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteMessageNoVirtualToArray(
+        9, this->reserved_range(i), target);
+  }
+
+  // repeated string reserved_name = 10;
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->reserved_name(i).data(), this->reserved_name(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "google.protobuf.DescriptorProto.reserved_name");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(10, this->reserved_name(i), target);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
@@ -3021,6 +3437,21 @@
         this->oneof_decl(i));
   }
 
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  total_size += 1 * this->reserved_range_size();
+  for (int i = 0; i < this->reserved_range_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->reserved_range(i));
+  }
+
+  // repeated string reserved_name = 10;
+  total_size += 1 * this->reserved_name_size();
+  for (int i = 0; i < this->reserved_name_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->reserved_name(i));
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -3034,9 +3465,9 @@
 
 void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const DescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DescriptorProto*>(
-      &from);
+  const DescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -3052,6 +3483,8 @@
   enum_type_.MergeFrom(from.enum_type_);
   extension_range_.MergeFrom(from.extension_range_);
   oneof_decl_.MergeFrom(from.oneof_decl_);
+  reserved_range_.MergeFrom(from.reserved_range_);
+  reserved_name_.MergeFrom(from.reserved_name_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
     if (from.has_name()) {
       set_has_name();
@@ -3103,6 +3536,8 @@
   extension_range_.UnsafeArenaSwap(&other->extension_range_);
   oneof_decl_.UnsafeArenaSwap(&other->oneof_decl_);
   std::swap(options_, other->options_);
+  reserved_range_.UnsafeArenaSwap(&other->reserved_range_);
+  reserved_name_.UnsafeArenaSwap(&other->reserved_name_);
   std::swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   std::swap(_cached_size_, other->_cached_size_);
@@ -3120,16 +3555,16 @@
 // DescriptorProto_ExtensionRange
 
 // optional int32 start = 1;
- bool DescriptorProto_ExtensionRange::has_start() const {
+bool DescriptorProto_ExtensionRange::has_start() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void DescriptorProto_ExtensionRange::set_has_start() {
+void DescriptorProto_ExtensionRange::set_has_start() {
   _has_bits_[0] |= 0x00000001u;
 }
- void DescriptorProto_ExtensionRange::clear_has_start() {
+void DescriptorProto_ExtensionRange::clear_has_start() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void DescriptorProto_ExtensionRange::clear_start() {
+void DescriptorProto_ExtensionRange::clear_start() {
   start_ = 0;
   clear_has_start();
 }
@@ -3144,16 +3579,16 @@
 }
 
 // optional int32 end = 2;
- bool DescriptorProto_ExtensionRange::has_end() const {
+bool DescriptorProto_ExtensionRange::has_end() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void DescriptorProto_ExtensionRange::set_has_end() {
+void DescriptorProto_ExtensionRange::set_has_end() {
   _has_bits_[0] |= 0x00000002u;
 }
- void DescriptorProto_ExtensionRange::clear_has_end() {
+void DescriptorProto_ExtensionRange::clear_has_end() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void DescriptorProto_ExtensionRange::clear_end() {
+void DescriptorProto_ExtensionRange::clear_end() {
   end_ = 0;
   clear_has_end();
 }
@@ -3169,19 +3604,71 @@
 
 // -------------------------------------------------------------------
 
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+bool DescriptorProto_ReservedRange::has_start() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DescriptorProto_ReservedRange::set_has_start() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DescriptorProto_ReservedRange::clear_has_start() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DescriptorProto_ReservedRange::clear_start() {
+  start_ = 0;
+  clear_has_start();
+}
+ ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return start_;
+}
+ void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) {
+  set_has_start();
+  start_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+bool DescriptorProto_ReservedRange::has_end() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void DescriptorProto_ReservedRange::set_has_end() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void DescriptorProto_ReservedRange::clear_has_end() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void DescriptorProto_ReservedRange::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+ ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return end_;
+}
+ void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
 // DescriptorProto
 
 // optional string name = 1;
- bool DescriptorProto::has_name() const {
+bool DescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void DescriptorProto::set_has_name() {
+void DescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void DescriptorProto::clear_has_name() {
+void DescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void DescriptorProto::clear_name() {
+void DescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -3225,10 +3712,10 @@
 }
 
 // repeated .google.protobuf.FieldDescriptorProto field = 2;
- int DescriptorProto::field_size() const {
+int DescriptorProto::field_size() const {
   return field_.size();
 }
- void DescriptorProto::clear_field() {
+void DescriptorProto::clear_field() {
   field_.Clear();
 }
  const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const {
@@ -3255,10 +3742,10 @@
 }
 
 // repeated .google.protobuf.FieldDescriptorProto extension = 6;
- int DescriptorProto::extension_size() const {
+int DescriptorProto::extension_size() const {
   return extension_.size();
 }
- void DescriptorProto::clear_extension() {
+void DescriptorProto::clear_extension() {
   extension_.Clear();
 }
  const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const {
@@ -3285,10 +3772,10 @@
 }
 
 // repeated .google.protobuf.DescriptorProto nested_type = 3;
- int DescriptorProto::nested_type_size() const {
+int DescriptorProto::nested_type_size() const {
   return nested_type_.size();
 }
- void DescriptorProto::clear_nested_type() {
+void DescriptorProto::clear_nested_type() {
   nested_type_.Clear();
 }
  const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const {
@@ -3315,10 +3802,10 @@
 }
 
 // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- int DescriptorProto::enum_type_size() const {
+int DescriptorProto::enum_type_size() const {
   return enum_type_.size();
 }
- void DescriptorProto::clear_enum_type() {
+void DescriptorProto::clear_enum_type() {
   enum_type_.Clear();
 }
  const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const {
@@ -3345,10 +3832,10 @@
 }
 
 // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- int DescriptorProto::extension_range_size() const {
+int DescriptorProto::extension_range_size() const {
   return extension_range_.size();
 }
- void DescriptorProto::clear_extension_range() {
+void DescriptorProto::clear_extension_range() {
   extension_range_.Clear();
 }
  const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const {
@@ -3375,10 +3862,10 @@
 }
 
 // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
- int DescriptorProto::oneof_decl_size() const {
+int DescriptorProto::oneof_decl_size() const {
   return oneof_decl_.size();
 }
- void DescriptorProto::clear_oneof_decl() {
+void DescriptorProto::clear_oneof_decl() {
   oneof_decl_.Clear();
 }
  const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const {
@@ -3405,16 +3892,16 @@
 }
 
 // optional .google.protobuf.MessageOptions options = 7;
- bool DescriptorProto::has_options() const {
+bool DescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void DescriptorProto::set_has_options() {
+void DescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000080u;
 }
- void DescriptorProto::clear_has_options() {
+void DescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void DescriptorProto::clear_options() {
+void DescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear();
   clear_has_options();
 }
@@ -3447,6 +3934,90 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
 }
 
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+int DescriptorProto::reserved_range_size() const {
+  return reserved_range_.size();
+}
+void DescriptorProto::clear_reserved_range() {
+  reserved_range_.Clear();
+}
+ const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Get(index);
+}
+ ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Mutable(index);
+}
+ ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Add();
+}
+ const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_;
+}
+ ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+int DescriptorProto::reserved_name_size() const {
+  return reserved_name_.size();
+}
+void DescriptorProto::clear_reserved_name() {
+  reserved_name_.Clear();
+}
+ const ::std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Get(index);
+}
+ ::std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Mutable(index);
+}
+ void DescriptorProto::set_reserved_name(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+  reserved_name_.Mutable(index)->assign(value);
+}
+ void DescriptorProto::set_reserved_name(int index, const char* value) {
+  reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+ ::std::string* DescriptorProto::add_reserved_name() {
+  return reserved_name_.Add();
+}
+ void DescriptorProto::add_reserved_name(const ::std::string& value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::add_reserved_name(const char* value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name)
+}
+ void DescriptorProto::add_reserved_name(const char* value, size_t size) {
+  reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &reserved_name_;
+}
+
 #endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
@@ -3540,7 +4111,7 @@
 #endif  // !_MSC_VER
 
 FieldDescriptorProto::FieldDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldDescriptorProto)
 }
@@ -4063,9 +4634,9 @@
 
 void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FieldDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldDescriptorProto*>(
-      &from);
+  const FieldDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -4166,16 +4737,16 @@
 // FieldDescriptorProto
 
 // optional string name = 1;
- bool FieldDescriptorProto::has_name() const {
+bool FieldDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FieldDescriptorProto::set_has_name() {
+void FieldDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FieldDescriptorProto::clear_has_name() {
+void FieldDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FieldDescriptorProto::clear_name() {
+void FieldDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -4219,16 +4790,16 @@
 }
 
 // optional int32 number = 3;
- bool FieldDescriptorProto::has_number() const {
+bool FieldDescriptorProto::has_number() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FieldDescriptorProto::set_has_number() {
+void FieldDescriptorProto::set_has_number() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FieldDescriptorProto::clear_has_number() {
+void FieldDescriptorProto::clear_has_number() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FieldDescriptorProto::clear_number() {
+void FieldDescriptorProto::clear_number() {
   number_ = 0;
   clear_has_number();
 }
@@ -4243,16 +4814,16 @@
 }
 
 // optional .google.protobuf.FieldDescriptorProto.Label label = 4;
- bool FieldDescriptorProto::has_label() const {
+bool FieldDescriptorProto::has_label() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void FieldDescriptorProto::set_has_label() {
+void FieldDescriptorProto::set_has_label() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FieldDescriptorProto::clear_has_label() {
+void FieldDescriptorProto::clear_has_label() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FieldDescriptorProto::clear_label() {
+void FieldDescriptorProto::clear_label() {
   label_ = 1;
   clear_has_label();
 }
@@ -4268,16 +4839,16 @@
 }
 
 // optional .google.protobuf.FieldDescriptorProto.Type type = 5;
- bool FieldDescriptorProto::has_type() const {
+bool FieldDescriptorProto::has_type() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void FieldDescriptorProto::set_has_type() {
+void FieldDescriptorProto::set_has_type() {
   _has_bits_[0] |= 0x00000008u;
 }
- void FieldDescriptorProto::clear_has_type() {
+void FieldDescriptorProto::clear_has_type() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void FieldDescriptorProto::clear_type() {
+void FieldDescriptorProto::clear_type() {
   type_ = 1;
   clear_has_type();
 }
@@ -4293,16 +4864,16 @@
 }
 
 // optional string type_name = 6;
- bool FieldDescriptorProto::has_type_name() const {
+bool FieldDescriptorProto::has_type_name() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FieldDescriptorProto::set_has_type_name() {
+void FieldDescriptorProto::set_has_type_name() {
   _has_bits_[0] |= 0x00000010u;
 }
- void FieldDescriptorProto::clear_has_type_name() {
+void FieldDescriptorProto::clear_has_type_name() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void FieldDescriptorProto::clear_type_name() {
+void FieldDescriptorProto::clear_type_name() {
   type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_type_name();
 }
@@ -4346,16 +4917,16 @@
 }
 
 // optional string extendee = 2;
- bool FieldDescriptorProto::has_extendee() const {
+bool FieldDescriptorProto::has_extendee() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FieldDescriptorProto::set_has_extendee() {
+void FieldDescriptorProto::set_has_extendee() {
   _has_bits_[0] |= 0x00000020u;
 }
- void FieldDescriptorProto::clear_has_extendee() {
+void FieldDescriptorProto::clear_has_extendee() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void FieldDescriptorProto::clear_extendee() {
+void FieldDescriptorProto::clear_extendee() {
   extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_extendee();
 }
@@ -4399,16 +4970,16 @@
 }
 
 // optional string default_value = 7;
- bool FieldDescriptorProto::has_default_value() const {
+bool FieldDescriptorProto::has_default_value() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void FieldDescriptorProto::set_has_default_value() {
+void FieldDescriptorProto::set_has_default_value() {
   _has_bits_[0] |= 0x00000040u;
 }
- void FieldDescriptorProto::clear_has_default_value() {
+void FieldDescriptorProto::clear_has_default_value() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void FieldDescriptorProto::clear_default_value() {
+void FieldDescriptorProto::clear_default_value() {
   default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_default_value();
 }
@@ -4452,16 +5023,16 @@
 }
 
 // optional int32 oneof_index = 9;
- bool FieldDescriptorProto::has_oneof_index() const {
+bool FieldDescriptorProto::has_oneof_index() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void FieldDescriptorProto::set_has_oneof_index() {
+void FieldDescriptorProto::set_has_oneof_index() {
   _has_bits_[0] |= 0x00000080u;
 }
- void FieldDescriptorProto::clear_has_oneof_index() {
+void FieldDescriptorProto::clear_has_oneof_index() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void FieldDescriptorProto::clear_oneof_index() {
+void FieldDescriptorProto::clear_oneof_index() {
   oneof_index_ = 0;
   clear_has_oneof_index();
 }
@@ -4476,16 +5047,16 @@
 }
 
 // optional .google.protobuf.FieldOptions options = 8;
- bool FieldDescriptorProto::has_options() const {
+bool FieldDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
- void FieldDescriptorProto::set_has_options() {
+void FieldDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000100u;
 }
- void FieldDescriptorProto::clear_has_options() {
+void FieldDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000100u;
 }
- void FieldDescriptorProto::clear_options() {
+void FieldDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear();
   clear_has_options();
 }
@@ -4527,7 +5098,7 @@
 #endif  // !_MSC_VER
 
 OneofDescriptorProto::OneofDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto)
 }
@@ -4709,9 +5280,9 @@
 
 void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const OneofDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const OneofDescriptorProto*>(
-      &from);
+  const OneofDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const OneofDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -4772,16 +5343,16 @@
 // OneofDescriptorProto
 
 // optional string name = 1;
- bool OneofDescriptorProto::has_name() const {
+bool OneofDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void OneofDescriptorProto::set_has_name() {
+void OneofDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void OneofDescriptorProto::clear_has_name() {
+void OneofDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void OneofDescriptorProto::clear_name() {
+void OneofDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -4835,7 +5406,7 @@
 #endif  // !_MSC_VER
 
 EnumDescriptorProto::EnumDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumDescriptorProto)
 }
@@ -4943,12 +5514,15 @@
       case 2: {
         if (tag == 18) {
          parse_value:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_value()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_value;
+        if (input->ExpectTag(18)) goto parse_loop_value;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_options;
         break;
       }
@@ -5096,9 +5670,9 @@
 
 void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumDescriptorProto*>(
-      &from);
+  const EnumDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -5169,16 +5743,16 @@
 // EnumDescriptorProto
 
 // optional string name = 1;
- bool EnumDescriptorProto::has_name() const {
+bool EnumDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumDescriptorProto::set_has_name() {
+void EnumDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumDescriptorProto::clear_has_name() {
+void EnumDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumDescriptorProto::clear_name() {
+void EnumDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -5222,10 +5796,10 @@
 }
 
 // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- int EnumDescriptorProto::value_size() const {
+int EnumDescriptorProto::value_size() const {
   return value_.size();
 }
- void EnumDescriptorProto::clear_value() {
+void EnumDescriptorProto::clear_value() {
   value_.Clear();
 }
  const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const {
@@ -5252,16 +5826,16 @@
 }
 
 // optional .google.protobuf.EnumOptions options = 3;
- bool EnumDescriptorProto::has_options() const {
+bool EnumDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void EnumDescriptorProto::set_has_options() {
+void EnumDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void EnumDescriptorProto::clear_has_options() {
+void EnumDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void EnumDescriptorProto::clear_options() {
+void EnumDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear();
   clear_has_options();
 }
@@ -5305,7 +5879,7 @@
 #endif  // !_MSC_VER
 
 EnumValueDescriptorProto::EnumValueDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueDescriptorProto)
 }
@@ -5564,9 +6138,9 @@
 
 void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumValueDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueDescriptorProto*>(
-      &from);
+  const EnumValueDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -5638,16 +6212,16 @@
 // EnumValueDescriptorProto
 
 // optional string name = 1;
- bool EnumValueDescriptorProto::has_name() const {
+bool EnumValueDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumValueDescriptorProto::set_has_name() {
+void EnumValueDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumValueDescriptorProto::clear_has_name() {
+void EnumValueDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumValueDescriptorProto::clear_name() {
+void EnumValueDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -5691,16 +6265,16 @@
 }
 
 // optional int32 number = 2;
- bool EnumValueDescriptorProto::has_number() const {
+bool EnumValueDescriptorProto::has_number() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void EnumValueDescriptorProto::set_has_number() {
+void EnumValueDescriptorProto::set_has_number() {
   _has_bits_[0] |= 0x00000002u;
 }
- void EnumValueDescriptorProto::clear_has_number() {
+void EnumValueDescriptorProto::clear_has_number() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void EnumValueDescriptorProto::clear_number() {
+void EnumValueDescriptorProto::clear_number() {
   number_ = 0;
   clear_has_number();
 }
@@ -5715,16 +6289,16 @@
 }
 
 // optional .google.protobuf.EnumValueOptions options = 3;
- bool EnumValueDescriptorProto::has_options() const {
+bool EnumValueDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void EnumValueDescriptorProto::set_has_options() {
+void EnumValueDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void EnumValueDescriptorProto::clear_has_options() {
+void EnumValueDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void EnumValueDescriptorProto::clear_options() {
+void EnumValueDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear();
   clear_has_options();
 }
@@ -5768,7 +6342,7 @@
 #endif  // !_MSC_VER
 
 ServiceDescriptorProto::ServiceDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceDescriptorProto)
 }
@@ -5876,12 +6450,15 @@
       case 2: {
         if (tag == 18) {
          parse_method:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_method:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_method()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_method;
+        if (input->ExpectTag(18)) goto parse_loop_method;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_options;
         break;
       }
@@ -6029,9 +6606,9 @@
 
 void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const ServiceDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceDescriptorProto*>(
-      &from);
+  const ServiceDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -6102,16 +6679,16 @@
 // ServiceDescriptorProto
 
 // optional string name = 1;
- bool ServiceDescriptorProto::has_name() const {
+bool ServiceDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void ServiceDescriptorProto::set_has_name() {
+void ServiceDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void ServiceDescriptorProto::clear_has_name() {
+void ServiceDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void ServiceDescriptorProto::clear_name() {
+void ServiceDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -6155,10 +6732,10 @@
 }
 
 // repeated .google.protobuf.MethodDescriptorProto method = 2;
- int ServiceDescriptorProto::method_size() const {
+int ServiceDescriptorProto::method_size() const {
   return method_.size();
 }
- void ServiceDescriptorProto::clear_method() {
+void ServiceDescriptorProto::clear_method() {
   method_.Clear();
 }
  const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const {
@@ -6185,16 +6762,16 @@
 }
 
 // optional .google.protobuf.ServiceOptions options = 3;
- bool ServiceDescriptorProto::has_options() const {
+bool ServiceDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void ServiceDescriptorProto::set_has_options() {
+void ServiceDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000004u;
 }
- void ServiceDescriptorProto::clear_has_options() {
+void ServiceDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void ServiceDescriptorProto::clear_options() {
+void ServiceDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear();
   clear_has_options();
 }
@@ -6241,7 +6818,7 @@
 #endif  // !_MSC_VER
 
 MethodDescriptorProto::MethodDescriptorProto()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto)
 }
@@ -6641,9 +7218,9 @@
 
 void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MethodDescriptorProto* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodDescriptorProto*>(
-      &from);
+  const MethodDescriptorProto* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodDescriptorProto>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -6729,16 +7306,16 @@
 // MethodDescriptorProto
 
 // optional string name = 1;
- bool MethodDescriptorProto::has_name() const {
+bool MethodDescriptorProto::has_name() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MethodDescriptorProto::set_has_name() {
+void MethodDescriptorProto::set_has_name() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MethodDescriptorProto::clear_has_name() {
+void MethodDescriptorProto::clear_has_name() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MethodDescriptorProto::clear_name() {
+void MethodDescriptorProto::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name();
 }
@@ -6782,16 +7359,16 @@
 }
 
 // optional string input_type = 2;
- bool MethodDescriptorProto::has_input_type() const {
+bool MethodDescriptorProto::has_input_type() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void MethodDescriptorProto::set_has_input_type() {
+void MethodDescriptorProto::set_has_input_type() {
   _has_bits_[0] |= 0x00000002u;
 }
- void MethodDescriptorProto::clear_has_input_type() {
+void MethodDescriptorProto::clear_has_input_type() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void MethodDescriptorProto::clear_input_type() {
+void MethodDescriptorProto::clear_input_type() {
   input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_input_type();
 }
@@ -6835,16 +7412,16 @@
 }
 
 // optional string output_type = 3;
- bool MethodDescriptorProto::has_output_type() const {
+bool MethodDescriptorProto::has_output_type() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void MethodDescriptorProto::set_has_output_type() {
+void MethodDescriptorProto::set_has_output_type() {
   _has_bits_[0] |= 0x00000004u;
 }
- void MethodDescriptorProto::clear_has_output_type() {
+void MethodDescriptorProto::clear_has_output_type() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void MethodDescriptorProto::clear_output_type() {
+void MethodDescriptorProto::clear_output_type() {
   output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_output_type();
 }
@@ -6888,16 +7465,16 @@
 }
 
 // optional .google.protobuf.MethodOptions options = 4;
- bool MethodDescriptorProto::has_options() const {
+bool MethodDescriptorProto::has_options() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void MethodDescriptorProto::set_has_options() {
+void MethodDescriptorProto::set_has_options() {
   _has_bits_[0] |= 0x00000008u;
 }
- void MethodDescriptorProto::clear_has_options() {
+void MethodDescriptorProto::clear_has_options() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void MethodDescriptorProto::clear_options() {
+void MethodDescriptorProto::clear_options() {
   if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear();
   clear_has_options();
 }
@@ -6931,16 +7508,16 @@
 }
 
 // optional bool client_streaming = 5 [default = false];
- bool MethodDescriptorProto::has_client_streaming() const {
+bool MethodDescriptorProto::has_client_streaming() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void MethodDescriptorProto::set_has_client_streaming() {
+void MethodDescriptorProto::set_has_client_streaming() {
   _has_bits_[0] |= 0x00000010u;
 }
- void MethodDescriptorProto::clear_has_client_streaming() {
+void MethodDescriptorProto::clear_has_client_streaming() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void MethodDescriptorProto::clear_client_streaming() {
+void MethodDescriptorProto::clear_client_streaming() {
   client_streaming_ = false;
   clear_has_client_streaming();
 }
@@ -6955,16 +7532,16 @@
 }
 
 // optional bool server_streaming = 6 [default = false];
- bool MethodDescriptorProto::has_server_streaming() const {
+bool MethodDescriptorProto::has_server_streaming() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void MethodDescriptorProto::set_has_server_streaming() {
+void MethodDescriptorProto::set_has_server_streaming() {
   _has_bits_[0] |= 0x00000020u;
 }
- void MethodDescriptorProto::clear_has_server_streaming() {
+void MethodDescriptorProto::clear_has_server_streaming() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void MethodDescriptorProto::clear_server_streaming() {
+void MethodDescriptorProto::clear_server_streaming() {
   server_streaming_ = false;
   clear_has_server_streaming();
 }
@@ -7024,7 +7601,7 @@
 #endif  // !_MSC_VER
 
 FileOptions::FileOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FileOptions)
 }
@@ -7381,12 +7958,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -7768,9 +8348,9 @@
 
 void FileOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FileOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FileOptions*>(
-      &from);
+  const FileOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FileOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -7895,16 +8475,16 @@
 // FileOptions
 
 // optional string java_package = 1;
- bool FileOptions::has_java_package() const {
+bool FileOptions::has_java_package() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FileOptions::set_has_java_package() {
+void FileOptions::set_has_java_package() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FileOptions::clear_has_java_package() {
+void FileOptions::clear_has_java_package() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FileOptions::clear_java_package() {
+void FileOptions::clear_java_package() {
   java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_package();
 }
@@ -7948,16 +8528,16 @@
 }
 
 // optional string java_outer_classname = 8;
- bool FileOptions::has_java_outer_classname() const {
+bool FileOptions::has_java_outer_classname() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FileOptions::set_has_java_outer_classname() {
+void FileOptions::set_has_java_outer_classname() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FileOptions::clear_has_java_outer_classname() {
+void FileOptions::clear_has_java_outer_classname() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FileOptions::clear_java_outer_classname() {
+void FileOptions::clear_java_outer_classname() {
   java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_java_outer_classname();
 }
@@ -8001,16 +8581,16 @@
 }
 
 // optional bool java_multiple_files = 10 [default = false];
- bool FileOptions::has_java_multiple_files() const {
+bool FileOptions::has_java_multiple_files() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void FileOptions::set_has_java_multiple_files() {
+void FileOptions::set_has_java_multiple_files() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FileOptions::clear_has_java_multiple_files() {
+void FileOptions::clear_has_java_multiple_files() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FileOptions::clear_java_multiple_files() {
+void FileOptions::clear_java_multiple_files() {
   java_multiple_files_ = false;
   clear_has_java_multiple_files();
 }
@@ -8025,16 +8605,16 @@
 }
 
 // optional bool java_generate_equals_and_hash = 20 [default = false];
- bool FileOptions::has_java_generate_equals_and_hash() const {
+bool FileOptions::has_java_generate_equals_and_hash() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void FileOptions::set_has_java_generate_equals_and_hash() {
+void FileOptions::set_has_java_generate_equals_and_hash() {
   _has_bits_[0] |= 0x00000008u;
 }
- void FileOptions::clear_has_java_generate_equals_and_hash() {
+void FileOptions::clear_has_java_generate_equals_and_hash() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void FileOptions::clear_java_generate_equals_and_hash() {
+void FileOptions::clear_java_generate_equals_and_hash() {
   java_generate_equals_and_hash_ = false;
   clear_has_java_generate_equals_and_hash();
 }
@@ -8049,16 +8629,16 @@
 }
 
 // optional bool java_string_check_utf8 = 27 [default = false];
- bool FileOptions::has_java_string_check_utf8() const {
+bool FileOptions::has_java_string_check_utf8() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FileOptions::set_has_java_string_check_utf8() {
+void FileOptions::set_has_java_string_check_utf8() {
   _has_bits_[0] |= 0x00000010u;
 }
- void FileOptions::clear_has_java_string_check_utf8() {
+void FileOptions::clear_has_java_string_check_utf8() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void FileOptions::clear_java_string_check_utf8() {
+void FileOptions::clear_java_string_check_utf8() {
   java_string_check_utf8_ = false;
   clear_has_java_string_check_utf8();
 }
@@ -8073,16 +8653,16 @@
 }
 
 // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
- bool FileOptions::has_optimize_for() const {
+bool FileOptions::has_optimize_for() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FileOptions::set_has_optimize_for() {
+void FileOptions::set_has_optimize_for() {
   _has_bits_[0] |= 0x00000020u;
 }
- void FileOptions::clear_has_optimize_for() {
+void FileOptions::clear_has_optimize_for() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void FileOptions::clear_optimize_for() {
+void FileOptions::clear_optimize_for() {
   optimize_for_ = 1;
   clear_has_optimize_for();
 }
@@ -8098,16 +8678,16 @@
 }
 
 // optional string go_package = 11;
- bool FileOptions::has_go_package() const {
+bool FileOptions::has_go_package() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void FileOptions::set_has_go_package() {
+void FileOptions::set_has_go_package() {
   _has_bits_[0] |= 0x00000040u;
 }
- void FileOptions::clear_has_go_package() {
+void FileOptions::clear_has_go_package() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void FileOptions::clear_go_package() {
+void FileOptions::clear_go_package() {
   go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_go_package();
 }
@@ -8151,16 +8731,16 @@
 }
 
 // optional bool cc_generic_services = 16 [default = false];
- bool FileOptions::has_cc_generic_services() const {
+bool FileOptions::has_cc_generic_services() const {
   return (_has_bits_[0] & 0x00000080u) != 0;
 }
- void FileOptions::set_has_cc_generic_services() {
+void FileOptions::set_has_cc_generic_services() {
   _has_bits_[0] |= 0x00000080u;
 }
- void FileOptions::clear_has_cc_generic_services() {
+void FileOptions::clear_has_cc_generic_services() {
   _has_bits_[0] &= ~0x00000080u;
 }
- void FileOptions::clear_cc_generic_services() {
+void FileOptions::clear_cc_generic_services() {
   cc_generic_services_ = false;
   clear_has_cc_generic_services();
 }
@@ -8175,16 +8755,16 @@
 }
 
 // optional bool java_generic_services = 17 [default = false];
- bool FileOptions::has_java_generic_services() const {
+bool FileOptions::has_java_generic_services() const {
   return (_has_bits_[0] & 0x00000100u) != 0;
 }
- void FileOptions::set_has_java_generic_services() {
+void FileOptions::set_has_java_generic_services() {
   _has_bits_[0] |= 0x00000100u;
 }
- void FileOptions::clear_has_java_generic_services() {
+void FileOptions::clear_has_java_generic_services() {
   _has_bits_[0] &= ~0x00000100u;
 }
- void FileOptions::clear_java_generic_services() {
+void FileOptions::clear_java_generic_services() {
   java_generic_services_ = false;
   clear_has_java_generic_services();
 }
@@ -8199,16 +8779,16 @@
 }
 
 // optional bool py_generic_services = 18 [default = false];
- bool FileOptions::has_py_generic_services() const {
+bool FileOptions::has_py_generic_services() const {
   return (_has_bits_[0] & 0x00000200u) != 0;
 }
- void FileOptions::set_has_py_generic_services() {
+void FileOptions::set_has_py_generic_services() {
   _has_bits_[0] |= 0x00000200u;
 }
- void FileOptions::clear_has_py_generic_services() {
+void FileOptions::clear_has_py_generic_services() {
   _has_bits_[0] &= ~0x00000200u;
 }
- void FileOptions::clear_py_generic_services() {
+void FileOptions::clear_py_generic_services() {
   py_generic_services_ = false;
   clear_has_py_generic_services();
 }
@@ -8223,16 +8803,16 @@
 }
 
 // optional bool deprecated = 23 [default = false];
- bool FileOptions::has_deprecated() const {
+bool FileOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000400u) != 0;
 }
- void FileOptions::set_has_deprecated() {
+void FileOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000400u;
 }
- void FileOptions::clear_has_deprecated() {
+void FileOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000400u;
 }
- void FileOptions::clear_deprecated() {
+void FileOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -8247,16 +8827,16 @@
 }
 
 // optional bool cc_enable_arenas = 31 [default = false];
- bool FileOptions::has_cc_enable_arenas() const {
+bool FileOptions::has_cc_enable_arenas() const {
   return (_has_bits_[0] & 0x00000800u) != 0;
 }
- void FileOptions::set_has_cc_enable_arenas() {
+void FileOptions::set_has_cc_enable_arenas() {
   _has_bits_[0] |= 0x00000800u;
 }
- void FileOptions::clear_has_cc_enable_arenas() {
+void FileOptions::clear_has_cc_enable_arenas() {
   _has_bits_[0] &= ~0x00000800u;
 }
- void FileOptions::clear_cc_enable_arenas() {
+void FileOptions::clear_cc_enable_arenas() {
   cc_enable_arenas_ = false;
   clear_has_cc_enable_arenas();
 }
@@ -8271,16 +8851,16 @@
 }
 
 // optional string objc_class_prefix = 36;
- bool FileOptions::has_objc_class_prefix() const {
+bool FileOptions::has_objc_class_prefix() const {
   return (_has_bits_[0] & 0x00001000u) != 0;
 }
- void FileOptions::set_has_objc_class_prefix() {
+void FileOptions::set_has_objc_class_prefix() {
   _has_bits_[0] |= 0x00001000u;
 }
- void FileOptions::clear_has_objc_class_prefix() {
+void FileOptions::clear_has_objc_class_prefix() {
   _has_bits_[0] &= ~0x00001000u;
 }
- void FileOptions::clear_objc_class_prefix() {
+void FileOptions::clear_objc_class_prefix() {
   objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_objc_class_prefix();
 }
@@ -8324,16 +8904,16 @@
 }
 
 // optional string csharp_namespace = 37;
- bool FileOptions::has_csharp_namespace() const {
+bool FileOptions::has_csharp_namespace() const {
   return (_has_bits_[0] & 0x00002000u) != 0;
 }
- void FileOptions::set_has_csharp_namespace() {
+void FileOptions::set_has_csharp_namespace() {
   _has_bits_[0] |= 0x00002000u;
 }
- void FileOptions::clear_has_csharp_namespace() {
+void FileOptions::clear_has_csharp_namespace() {
   _has_bits_[0] &= ~0x00002000u;
 }
- void FileOptions::clear_csharp_namespace() {
+void FileOptions::clear_csharp_namespace() {
   csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_csharp_namespace();
 }
@@ -8377,10 +8957,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int FileOptions::uninterpreted_option_size() const {
+int FileOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void FileOptions::clear_uninterpreted_option() {
+void FileOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const {
@@ -8419,7 +8999,7 @@
 #endif  // !_MSC_VER
 
 MessageOptions::MessageOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MessageOptions)
 }
@@ -8574,12 +9154,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -8741,9 +9324,9 @@
 
 void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MessageOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MessageOptions*>(
-      &from);
+  const MessageOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MessageOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -8821,16 +9404,16 @@
 // MessageOptions
 
 // optional bool message_set_wire_format = 1 [default = false];
- bool MessageOptions::has_message_set_wire_format() const {
+bool MessageOptions::has_message_set_wire_format() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MessageOptions::set_has_message_set_wire_format() {
+void MessageOptions::set_has_message_set_wire_format() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MessageOptions::clear_has_message_set_wire_format() {
+void MessageOptions::clear_has_message_set_wire_format() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MessageOptions::clear_message_set_wire_format() {
+void MessageOptions::clear_message_set_wire_format() {
   message_set_wire_format_ = false;
   clear_has_message_set_wire_format();
 }
@@ -8845,16 +9428,16 @@
 }
 
 // optional bool no_standard_descriptor_accessor = 2 [default = false];
- bool MessageOptions::has_no_standard_descriptor_accessor() const {
+bool MessageOptions::has_no_standard_descriptor_accessor() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void MessageOptions::set_has_no_standard_descriptor_accessor() {
+void MessageOptions::set_has_no_standard_descriptor_accessor() {
   _has_bits_[0] |= 0x00000002u;
 }
- void MessageOptions::clear_has_no_standard_descriptor_accessor() {
+void MessageOptions::clear_has_no_standard_descriptor_accessor() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void MessageOptions::clear_no_standard_descriptor_accessor() {
+void MessageOptions::clear_no_standard_descriptor_accessor() {
   no_standard_descriptor_accessor_ = false;
   clear_has_no_standard_descriptor_accessor();
 }
@@ -8869,16 +9452,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool MessageOptions::has_deprecated() const {
+bool MessageOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void MessageOptions::set_has_deprecated() {
+void MessageOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000004u;
 }
- void MessageOptions::clear_has_deprecated() {
+void MessageOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void MessageOptions::clear_deprecated() {
+void MessageOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -8893,16 +9476,16 @@
 }
 
 // optional bool map_entry = 7;
- bool MessageOptions::has_map_entry() const {
+bool MessageOptions::has_map_entry() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void MessageOptions::set_has_map_entry() {
+void MessageOptions::set_has_map_entry() {
   _has_bits_[0] |= 0x00000008u;
 }
- void MessageOptions::clear_has_map_entry() {
+void MessageOptions::clear_has_map_entry() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void MessageOptions::clear_map_entry() {
+void MessageOptions::clear_map_entry() {
   map_entry_ = false;
   clear_has_map_entry();
 }
@@ -8917,10 +9500,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int MessageOptions::uninterpreted_option_size() const {
+int MessageOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void MessageOptions::clear_uninterpreted_option() {
+void MessageOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const {
@@ -8973,9 +9556,33 @@
 const FieldOptions_CType FieldOptions::CType_MAX;
 const int FieldOptions::CType_ARRAYSIZE;
 #endif  // _MSC_VER
+const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FieldOptions_JSType_descriptor_;
+}
+bool FieldOptions_JSType_IsValid(int value) {
+  switch(value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#ifndef _MSC_VER
+const FieldOptions_JSType FieldOptions::JS_NORMAL;
+const FieldOptions_JSType FieldOptions::JS_STRING;
+const FieldOptions_JSType FieldOptions::JS_NUMBER;
+const FieldOptions_JSType FieldOptions::JSType_MIN;
+const FieldOptions_JSType FieldOptions::JSType_MAX;
+const int FieldOptions::JSType_ARRAYSIZE;
+#endif  // _MSC_VER
 #ifndef _MSC_VER
 const int FieldOptions::kCtypeFieldNumber;
 const int FieldOptions::kPackedFieldNumber;
+const int FieldOptions::kJstypeFieldNumber;
 const int FieldOptions::kLazyFieldNumber;
 const int FieldOptions::kDeprecatedFieldNumber;
 const int FieldOptions::kWeakFieldNumber;
@@ -8983,7 +9590,7 @@
 #endif  // !_MSC_VER
 
 FieldOptions::FieldOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldOptions)
 }
@@ -9003,6 +9610,7 @@
   _cached_size_ = 0;
   ctype_ = 0;
   packed_ = false;
+  jstype_ = 0;
   lazy_ = false;
   deprecated_ = false;
   weak_ = false;
@@ -9054,8 +9662,9 @@
            ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
 } while (0)
 
-  if (_has_bits_[0 / 32] & 31u) {
-    ZR_(ctype_, weak_);
+  if (_has_bits_[0 / 32] & 63u) {
+    ZR_(ctype_, jstype_);
+    ZR_(packed_, weak_);
   }
 
 #undef ZR_HELPER_
@@ -9138,6 +9747,26 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(48)) goto parse_jstype;
+        break;
+      }
+
+      // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+      case 6: {
+        if (tag == 48) {
+         parse_jstype:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::google::protobuf::FieldOptions_JSType_IsValid(value)) {
+            set_jstype(static_cast< ::google::protobuf::FieldOptions_JSType >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(6, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectTag(80)) goto parse_weak;
         break;
       }
@@ -9161,12 +9790,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -9222,6 +9854,12 @@
     ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output);
   }
 
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (has_jstype()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->jstype(), output);
+  }
+
   // optional bool weak = 10 [default = false];
   if (has_weak()) {
     ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output);
@@ -9268,6 +9906,12 @@
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target);
   }
 
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  if (has_jstype()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->jstype(), target);
+  }
+
   // optional bool weak = 10 [default = false];
   if (has_weak()) {
     target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target);
@@ -9295,7 +9939,7 @@
 int FieldOptions::ByteSize() const {
   int total_size = 0;
 
-  if (_has_bits_[0 / 32] & 31) {
+  if (_has_bits_[0 / 32] & 63) {
     // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
     if (has_ctype()) {
       total_size += 1 +
@@ -9307,6 +9951,12 @@
       total_size += 1 + 1;
     }
 
+    // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+    if (has_jstype()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->jstype());
+    }
+
     // optional bool lazy = 5 [default = false];
     if (has_lazy()) {
       total_size += 1 + 1;
@@ -9346,9 +9996,9 @@
 
 void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FieldOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldOptions*>(
-      &from);
+  const FieldOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -9366,6 +10016,9 @@
     if (from.has_packed()) {
       set_packed(from.packed());
     }
+    if (from.has_jstype()) {
+      set_jstype(from.jstype());
+    }
     if (from.has_lazy()) {
       set_lazy(from.lazy());
     }
@@ -9408,6 +10061,7 @@
 void FieldOptions::InternalSwap(FieldOptions* other) {
   std::swap(ctype_, other->ctype_);
   std::swap(packed_, other->packed_);
+  std::swap(jstype_, other->jstype_);
   std::swap(lazy_, other->lazy_);
   std::swap(deprecated_, other->deprecated_);
   std::swap(weak_, other->weak_);
@@ -9430,16 +10084,16 @@
 // FieldOptions
 
 // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
- bool FieldOptions::has_ctype() const {
+bool FieldOptions::has_ctype() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void FieldOptions::set_has_ctype() {
+void FieldOptions::set_has_ctype() {
   _has_bits_[0] |= 0x00000001u;
 }
- void FieldOptions::clear_has_ctype() {
+void FieldOptions::clear_has_ctype() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void FieldOptions::clear_ctype() {
+void FieldOptions::clear_ctype() {
   ctype_ = 0;
   clear_has_ctype();
 }
@@ -9455,16 +10109,16 @@
 }
 
 // optional bool packed = 2;
- bool FieldOptions::has_packed() const {
+bool FieldOptions::has_packed() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void FieldOptions::set_has_packed() {
+void FieldOptions::set_has_packed() {
   _has_bits_[0] |= 0x00000002u;
 }
- void FieldOptions::clear_has_packed() {
+void FieldOptions::clear_has_packed() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void FieldOptions::clear_packed() {
+void FieldOptions::clear_packed() {
   packed_ = false;
   clear_has_packed();
 }
@@ -9478,17 +10132,42 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
 }
 
-// optional bool lazy = 5 [default = false];
- bool FieldOptions::has_lazy() const {
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+bool FieldOptions::has_jstype() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void FieldOptions::set_has_lazy() {
+void FieldOptions::set_has_jstype() {
   _has_bits_[0] |= 0x00000004u;
 }
- void FieldOptions::clear_has_lazy() {
+void FieldOptions::clear_has_jstype() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void FieldOptions::clear_lazy() {
+void FieldOptions::clear_jstype() {
+  jstype_ = 0;
+  clear_has_jstype();
+}
+ ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_);
+}
+ void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) {
+  assert(::google::protobuf::FieldOptions_JSType_IsValid(value));
+  set_has_jstype();
+  jstype_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+bool FieldOptions::has_lazy() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void FieldOptions::set_has_lazy() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void FieldOptions::clear_has_lazy() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void FieldOptions::clear_lazy() {
   lazy_ = false;
   clear_has_lazy();
 }
@@ -9503,16 +10182,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool FieldOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00000008u) != 0;
+bool FieldOptions::has_deprecated() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void FieldOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00000008u;
+void FieldOptions::set_has_deprecated() {
+  _has_bits_[0] |= 0x00000010u;
 }
- void FieldOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00000008u;
+void FieldOptions::clear_has_deprecated() {
+  _has_bits_[0] &= ~0x00000010u;
 }
- void FieldOptions::clear_deprecated() {
+void FieldOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -9527,16 +10206,16 @@
 }
 
 // optional bool weak = 10 [default = false];
- bool FieldOptions::has_weak() const {
-  return (_has_bits_[0] & 0x00000010u) != 0;
+bool FieldOptions::has_weak() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void FieldOptions::set_has_weak() {
-  _has_bits_[0] |= 0x00000010u;
+void FieldOptions::set_has_weak() {
+  _has_bits_[0] |= 0x00000020u;
 }
- void FieldOptions::clear_has_weak() {
-  _has_bits_[0] &= ~0x00000010u;
+void FieldOptions::clear_has_weak() {
+  _has_bits_[0] &= ~0x00000020u;
 }
- void FieldOptions::clear_weak() {
+void FieldOptions::clear_weak() {
   weak_ = false;
   clear_has_weak();
 }
@@ -9551,10 +10230,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int FieldOptions::uninterpreted_option_size() const {
+int FieldOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void FieldOptions::clear_uninterpreted_option() {
+void FieldOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const {
@@ -9591,7 +10270,7 @@
 #endif  // !_MSC_VER
 
 EnumOptions::EnumOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumOptions)
 }
@@ -9714,12 +10393,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -9851,9 +10533,9 @@
 
 void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumOptions*>(
-      &from);
+  const EnumOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -9923,16 +10605,16 @@
 // EnumOptions
 
 // optional bool allow_alias = 2;
- bool EnumOptions::has_allow_alias() const {
+bool EnumOptions::has_allow_alias() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumOptions::set_has_allow_alias() {
+void EnumOptions::set_has_allow_alias() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumOptions::clear_has_allow_alias() {
+void EnumOptions::clear_has_allow_alias() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumOptions::clear_allow_alias() {
+void EnumOptions::clear_allow_alias() {
   allow_alias_ = false;
   clear_has_allow_alias();
 }
@@ -9947,16 +10629,16 @@
 }
 
 // optional bool deprecated = 3 [default = false];
- bool EnumOptions::has_deprecated() const {
+bool EnumOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void EnumOptions::set_has_deprecated() {
+void EnumOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000002u;
 }
- void EnumOptions::clear_has_deprecated() {
+void EnumOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void EnumOptions::clear_deprecated() {
+void EnumOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -9971,10 +10653,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int EnumOptions::uninterpreted_option_size() const {
+int EnumOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void EnumOptions::clear_uninterpreted_option() {
+void EnumOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const {
@@ -10010,7 +10692,7 @@
 #endif  // !_MSC_VER
 
 EnumValueOptions::EnumValueOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValueOptions)
 }
@@ -10105,12 +10787,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -10225,9 +10910,9 @@
 
 void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumValueOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValueOptions*>(
-      &from);
+  const EnumValueOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValueOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10293,16 +10978,16 @@
 // EnumValueOptions
 
 // optional bool deprecated = 1 [default = false];
- bool EnumValueOptions::has_deprecated() const {
+bool EnumValueOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void EnumValueOptions::set_has_deprecated() {
+void EnumValueOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void EnumValueOptions::clear_has_deprecated() {
+void EnumValueOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void EnumValueOptions::clear_deprecated() {
+void EnumValueOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -10317,10 +11002,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int EnumValueOptions::uninterpreted_option_size() const {
+int EnumValueOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void EnumValueOptions::clear_uninterpreted_option() {
+void EnumValueOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const {
@@ -10356,7 +11041,7 @@
 #endif  // !_MSC_VER
 
 ServiceOptions::ServiceOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ServiceOptions)
 }
@@ -10451,12 +11136,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -10571,9 +11259,9 @@
 
 void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const ServiceOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ServiceOptions*>(
-      &from);
+  const ServiceOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ServiceOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10639,16 +11327,16 @@
 // ServiceOptions
 
 // optional bool deprecated = 33 [default = false];
- bool ServiceOptions::has_deprecated() const {
+bool ServiceOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void ServiceOptions::set_has_deprecated() {
+void ServiceOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void ServiceOptions::clear_has_deprecated() {
+void ServiceOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void ServiceOptions::clear_deprecated() {
+void ServiceOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -10663,10 +11351,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int ServiceOptions::uninterpreted_option_size() const {
+int ServiceOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void ServiceOptions::clear_uninterpreted_option() {
+void ServiceOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const {
@@ -10702,7 +11390,7 @@
 #endif  // !_MSC_VER
 
 MethodOptions::MethodOptions()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.MethodOptions)
 }
@@ -10797,12 +11485,15 @@
       case 999: {
         if (tag == 7994) {
          parse_uninterpreted_option:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_uninterpreted_option()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(7994)) goto parse_uninterpreted_option;
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -10917,9 +11608,9 @@
 
 void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const MethodOptions* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const MethodOptions*>(
-      &from);
+  const MethodOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const MethodOptions>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -10985,16 +11676,16 @@
 // MethodOptions
 
 // optional bool deprecated = 33 [default = false];
- bool MethodOptions::has_deprecated() const {
+bool MethodOptions::has_deprecated() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void MethodOptions::set_has_deprecated() {
+void MethodOptions::set_has_deprecated() {
   _has_bits_[0] |= 0x00000001u;
 }
- void MethodOptions::clear_has_deprecated() {
+void MethodOptions::clear_has_deprecated() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void MethodOptions::clear_deprecated() {
+void MethodOptions::clear_deprecated() {
   deprecated_ = false;
   clear_has_deprecated();
 }
@@ -11009,10 +11700,10 @@
 }
 
 // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- int MethodOptions::uninterpreted_option_size() const {
+int MethodOptions::uninterpreted_option_size() const {
   return uninterpreted_option_.size();
 }
- void MethodOptions::clear_uninterpreted_option() {
+void MethodOptions::clear_uninterpreted_option() {
   uninterpreted_option_.Clear();
 }
  const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const {
@@ -11048,7 +11739,7 @@
 #endif  // !_MSC_VER
 
 UninterpretedOption_NamePart::UninterpretedOption_NamePart()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption.NamePart)
 }
@@ -11281,9 +11972,9 @@
 
 void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UninterpretedOption_NamePart* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption_NamePart*>(
-      &from);
+  const UninterpretedOption_NamePart* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption_NamePart>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -11359,7 +12050,7 @@
 #endif  // !_MSC_VER
 
 UninterpretedOption::UninterpretedOption()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption)
 }
@@ -11470,13 +12161,15 @@
       // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
       case 2: {
         if (tag == 18) {
-         parse_name:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_name()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_name;
+        if (input->ExpectTag(18)) goto parse_loop_name;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_identifier_value;
         break;
       }
@@ -11780,9 +12473,9 @@
 
 void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UninterpretedOption* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UninterpretedOption*>(
-      &from);
+  const UninterpretedOption* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UninterpretedOption>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -11868,16 +12561,16 @@
 // UninterpretedOption_NamePart
 
 // required string name_part = 1;
- bool UninterpretedOption_NamePart::has_name_part() const {
+bool UninterpretedOption_NamePart::has_name_part() const {
   return (_has_bits_[0] & 0x00000001u) != 0;
 }
- void UninterpretedOption_NamePart::set_has_name_part() {
+void UninterpretedOption_NamePart::set_has_name_part() {
   _has_bits_[0] |= 0x00000001u;
 }
- void UninterpretedOption_NamePart::clear_has_name_part() {
+void UninterpretedOption_NamePart::clear_has_name_part() {
   _has_bits_[0] &= ~0x00000001u;
 }
- void UninterpretedOption_NamePart::clear_name_part() {
+void UninterpretedOption_NamePart::clear_name_part() {
   name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_name_part();
 }
@@ -11921,16 +12614,16 @@
 }
 
 // required bool is_extension = 2;
- bool UninterpretedOption_NamePart::has_is_extension() const {
+bool UninterpretedOption_NamePart::has_is_extension() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void UninterpretedOption_NamePart::set_has_is_extension() {
+void UninterpretedOption_NamePart::set_has_is_extension() {
   _has_bits_[0] |= 0x00000002u;
 }
- void UninterpretedOption_NamePart::clear_has_is_extension() {
+void UninterpretedOption_NamePart::clear_has_is_extension() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void UninterpretedOption_NamePart::clear_is_extension() {
+void UninterpretedOption_NamePart::clear_is_extension() {
   is_extension_ = false;
   clear_has_is_extension();
 }
@@ -11949,10 +12642,10 @@
 // UninterpretedOption
 
 // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- int UninterpretedOption::name_size() const {
+int UninterpretedOption::name_size() const {
   return name_.size();
 }
- void UninterpretedOption::clear_name() {
+void UninterpretedOption::clear_name() {
   name_.Clear();
 }
  const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const {
@@ -11979,16 +12672,16 @@
 }
 
 // optional string identifier_value = 3;
- bool UninterpretedOption::has_identifier_value() const {
+bool UninterpretedOption::has_identifier_value() const {
   return (_has_bits_[0] & 0x00000002u) != 0;
 }
- void UninterpretedOption::set_has_identifier_value() {
+void UninterpretedOption::set_has_identifier_value() {
   _has_bits_[0] |= 0x00000002u;
 }
- void UninterpretedOption::clear_has_identifier_value() {
+void UninterpretedOption::clear_has_identifier_value() {
   _has_bits_[0] &= ~0x00000002u;
 }
- void UninterpretedOption::clear_identifier_value() {
+void UninterpretedOption::clear_identifier_value() {
   identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_identifier_value();
 }
@@ -12032,16 +12725,16 @@
 }
 
 // optional uint64 positive_int_value = 4;
- bool UninterpretedOption::has_positive_int_value() const {
+bool UninterpretedOption::has_positive_int_value() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void UninterpretedOption::set_has_positive_int_value() {
+void UninterpretedOption::set_has_positive_int_value() {
   _has_bits_[0] |= 0x00000004u;
 }
- void UninterpretedOption::clear_has_positive_int_value() {
+void UninterpretedOption::clear_has_positive_int_value() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void UninterpretedOption::clear_positive_int_value() {
+void UninterpretedOption::clear_positive_int_value() {
   positive_int_value_ = GOOGLE_ULONGLONG(0);
   clear_has_positive_int_value();
 }
@@ -12056,16 +12749,16 @@
 }
 
 // optional int64 negative_int_value = 5;
- bool UninterpretedOption::has_negative_int_value() const {
+bool UninterpretedOption::has_negative_int_value() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void UninterpretedOption::set_has_negative_int_value() {
+void UninterpretedOption::set_has_negative_int_value() {
   _has_bits_[0] |= 0x00000008u;
 }
- void UninterpretedOption::clear_has_negative_int_value() {
+void UninterpretedOption::clear_has_negative_int_value() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void UninterpretedOption::clear_negative_int_value() {
+void UninterpretedOption::clear_negative_int_value() {
   negative_int_value_ = GOOGLE_LONGLONG(0);
   clear_has_negative_int_value();
 }
@@ -12080,16 +12773,16 @@
 }
 
 // optional double double_value = 6;
- bool UninterpretedOption::has_double_value() const {
+bool UninterpretedOption::has_double_value() const {
   return (_has_bits_[0] & 0x00000010u) != 0;
 }
- void UninterpretedOption::set_has_double_value() {
+void UninterpretedOption::set_has_double_value() {
   _has_bits_[0] |= 0x00000010u;
 }
- void UninterpretedOption::clear_has_double_value() {
+void UninterpretedOption::clear_has_double_value() {
   _has_bits_[0] &= ~0x00000010u;
 }
- void UninterpretedOption::clear_double_value() {
+void UninterpretedOption::clear_double_value() {
   double_value_ = 0;
   clear_has_double_value();
 }
@@ -12104,16 +12797,16 @@
 }
 
 // optional bytes string_value = 7;
- bool UninterpretedOption::has_string_value() const {
+bool UninterpretedOption::has_string_value() const {
   return (_has_bits_[0] & 0x00000020u) != 0;
 }
- void UninterpretedOption::set_has_string_value() {
+void UninterpretedOption::set_has_string_value() {
   _has_bits_[0] |= 0x00000020u;
 }
- void UninterpretedOption::clear_has_string_value() {
+void UninterpretedOption::clear_has_string_value() {
   _has_bits_[0] &= ~0x00000020u;
 }
- void UninterpretedOption::clear_string_value() {
+void UninterpretedOption::clear_string_value() {
   string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_string_value();
 }
@@ -12157,16 +12850,16 @@
 }
 
 // optional string aggregate_value = 8;
- bool UninterpretedOption::has_aggregate_value() const {
+bool UninterpretedOption::has_aggregate_value() const {
   return (_has_bits_[0] & 0x00000040u) != 0;
 }
- void UninterpretedOption::set_has_aggregate_value() {
+void UninterpretedOption::set_has_aggregate_value() {
   _has_bits_[0] |= 0x00000040u;
 }
- void UninterpretedOption::clear_has_aggregate_value() {
+void UninterpretedOption::clear_has_aggregate_value() {
   _has_bits_[0] &= ~0x00000040u;
 }
- void UninterpretedOption::clear_aggregate_value() {
+void UninterpretedOption::clear_aggregate_value() {
   aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_aggregate_value();
 }
@@ -12222,7 +12915,7 @@
 #endif  // !_MSC_VER
 
 SourceCodeInfo_Location::SourceCodeInfo_Location()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo.Location)
 }
@@ -12625,9 +13318,9 @@
 
 void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const SourceCodeInfo_Location* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo_Location*>(
-      &from);
+  const SourceCodeInfo_Location* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo_Location>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -12703,7 +13396,7 @@
 #endif  // !_MSC_VER
 
 SourceCodeInfo::SourceCodeInfo()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo)
 }
@@ -12780,13 +13473,15 @@
       // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
       case 1: {
         if (tag == 10) {
-         parse_location:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_location:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_location()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_location;
+        if (input->ExpectTag(10)) goto parse_loop_location;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -12871,9 +13566,9 @@
 
 void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const SourceCodeInfo* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceCodeInfo*>(
-      &from);
+  const SourceCodeInfo* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceCodeInfo>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -12929,10 +13624,10 @@
 // SourceCodeInfo_Location
 
 // repeated int32 path = 1 [packed = true];
- int SourceCodeInfo_Location::path_size() const {
+int SourceCodeInfo_Location::path_size() const {
   return path_.size();
 }
- void SourceCodeInfo_Location::clear_path() {
+void SourceCodeInfo_Location::clear_path() {
   path_.Clear();
 }
  ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const {
@@ -12959,10 +13654,10 @@
 }
 
 // repeated int32 span = 2 [packed = true];
- int SourceCodeInfo_Location::span_size() const {
+int SourceCodeInfo_Location::span_size() const {
   return span_.size();
 }
- void SourceCodeInfo_Location::clear_span() {
+void SourceCodeInfo_Location::clear_span() {
   span_.Clear();
 }
  ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const {
@@ -12989,16 +13684,16 @@
 }
 
 // optional string leading_comments = 3;
- bool SourceCodeInfo_Location::has_leading_comments() const {
+bool SourceCodeInfo_Location::has_leading_comments() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
- void SourceCodeInfo_Location::set_has_leading_comments() {
+void SourceCodeInfo_Location::set_has_leading_comments() {
   _has_bits_[0] |= 0x00000004u;
 }
- void SourceCodeInfo_Location::clear_has_leading_comments() {
+void SourceCodeInfo_Location::clear_has_leading_comments() {
   _has_bits_[0] &= ~0x00000004u;
 }
- void SourceCodeInfo_Location::clear_leading_comments() {
+void SourceCodeInfo_Location::clear_leading_comments() {
   leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_leading_comments();
 }
@@ -13042,16 +13737,16 @@
 }
 
 // optional string trailing_comments = 4;
- bool SourceCodeInfo_Location::has_trailing_comments() const {
+bool SourceCodeInfo_Location::has_trailing_comments() const {
   return (_has_bits_[0] & 0x00000008u) != 0;
 }
- void SourceCodeInfo_Location::set_has_trailing_comments() {
+void SourceCodeInfo_Location::set_has_trailing_comments() {
   _has_bits_[0] |= 0x00000008u;
 }
- void SourceCodeInfo_Location::clear_has_trailing_comments() {
+void SourceCodeInfo_Location::clear_has_trailing_comments() {
   _has_bits_[0] &= ~0x00000008u;
 }
- void SourceCodeInfo_Location::clear_trailing_comments() {
+void SourceCodeInfo_Location::clear_trailing_comments() {
   trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   clear_has_trailing_comments();
 }
@@ -13095,10 +13790,10 @@
 }
 
 // repeated string leading_detached_comments = 6;
- int SourceCodeInfo_Location::leading_detached_comments_size() const {
+int SourceCodeInfo_Location::leading_detached_comments_size() const {
   return leading_detached_comments_.size();
 }
- void SourceCodeInfo_Location::clear_leading_detached_comments() {
+void SourceCodeInfo_Location::clear_leading_detached_comments() {
   leading_detached_comments_.Clear();
 }
  const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const {
@@ -13153,10 +13848,10 @@
 // SourceCodeInfo
 
 // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
- int SourceCodeInfo::location_size() const {
+int SourceCodeInfo::location_size() const {
   return location_.size();
 }
- void SourceCodeInfo::clear_location() {
+void SourceCodeInfo::clear_location() {
   location_.Clear();
 }
  const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const {
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 5bebf4f..b887b8c 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -42,6 +42,7 @@
 class FileDescriptorProto;
 class DescriptorProto;
 class DescriptorProto_ExtensionRange;
+class DescriptorProto_ReservedRange;
 class FieldDescriptorProto;
 class OneofDescriptorProto;
 class EnumDescriptorProto;
@@ -155,6 +156,26 @@
   return ::google::protobuf::internal::ParseNamedEnum<FieldOptions_CType>(
     FieldOptions_CType_descriptor(), name, value);
 }
+enum FieldOptions_JSType {
+  FieldOptions_JSType_JS_NORMAL = 0,
+  FieldOptions_JSType_JS_STRING = 1,
+  FieldOptions_JSType_JS_NUMBER = 2
+};
+LIBPROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
+const FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
+const FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
+const int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
+
+LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor();
+inline const ::std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    FieldOptions_JSType_descriptor(), value);
+}
+inline bool FieldOptions_JSType_Parse(
+    const ::std::string& name, FieldOptions_JSType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<FieldOptions_JSType>(
+    FieldOptions_JSType_descriptor(), name, value);
+}
 // ===================================================================
 
 class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message {
@@ -591,6 +612,105 @@
 };
 // -------------------------------------------------------------------
 
+class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message {
+ public:
+  DescriptorProto_ReservedRange();
+  virtual ~DescriptorProto_ReservedRange();
+
+  DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from);
+
+  inline DescriptorProto_ReservedRange& operator=(const DescriptorProto_ReservedRange& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DescriptorProto_ReservedRange& default_instance();
+
+  void Swap(DescriptorProto_ReservedRange* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DescriptorProto_ReservedRange* New() const { return New(NULL); }
+
+  DescriptorProto_ReservedRange* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DescriptorProto_ReservedRange& from);
+  void MergeFrom(const DescriptorProto_ReservedRange& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DescriptorProto_ReservedRange* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 start = 1;
+  bool has_start() const;
+  void clear_start();
+  static const int kStartFieldNumber = 1;
+  ::google::protobuf::int32 start() const;
+  void set_start(::google::protobuf::int32 value);
+
+  // optional int32 end = 2;
+  bool has_end() const;
+  void clear_end();
+  static const int kEndFieldNumber = 2;
+  ::google::protobuf::int32 end() const;
+  void set_end(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange)
+ private:
+  inline void set_has_start();
+  inline void clear_has_start();
+  inline void set_has_end();
+  inline void clear_has_end();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::int32 start_;
+  ::google::protobuf::int32 end_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static DescriptorProto_ReservedRange* default_instance_;
+};
+// -------------------------------------------------------------------
+
 class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
  public:
   DescriptorProto();
@@ -654,6 +774,7 @@
   // nested types ----------------------------------------------------
 
   typedef DescriptorProto_ExtensionRange ExtensionRange;
+  typedef DescriptorProto_ReservedRange ReservedRange;
 
   // accessors -------------------------------------------------------
 
@@ -750,6 +871,34 @@
   ::google::protobuf::MessageOptions* release_options();
   void set_allocated_options(::google::protobuf::MessageOptions* options);
 
+  // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+  int reserved_range_size() const;
+  void clear_reserved_range();
+  static const int kReservedRangeFieldNumber = 9;
+  const ::google::protobuf::DescriptorProto_ReservedRange& reserved_range(int index) const;
+  ::google::protobuf::DescriptorProto_ReservedRange* mutable_reserved_range(int index);
+  ::google::protobuf::DescriptorProto_ReservedRange* add_reserved_range();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+      reserved_range() const;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+      mutable_reserved_range();
+
+  // repeated string reserved_name = 10;
+  int reserved_name_size() const;
+  void clear_reserved_name();
+  static const int kReservedNameFieldNumber = 10;
+  const ::std::string& reserved_name(int index) const;
+  ::std::string* mutable_reserved_name(int index);
+  void set_reserved_name(int index, const ::std::string& value);
+  void set_reserved_name(int index, const char* value);
+  void set_reserved_name(int index, const char* value, size_t size);
+  ::std::string* add_reserved_name();
+  void add_reserved_name(const ::std::string& value);
+  void add_reserved_name(const char* value);
+  void add_reserved_name(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& reserved_name() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_reserved_name();
+
   // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto)
  private:
   inline void set_has_name();
@@ -768,6 +917,8 @@
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto > oneof_decl_;
   ::google::protobuf::MessageOptions* options_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange > reserved_range_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> reserved_name_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -2144,6 +2295,31 @@
     return FieldOptions_CType_Parse(name, value);
   }
 
+  typedef FieldOptions_JSType JSType;
+  static const JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL;
+  static const JSType JS_STRING = FieldOptions_JSType_JS_STRING;
+  static const JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER;
+  static inline bool JSType_IsValid(int value) {
+    return FieldOptions_JSType_IsValid(value);
+  }
+  static const JSType JSType_MIN =
+    FieldOptions_JSType_JSType_MIN;
+  static const JSType JSType_MAX =
+    FieldOptions_JSType_JSType_MAX;
+  static const int JSType_ARRAYSIZE =
+    FieldOptions_JSType_JSType_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  JSType_descriptor() {
+    return FieldOptions_JSType_descriptor();
+  }
+  static inline const ::std::string& JSType_Name(JSType value) {
+    return FieldOptions_JSType_Name(value);
+  }
+  static inline bool JSType_Parse(const ::std::string& name,
+      JSType* value) {
+    return FieldOptions_JSType_Parse(name, value);
+  }
+
   // accessors -------------------------------------------------------
 
   // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
@@ -2160,6 +2336,13 @@
   bool packed() const;
   void set_packed(bool value);
 
+  // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+  bool has_jstype() const;
+  void clear_jstype();
+  static const int kJstypeFieldNumber = 6;
+  ::google::protobuf::FieldOptions_JSType jstype() const;
+  void set_jstype(::google::protobuf::FieldOptions_JSType value);
+
   // optional bool lazy = 5 [default = false];
   bool has_lazy() const;
   void clear_lazy();
@@ -2200,6 +2383,8 @@
   inline void clear_has_ctype();
   inline void set_has_packed();
   inline void clear_has_packed();
+  inline void set_has_jstype();
+  inline void clear_has_jstype();
   inline void set_has_lazy();
   inline void clear_has_lazy();
   inline void set_has_deprecated();
@@ -2213,11 +2398,12 @@
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   int ctype_;
+  int jstype_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   bool packed_;
   bool lazy_;
   bool deprecated_;
   bool weak_;
-  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -3754,6 +3940,58 @@
 
 // -------------------------------------------------------------------
 
+// DescriptorProto_ReservedRange
+
+// optional int32 start = 1;
+inline bool DescriptorProto_ReservedRange::has_start() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DescriptorProto_ReservedRange::set_has_start() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DescriptorProto_ReservedRange::clear_has_start() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DescriptorProto_ReservedRange::clear_start() {
+  start_ = 0;
+  clear_has_start();
+}
+inline ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start)
+  return start_;
+}
+inline void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) {
+  set_has_start();
+  start_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start)
+}
+
+// optional int32 end = 2;
+inline bool DescriptorProto_ReservedRange::has_end() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DescriptorProto_ReservedRange::set_has_end() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DescriptorProto_ReservedRange::clear_has_end() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DescriptorProto_ReservedRange::clear_end() {
+  end_ = 0;
+  clear_has_end();
+}
+inline ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end)
+  return end_;
+}
+inline void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) {
+  set_has_end();
+  end_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end)
+}
+
+// -------------------------------------------------------------------
+
 // DescriptorProto
 
 // optional string name = 1;
@@ -4032,6 +4270,90 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options)
 }
 
+// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
+inline int DescriptorProto::reserved_range_size() const {
+  return reserved_range_.size();
+}
+inline void DescriptorProto::clear_reserved_range() {
+  reserved_range_.Clear();
+}
+inline const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Get(index);
+}
+inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Mutable(index);
+}
+inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() {
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_.Add();
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >&
+DescriptorProto::reserved_range() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range)
+  return reserved_range_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >*
+DescriptorProto::mutable_reserved_range() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range)
+  return &reserved_range_;
+}
+
+// repeated string reserved_name = 10;
+inline int DescriptorProto::reserved_name_size() const {
+  return reserved_name_.size();
+}
+inline void DescriptorProto::clear_reserved_name() {
+  reserved_name_.Clear();
+}
+inline const ::std::string& DescriptorProto::reserved_name(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Get(index);
+}
+inline ::std::string* DescriptorProto::mutable_reserved_name(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_.Mutable(index);
+}
+inline void DescriptorProto::set_reserved_name(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name)
+  reserved_name_.Mutable(index)->assign(value);
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value) {
+  reserved_name_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) {
+  reserved_name_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline ::std::string* DescriptorProto::add_reserved_name() {
+  return reserved_name_.Add();
+}
+inline void DescriptorProto::add_reserved_name(const ::std::string& value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value) {
+  reserved_name_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name)
+}
+inline void DescriptorProto::add_reserved_name(const char* value, size_t size) {
+  reserved_name_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+DescriptorProto::reserved_name() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name)
+  return reserved_name_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+DescriptorProto::mutable_reserved_name() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name)
+  return &reserved_name_;
+}
+
 // -------------------------------------------------------------------
 
 // FieldDescriptorProto
@@ -5783,16 +6105,41 @@
   // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed)
 }
 
-// optional bool lazy = 5 [default = false];
-inline bool FieldOptions::has_lazy() const {
+// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
+inline bool FieldOptions::has_jstype() const {
   return (_has_bits_[0] & 0x00000004u) != 0;
 }
-inline void FieldOptions::set_has_lazy() {
+inline void FieldOptions::set_has_jstype() {
   _has_bits_[0] |= 0x00000004u;
 }
-inline void FieldOptions::clear_has_lazy() {
+inline void FieldOptions::clear_has_jstype() {
   _has_bits_[0] &= ~0x00000004u;
 }
+inline void FieldOptions::clear_jstype() {
+  jstype_ = 0;
+  clear_has_jstype();
+}
+inline ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype)
+  return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_);
+}
+inline void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) {
+  assert(::google::protobuf::FieldOptions_JSType_IsValid(value));
+  set_has_jstype();
+  jstype_ = value;
+  // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype)
+}
+
+// optional bool lazy = 5 [default = false];
+inline bool FieldOptions::has_lazy() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void FieldOptions::set_has_lazy() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void FieldOptions::clear_has_lazy() {
+  _has_bits_[0] &= ~0x00000008u;
+}
 inline void FieldOptions::clear_lazy() {
   lazy_ = false;
   clear_has_lazy();
@@ -5809,13 +6156,13 @@
 
 // optional bool deprecated = 3 [default = false];
 inline bool FieldOptions::has_deprecated() const {
-  return (_has_bits_[0] & 0x00000008u) != 0;
+  return (_has_bits_[0] & 0x00000010u) != 0;
 }
 inline void FieldOptions::set_has_deprecated() {
-  _has_bits_[0] |= 0x00000008u;
+  _has_bits_[0] |= 0x00000010u;
 }
 inline void FieldOptions::clear_has_deprecated() {
-  _has_bits_[0] &= ~0x00000008u;
+  _has_bits_[0] &= ~0x00000010u;
 }
 inline void FieldOptions::clear_deprecated() {
   deprecated_ = false;
@@ -5833,13 +6180,13 @@
 
 // optional bool weak = 10 [default = false];
 inline bool FieldOptions::has_weak() const {
-  return (_has_bits_[0] & 0x00000010u) != 0;
+  return (_has_bits_[0] & 0x00000020u) != 0;
 }
 inline void FieldOptions::set_has_weak() {
-  _has_bits_[0] |= 0x00000010u;
+  _has_bits_[0] |= 0x00000020u;
 }
 inline void FieldOptions::clear_has_weak() {
-  _has_bits_[0] &= ~0x00000010u;
+  _has_bits_[0] &= ~0x00000020u;
 }
 inline void FieldOptions::clear_weak() {
   weak_ = false;
@@ -6746,6 +7093,48 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
@@ -6776,6 +7165,11 @@
 inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() {
   return ::google::protobuf::FieldOptions_CType_descriptor();
 }
+template <> struct is_proto_enum< ::google::protobuf::FieldOptions_JSType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_JSType>() {
+  return ::google::protobuf::FieldOptions_JSType_descriptor();
+}
 
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 7099135..20a6008 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -106,6 +106,18 @@
   repeated OneofDescriptorProto oneof_decl = 8;
 
   optional MessageOptions options = 7;
+
+  // Range of reserved tag numbers. Reserved tag numbers may not be used by
+  // fields or extension ranges in the same message. Reserved ranges may
+  // not overlap.
+  message ReservedRange {
+    optional int32 start = 1; // Inclusive.
+    optional int32 end = 2;   // Exclusive.
+  }
+  repeated ReservedRange reserved_range = 9;
+  // Reserved field names, which may not be used by fields in the same message.
+  // A given name may only be reserved once.
+  repeated string reserved_name = 10;
 }
 
 // Describes a field within a message.
@@ -251,11 +263,11 @@
 // * For options which will be published and used publicly by multiple
 //   independent entities, e-mail protobuf-global-extension-registry@google.com
 //   to reserve extension numbers. Simply provide your project name (e.g.
-//   Object-C plugin) and your porject website (if available) -- there's no need
-//   to explain how you intend to use them. Usually you only need one extension
-//   number. You can declare multiple options with only one extension number by
-//   putting them in a sub-message. See the Custom Options section of the docs
-//   for examples:
+//   Objective-C plugin) and your project website (if available) -- there's no
+//   need to explain how you intend to use them. Usually you only need one
+//   extension number. You can declare multiple options with only one extension
+//   number by putting them in a sub-message. See the Custom Options section of
+//   the docs for examples:
 //   https://developers.google.com/protocol-buffers/docs/proto#options
 //   If this turns out to be popular, a web service will be set up
 //   to automatically assign option numbers.
@@ -442,10 +454,31 @@
   // The packed option can be enabled for repeated primitive fields to enable
   // a more efficient representation on the wire. Rather than repeatedly
   // writing the tag and type for each element, the entire array is encoded as
-  // a single length-delimited blob.
+  // a single length-delimited blob. In proto3, only explicit setting it to
+  // false will avoid using packed encoding.
   optional bool packed = 2;
 
 
+  // The jstype option determines the JavaScript type used for values of the
+  // field.  The option is permitted only for 64 bit integral and fixed types
+  // (int64, uint64, sint64, fixed64, sfixed64).  By default these types are
+  // represented as JavaScript strings.  This avoids loss of precision that can
+  // happen when a large value is converted to a floating point JavaScript
+  // numbers.  Specifying JS_NUMBER for the jstype causes the generated
+  // JavaScript code to use the JavaScript "number" type instead of strings.
+  // This option is an enum to permit additional types to be added,
+  // e.g. goog.math.Integer.
+  optional JSType jstype = 6 [default = JS_NORMAL];
+  enum JSType {
+    // Use the default type.
+    JS_NORMAL = 0;
+
+    // Use JavaScript strings.
+    JS_STRING = 1;
+
+    // Use JavaScript numbers.
+    JS_NUMBER = 2;
+  }
 
   // Should this field be parsed lazily?  Lazy applies only to message-type
   // fields.  It means that when the outer message is initially parsed, the
diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h
index 934e402..86002d5 100644
--- a/src/google/protobuf/descriptor_database.h
+++ b/src/google/protobuf/descriptor_database.h
@@ -312,7 +312,7 @@
 // A DescriptorDatabase that fetches files from a given pool.
 class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
  public:
-  DescriptorPoolDatabase(const DescriptorPool& pool);
+  explicit DescriptorPoolDatabase(const DescriptorPool& pool);
   ~DescriptorPoolDatabase();
 
   // implements DescriptorDatabase -----------------------------------
@@ -341,7 +341,7 @@
   // Merge more than two databases.  The sources remain property of the caller.
   // The vector may be deleted after the constructor returns but the
   // DescriptorDatabases need to stick around.
-  MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
+  explicit MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
   ~MergedDescriptorDatabase();
 
   // implements DescriptorDatabase -----------------------------------
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index fdce3d7..760df09 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -139,6 +139,14 @@
   return result;
 }
 
+DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent,
+                                                 int start, int end) {
+  DescriptorProto::ReservedRange* result = parent->add_reserved_range();
+  result->set_start(start);
+  result->set_end(end);
+  return result;
+}
+
 EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto,
                                        const string& name, int number) {
   EnumValueDescriptorProto* result = enum_proto->add_value();
@@ -1720,6 +1728,84 @@
 
 // ===================================================================
 
+// Test reserved fields.
+class ReservedDescriptorTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Build descriptors for the following definitions:
+    //
+    //   message Foo {
+    //     reserved 2, 9 to 11, 15;
+    //     reserved "foo", "bar";
+    //   }
+
+    FileDescriptorProto foo_file;
+    foo_file.set_name("foo.proto");
+
+    DescriptorProto* foo = AddMessage(&foo_file, "Foo");
+    AddReservedRange(foo, 2, 3);
+    AddReservedRange(foo, 9, 12);
+    AddReservedRange(foo, 15, 16);
+
+    foo->add_reserved_name("foo");
+    foo->add_reserved_name("bar");
+
+    // Build the descriptors and get the pointers.
+    foo_file_ = pool_.BuildFile(foo_file);
+    ASSERT_TRUE(foo_file_ != NULL);
+
+    ASSERT_EQ(1, foo_file_->message_type_count());
+    foo_ = foo_file_->message_type(0);
+  }
+
+  DescriptorPool pool_;
+  const FileDescriptor* foo_file_;
+  const Descriptor* foo_;
+};
+
+TEST_F(ReservedDescriptorTest, ReservedRanges) {
+  ASSERT_EQ(3, foo_->reserved_range_count());
+
+  EXPECT_EQ(2, foo_->reserved_range(0)->start);
+  EXPECT_EQ(3, foo_->reserved_range(0)->end);
+
+  EXPECT_EQ(9, foo_->reserved_range(1)->start);
+  EXPECT_EQ(12, foo_->reserved_range(1)->end);
+
+  EXPECT_EQ(15, foo_->reserved_range(2)->start);
+  EXPECT_EQ(16, foo_->reserved_range(2)->end);
+};
+
+TEST_F(ReservedDescriptorTest, IsReservedNumber) {
+  EXPECT_FALSE(foo_->IsReservedNumber(1));
+  EXPECT_TRUE (foo_->IsReservedNumber(2));
+  EXPECT_FALSE(foo_->IsReservedNumber(3));
+  EXPECT_FALSE(foo_->IsReservedNumber(8));
+  EXPECT_TRUE (foo_->IsReservedNumber(9));
+  EXPECT_TRUE (foo_->IsReservedNumber(10));
+  EXPECT_TRUE (foo_->IsReservedNumber(11));
+  EXPECT_FALSE(foo_->IsReservedNumber(12));
+  EXPECT_FALSE(foo_->IsReservedNumber(13));
+  EXPECT_FALSE(foo_->IsReservedNumber(14));
+  EXPECT_TRUE (foo_->IsReservedNumber(15));
+  EXPECT_FALSE(foo_->IsReservedNumber(16));
+};
+
+TEST_F(ReservedDescriptorTest, ReservedNames) {
+  ASSERT_EQ(2, foo_->reserved_name_count());
+
+  EXPECT_EQ("foo", foo_->reserved_name(0));
+  EXPECT_EQ("bar", foo_->reserved_name(1));
+};
+
+TEST_F(ReservedDescriptorTest, IsReservedName) {
+  EXPECT_TRUE (foo_->IsReservedName("foo"));
+  EXPECT_TRUE (foo_->IsReservedName("bar"));
+  EXPECT_FALSE(foo_->IsReservedName("baz"));
+};
+
+// ===================================================================
+
 class MiscTest : public testing::Test {
  protected:
   // Function which makes a field descriptor of the given type.
@@ -2997,10 +3083,10 @@
  protected:
   // Parse file_text as a FileDescriptorProto in text format and add it
   // to the DescriptorPool.  Expect no errors.
-  void BuildFile(const string& file_text) {
+  const FileDescriptor* BuildFile(const string& file_text) {
     FileDescriptorProto file_proto;
-    ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
-    ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL);
+    EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
+    return GOOGLE_CHECK_NOTNULL(pool_.BuildFile(file_proto));
   }
 
   // Parse file_text as a FileDescriptorProto in text format and add it
@@ -3251,6 +3337,102 @@
       "already-defined range 20 to 29.\n");
 }
 
+TEST_F(ValidationErrorTest, ReservedFieldError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  reserved_range { start: 10 end: 20 }"
+    "}",
+
+    "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedExtensionRangeError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  extension_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 15 }"
+    "}",
+
+    "foo.proto: Foo: NUMBER: Extension range 10 to 19"
+    " overlaps with reserved range 5 to 14.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) {
+  BuildFile(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  extension_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 10 }"
+    "}");
+}
+
+TEST_F(ValidationErrorTest, ReservedRangeOverlap) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_range { start: 10 end: 20 }"
+    "  reserved_range { start: 5 end: 15 }"
+    "}",
+
+    "foo.proto: Foo: NUMBER: Reserved range 5 to 14"
+    " overlaps with already-defined range 10 to 19.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedNameError) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "}",
+
+    "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n"
+    "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedNameRedundant) {
+  BuildFileWithErrors(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"foo\""
+    "}",
+
+    "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n");
+}
+
+TEST_F(ValidationErrorTest, ReservedFieldsDebugString) {
+  const FileDescriptor* file = BuildFile(
+    "name: \"foo.proto\" "
+    "message_type {"
+    "  name: \"Foo\""
+    "  reserved_name: \"foo\""
+    "  reserved_name: \"bar\""
+    "  reserved_range { start: 5 end: 6 }"
+    "  reserved_range { start: 10 end: 20 }"
+    "}");
+
+  ASSERT_EQ(
+    "syntax = \"proto2\";\n\n"
+    "message Foo {\n"
+    "  reserved 5, 10 to 19;\n"
+    "  reserved \"foo\", \"bar\";\n"
+    "}\n\n",
+    file->DebugString());
+}
+
 TEST_F(ValidationErrorTest, InvalidDefaults) {
   BuildFileWithErrors(
     "name: \"foo.proto\" "
@@ -3399,6 +3581,48 @@
       "range for type \"Foo\".\n");
 }
 
+TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) {
+  // Fields belonging to the same oneof must be defined consecutively.
+  BuildFileWithWarnings(
+      "name: \"foo.proto\" "
+      "message_type {"
+      "  name: \"Foo\""
+      "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
+      "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  oneof_decl { name:\"foos\" }"
+      "}",
+
+      "foo.proto: Foo.bar: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"bar\" cannot be defined before the completion of the "
+      "\"foos\" oneof definition.\n");
+
+  // Prevent interleaved fields, which belong to different oneofs.
+  BuildFileWithWarnings(
+      "name: \"foo2.proto\" "
+      "message_type {"
+      "  name: \"Foo2\""
+      "  field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 0 }"
+      "  field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 "
+      "          oneof_index: 1 }"
+      "  oneof_decl { name:\"foos\" }"
+      "  oneof_decl { name:\"bars\" }"
+      "}",
+      "foo2.proto: Foo2.bar1: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"bar1\" cannot be defined before the completion of the "
+      "\"foos\" oneof definition.\n"
+      "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined "
+      "consecutively. \"foo2\" cannot be defined before the completion of the "
+      "\"bars\" oneof definition.\n");
+}
+
 TEST_F(ValidationErrorTest, FieldNumberConflict) {
   BuildFileWithErrors(
     "name: \"foo.proto\" "
@@ -5293,6 +5517,22 @@
       "in proto3.\n");
 }
 
+TEST_F(ValidationErrorTest, ValidateProto3Group) {
+  BuildFileWithErrors(
+      "name: 'foo.proto' "
+      "syntax: 'proto3' "
+      "message_type { "
+      "  name: 'Foo' "
+      "  nested_type { "
+      "    name: 'FooGroup' "
+      "  } "
+      "  field { name:'foo_group' number: 1 label:LABEL_OPTIONAL "
+      "          type: TYPE_GROUP type_name:'FooGroup' } "
+      "}",
+      "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 "
+      "syntax.\n");
+}
+
 
 TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) {
   // Define an enum in a proto2 file.
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index 4a11209..f78fce2 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -117,7 +117,7 @@
 #endif  // !_MSC_VER
 
 Duration::Duration()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Duration)
 }
@@ -310,9 +310,9 @@
 
 void Duration::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Duration* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Duration*>(
-      &from);
+  const Duration* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Duration>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -370,7 +370,7 @@
 // Duration
 
 // optional int64 seconds = 1;
- void Duration::clear_seconds() {
+void Duration::clear_seconds() {
   seconds_ = GOOGLE_LONGLONG(0);
 }
  ::google::protobuf::int64 Duration::seconds() const {
@@ -384,7 +384,7 @@
 }
 
 // optional int32 nanos = 2;
- void Duration::clear_nanos() {
+void Duration::clear_nanos() {
   nanos_ = 0;
 }
  ::google::protobuf::int32 Duration::nanos() const {
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index f7ca501..1a9a666 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -111,7 +111,7 @@
 #endif  // !_MSC_VER
 
 Empty::Empty()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Empty)
 }
@@ -221,9 +221,9 @@
 
 void Empty::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Empty* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Empty*>(
-      &from);
+  const Empty* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Empty>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 03b38dd..649ae18 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -314,7 +314,7 @@
     extension->is_repeated = true;                                             \
     extension->is_packed = packed;                                             \
     extension->repeated_##LOWERCASE##_value =                                  \
-      Arena::Create<RepeatedField<LOWERCASE> >(arena_, arena_);                \
+      Arena::CreateMessage<RepeatedField<LOWERCASE> >(arena_);                 \
   } else {                                                                     \
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE);                              \
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);                                   \
@@ -359,43 +359,43 @@
         static_cast<WireFormatLite::FieldType>(field_type))) {
       case WireFormatLite::CPPTYPE_INT32:
         extension->repeated_int32_value =
-            Arena::Create<RepeatedField<int32> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_INT64:
         extension->repeated_int64_value =
-            Arena::Create<RepeatedField<int64> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT32:
         extension->repeated_uint32_value =
-            Arena::Create<RepeatedField<uint32> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<uint32> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_UINT64:
         extension->repeated_uint64_value =
-            Arena::Create<RepeatedField<uint64> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<uint64> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_DOUBLE:
         extension->repeated_double_value =
-            Arena::Create<RepeatedField<double> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<double> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_FLOAT:
         extension->repeated_float_value =
-            Arena::Create<RepeatedField<float> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<float> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_BOOL:
         extension->repeated_bool_value =
-            Arena::Create<RepeatedField<bool> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<bool> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_ENUM:
         extension->repeated_enum_value =
-            Arena::Create<RepeatedField<int> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedField<int> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_STRING:
         extension->repeated_string_value =
-            Arena::Create<RepeatedPtrField< ::std::string> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedPtrField< ::std::string> >(arena_);
         break;
       case WireFormatLite::CPPTYPE_MESSAGE:
         extension->repeated_message_value =
-            Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+            Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
         break;
     }
   }
@@ -468,7 +468,7 @@
     extension->is_repeated = true;
     extension->is_packed = packed;
     extension->repeated_enum_value =
-        Arena::Create<RepeatedField<int> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedField<int> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM);
     GOOGLE_DCHECK_EQ(extension->is_packed, packed);
@@ -529,7 +529,7 @@
     extension->is_repeated = true;
     extension->is_packed = false;
     extension->repeated_string_value =
-        Arena::Create<RepeatedPtrField<string> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedPtrField<string> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING);
   }
@@ -632,6 +632,35 @@
   extension->is_cleared = false;
 }
 
+void ExtensionSet::UnsafeArenaSetAllocatedMessage(
+    int number, FieldType type, const FieldDescriptor* descriptor,
+    MessageLite* message) {
+  if (message == NULL) {
+    ClearExtension(number);
+    return;
+  }
+  Extension* extension;
+  if (MaybeNewExtension(number, descriptor, &extension)) {
+    extension->type = type;
+    GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
+    extension->is_repeated = false;
+    extension->is_lazy = false;
+    extension->message_value = message;
+  } else {
+    GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
+    if (extension->is_lazy) {
+      extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message);
+    } else {
+      if (arena_ == NULL) {
+        delete extension->message_value;
+      }
+      extension->message_value = message;
+    }
+  }
+  extension->is_cleared = false;
+}
+
+
 MessageLite* ExtensionSet::ReleaseMessage(int number,
                                           const MessageLite& prototype) {
   map<int, Extension>::iterator iter = extensions_.find(number);
@@ -712,7 +741,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
     extension->is_repeated = true;
     extension->repeated_message_value =
-        Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+        Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
   }
@@ -866,7 +895,7 @@
       case WireFormatLite::CPPTYPE_##UPPERCASE:                             \
         if (is_new) {                                                       \
           extension->repeated_##LOWERCASE##_value =                         \
-            Arena::Create<REPEATED_TYPE >(arena_, arena_);                  \
+            Arena::CreateMessage<REPEATED_TYPE >(arena_);                   \
         }                                                                   \
         extension->repeated_##LOWERCASE##_value->MergeFrom(                 \
           *other_extension.repeated_##LOWERCASE##_value);                   \
@@ -886,7 +915,7 @@
       case WireFormatLite::CPPTYPE_MESSAGE:
         if (is_new) {
           extension->repeated_message_value =
-              Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+              Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
         }
         // We can't call RepeatedPtrField<MessageLite>::MergeFrom() because
         // it would attempt to allocate new objects.
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index 6d6702b..c371e01 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -194,7 +194,7 @@
   // directly, unless you are doing low-level memory management.
   //
   // When calling any of these accessors, the extension number requested
-  // MUST exist in the DescriptorPool provided to the constructor.  Otheriwse,
+  // MUST exist in the DescriptorPool provided to the constructor.  Otherwise,
   // the method will fail an assert.  Normally, though, you would not call
   // these directly; you would either call the generated accessors of your
   // message class (e.g. GetExtension()) or you would call the accessors
@@ -262,6 +262,9 @@
   void SetAllocatedMessage(int number, FieldType type,
                            const FieldDescriptor* descriptor,
                            MessageLite* message);
+  void UnsafeArenaSetAllocatedMessage(int number, FieldType type,
+                                      const FieldDescriptor* descriptor,
+                                      MessageLite* message);
   MessageLite* ReleaseMessage(int number, const MessageLite& prototype);
   MessageLite* UnsafeArenaReleaseMessage(
       int number, const MessageLite& prototype);
@@ -432,6 +435,7 @@
         const MessageLite& prototype) const = 0;
     virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0;
     virtual void SetAllocatedMessage(MessageLite *message) = 0;
+    virtual void UnsafeArenaSetAllocatedMessage(MessageLite *message) = 0;
     virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0;
     virtual MessageLite* UnsafeArenaReleaseMessage(
         const MessageLite& prototype) = 0;
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 796e7a5..330bd82 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -221,7 +221,7 @@
     GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
     extension->is_repeated = true;
     extension->repeated_message_value =
-        ::google::protobuf::Arena::Create<RepeatedPtrField<MessageLite> >(arena_, arena_);
+        ::google::protobuf::Arena::CreateMessage<RepeatedPtrField<MessageLite> >(arena_);
   } else {
     GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
   }
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index b00461d..68314fd 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -114,7 +114,7 @@
 #endif  // !_MSC_VER
 
 FieldMask::FieldMask()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FieldMask)
 }
@@ -277,9 +277,9 @@
 
 void FieldMask::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FieldMask* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FieldMask*>(
-      &from);
+  const FieldMask* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FieldMask>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -331,10 +331,10 @@
 // FieldMask
 
 // repeated string paths = 1;
- int FieldMask::paths_size() const {
+int FieldMask::paths_size() const {
   return paths_.size();
 }
- void FieldMask::clear_paths() {
+void FieldMask::clear_paths() {
   paths_.Clear();
 }
  const ::std::string& FieldMask::paths(int index) const {
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 4dddf6c..dc8abb9 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -40,6 +40,7 @@
 
 #include <string>
 #include <vector>
+#include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/common.h>
 // TODO(jasonh): Remove this once the compiler change to directly include this
 // is released to components.
@@ -597,6 +598,42 @@
 #endif
 }
 
+// Tries to downcast this message to a generated message type.
+// Returns NULL if this class is not an instance of T.
+//
+// This is like dynamic_cast_if_available, except it works even when
+// dynamic_cast is not available by using Reflection.  However it only works
+// with Message objects.
+//
+// TODO(haberman): can we remove dynamic_cast_if_available in favor of this?
+template <typename T>
+T* DynamicCastToGenerated(const Message* from) {
+  // Compile-time assert that T is a generated type that has a
+  // default_instance() accessor, but avoid actually calling it.
+  const T&(*get_default_instance)() = &T::default_instance;
+  (void)get_default_instance;
+
+  // Compile-time assert that T is a subclass of google::protobuf::Message.
+  const Message* unused = static_cast<T*>(NULL);
+  (void)unused;
+
+#if defined(GOOGLE_PROTOBUF_NO_RTTI) || \
+  (defined(_MSC_VER) && !defined(_CPPRTTI))
+  bool ok = &T::default_instance() ==
+            from->GetReflection()->GetMessageFactory()->GetPrototype(
+                from->GetDescriptor());
+  return ok ? down_cast<T*>(from) : NULL;
+#else
+  return dynamic_cast<T*>(from);
+#endif
+}
+
+template <typename T>
+T* DynamicCastToGenerated(Message* from) {
+  const Message* message_const = from;
+  return const_cast<T*>(DynamicCastToGenerated<const T>(message_const));
+}
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 678f92a..6357e27 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -47,6 +47,10 @@
 namespace google {
 
 namespace protobuf {
+
+class Arena;
+namespace io { class CodedInputStream; }
+
 namespace internal {
 
 
@@ -106,6 +110,15 @@
   return true;
 }
 
+class ArenaString;
+
+// Read a length (varint32), followed by a string, from *input.  Return a
+// pointer to a copy of the string that resides in *arena.  Requires both
+// args to be non-NULL.  If something goes wrong while reading the data
+// then NULL is returned (e.g., input does not start with a valid varint).
+ArenaString* ReadArenaString(::google::protobuf::io::CodedInputStream* input,
+                             ::google::protobuf::Arena* arena);
+
 }  // namespace internal
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 93e1a22..3b8650d 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -156,6 +156,11 @@
   return std::make_pair(PushLimit(byte_limit), --recursion_budget_);
 }
 
+CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() {
+  uint32 length;
+  return PushLimit(ReadVarint32(&length) ? length : 0);
+}
+
 bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) {
   bool result = ConsumedEntireMessage();
   PopLimit(limit);
@@ -164,6 +169,12 @@
   return result;
 }
 
+bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) {
+  bool result = ConsumedEntireMessage();
+  PopLimit(limit);
+  return result;
+}
+
 int CodedInputStream::BytesUntilLimit() const {
   if (current_limit_ == INT_MAX) return -1;
   int current_position = CurrentPosition();
@@ -245,20 +256,7 @@
 }
 
 bool CodedInputStream::ReadRaw(void* buffer, int size) {
-  int current_buffer_size;
-  while ((current_buffer_size = BufferSize()) < size) {
-    // Reading past end of buffer.  Copy what we have, then refresh.
-    memcpy(buffer, buffer_, current_buffer_size);
-    buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
-    size -= current_buffer_size;
-    Advance(current_buffer_size);
-    if (!Refresh()) return false;
-  }
-
-  memcpy(buffer, buffer_, size);
-  Advance(size);
-
-  return true;
+  return InternalReadRawInline(buffer, size);
 }
 
 bool CodedInputStream::ReadString(string* buffer, int size) {
@@ -336,17 +334,23 @@
 
 namespace {
 
-inline const uint8* ReadVarint32FromArray(
-    const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
-inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
+// Read a varint from the given buffer, write it to *value, and return a pair.
+// The first part of the pair is true iff the read was successful.  The second
+// part is buffer + (number of bytes read).  This function is always inlined,
+// so returning a pair is costless.
+inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
+    uint32 first_byte, const uint8* buffer,
+    uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+inline ::std::pair<bool, const uint8*> ReadVarint32FromArray(
+    uint32 first_byte, const uint8* buffer, uint32* value) {
   // Fast path:  We have enough bytes left in the buffer to guarantee that
   // this read won't cross the end, so we can skip the checks.
+  GOOGLE_DCHECK_EQ(*buffer, first_byte);
+  GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte;
   const uint8* ptr = buffer;
   uint32 b;
-  uint32 result;
-
-  b = *(ptr++); result  = b      ; if (!(b & 0x80)) goto done;
-  result -= 0x80;
+  uint32 result = first_byte - 0x80;
+  ++ptr;  // We just processed the first byte.  Move on to the second.
   b = *(ptr++); result += b <<  7; if (!(b & 0x80)) goto done;
   result -= 0x80 << 7;
   b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done;
@@ -364,38 +368,42 @@
 
   // We have overrun the maximum size of a varint (10 bytes).  Assume
   // the data is corrupt.
-  return NULL;
+  return std::make_pair(false, ptr);
 
  done:
   *value = result;
-  return ptr;
+  return std::make_pair(true, ptr);
 }
 
 }  // namespace
 
 bool CodedInputStream::ReadVarint32Slow(uint32* value) {
-  uint64 result;
   // Directly invoke ReadVarint64Fallback, since we already tried to optimize
   // for one-byte varints.
-  if (!ReadVarint64Fallback(&result)) return false;
-  *value = (uint32)result;
-  return true;
+  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  *value = static_cast<uint32>(p.first);
+  return p.second;
 }
 
-bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
+int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
-    const uint8* end = ReadVarint32FromArray(buffer_, value);
-    if (end == NULL) return false;
-    buffer_ = end;
-    return true;
+    GOOGLE_DCHECK_NE(first_byte_or_zero, 0)
+        << "Caller should provide us with *buffer_ when buffer is non-empty";
+    uint32 temp;
+    ::std::pair<bool, const uint8*> p =
+          ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp);
+    if (!p.first) return -1;
+    buffer_ = p.second;
+    return temp;
   } else {
     // Really slow case: we will incur the cost of an extra function call here,
     // but moving this out of line reduces the size of this function, which
     // improves the common case. In micro benchmarks, this is worth about 10-15%
-    return ReadVarint32Slow(value);
+    uint32 temp;
+    return ReadVarint32Slow(&temp) ? static_cast<int64>(temp) : -1;
   }
 }
 
@@ -425,18 +433,24 @@
   return static_cast<uint32>(result);
 }
 
-uint32 CodedInputStream::ReadTagFallback() {
+uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) {
   const int buf_size = BufferSize();
   if (buf_size >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buf_size > 0 && !(buffer_end_[-1] & 0x80))) {
-    uint32 tag;
-    const uint8* end = ReadVarint32FromArray(buffer_, &tag);
-    if (end == NULL) {
+    GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]);
+    if (first_byte_or_zero == 0) {
+      ++buffer_;
       return 0;
     }
-    buffer_ = end;
+    uint32 tag;
+    ::std::pair<bool, const uint8*> p =
+        ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag);
+    if (!p.first) {
+      return 0;
+    }
+    buffer_ = p.second;
     return tag;
   } else {
     // We are commonly at a limit when attempting to read tags. Try to quickly
@@ -479,7 +493,7 @@
   return true;
 }
 
-bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
+std::pair<uint64, bool> CodedInputStream::ReadVarint64Fallback() {
   if (BufferSize() >= kMaxVarintBytes ||
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
@@ -517,16 +531,18 @@
 
     // We have overrun the maximum size of a varint (10 bytes).  The data
     // must be corrupt.
-    return false;
+    return std::make_pair(0, false);
 
    done:
     Advance(ptr - buffer_);
-    *value = (static_cast<uint64>(part0)      ) |
-             (static_cast<uint64>(part1) << 28) |
-             (static_cast<uint64>(part2) << 56);
-    return true;
+    return std::make_pair((static_cast<uint64>(part0)) |
+                              (static_cast<uint64>(part1) << 28) |
+                              (static_cast<uint64>(part2) << 56),
+                          true);
   } else {
-    return ReadVarint64Slow(value);
+    uint64 temp;
+    bool success = ReadVarint64Slow(&temp);
+    return std::make_pair(temp, success);
   }
 }
 
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index dea4b65..961c1a3 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -197,6 +197,11 @@
   // Read raw bytes, copying them into the given buffer.
   bool ReadRaw(void* buffer, int size);
 
+  // Like the above, with inlined optimizations. This should only be used
+  // by the protobuf implementation.
+  inline bool InternalReadRawInline(void* buffer,
+                                    int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
+
   // Like ReadRaw, but reads into a string.
   //
   // Implementation Note:  ReadString() grows the string gradually as it
@@ -387,9 +392,14 @@
   // under the limit, false if it has gone over.
   bool IncrementRecursionDepth();
 
-  // Decrements the recursion depth.
+  // Decrements the recursion depth if possible.
   void DecrementRecursionDepth();
 
+  // Decrements the recursion depth blindly.  This is faster than
+  // DecrementRecursionDepth().  It should be used only if all previous
+  // increments to recursion depth were successful.
+  void UnsafeDecrementRecursionDepth();
+
   // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_).
   // Using this can reduce code size and complexity in some cases.  The caller
   // is expected to check that the second part of the result is non-negative (to
@@ -398,15 +408,25 @@
   std::pair<CodedInputStream::Limit, int> IncrementRecursionDepthAndPushLimit(
       int byte_limit);
 
+  // Shorthand for PushLimit(ReadVarint32(&length) ? length : 0).
+  Limit ReadLengthAndPushLimit();
+
   // Helper that is equivalent to: {
   //  bool result = ConsumedEntireMessage();
   //  PopLimit(limit);
-  //  DecrementRecursionDepth();
+  //  UnsafeDecrementRecursionDepth();
   //  return result; }
   // Using this can reduce code size and complexity in some cases.
   // Do not use unless the current recursion depth is greater than zero.
   bool DecrementRecursionDepthAndPopLimit(Limit limit);
 
+  // Helper that is equivalent to: {
+  //  bool result = ConsumedEntireMessage();
+  //  PopLimit(limit);
+  //  return result; }
+  // Using this can reduce code size and complexity in some cases.
+  bool CheckEntireMessageConsumedAndPopLimit(Limit limit);
+
   // Extension Registry ----------------------------------------------
   // ADVANCED USAGE:  99.9% of people can ignore this section.
   //
@@ -568,9 +588,13 @@
   // optimization. The Slow method is yet another fallback when the buffer is
   // not large enough. Making the slow path out-of-line speeds up the common
   // case by 10-15%. The slow path is fairly uncommon: it only triggers when a
-  // message crosses multiple buffers.
-  bool ReadVarint32Fallback(uint32* value);
-  bool ReadVarint64Fallback(uint64* value);
+  // message crosses multiple buffers.  Note: ReadVarint32Fallback() and
+  // ReadVarint64Fallback() are called frequently and generally not inlined, so
+  // they have been optimized to avoid "out" parameters.  The former returns -1
+  // if it fails and the uint32 it read otherwise.  The latter has a bool
+  // indicating success or failure as part of its return type.
+  int64 ReadVarint32Fallback(uint32 first_byte_or_zero);
+  std::pair<uint64, bool> ReadVarint64Fallback();
   bool ReadVarint32Slow(uint32* value);
   bool ReadVarint64Slow(uint64* value);
   bool ReadLittleEndian32Fallback(uint32* value);
@@ -578,7 +602,7 @@
   // Fallback/slow methods for reading tags. These do not update last_tag_,
   // but will set legitimate_message_end_ if we are at the end of the input
   // stream.
-  uint32 ReadTagFallback();
+  uint32 ReadTagFallback(uint32 first_byte_or_zero);
   uint32 ReadTagSlow();
   bool ReadStringFallback(string* buffer, int size);
 
@@ -818,13 +842,18 @@
 // methods optimize for that case.
 
 inline bool CodedInputStream::ReadVarint32(uint32* value) {
-  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) {
-    *value = *buffer_;
-    Advance(1);
-    return true;
-  } else {
-    return ReadVarint32Fallback(value);
+  uint32 v = 0;
+  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
   }
+  int64 result = ReadVarint32Fallback(v);
+  *value = static_cast<uint32>(result);
+  return result >= 0;
 }
 
 inline bool CodedInputStream::ReadVarint64(uint64* value) {
@@ -832,9 +861,10 @@
     *value = *buffer_;
     Advance(1);
     return true;
-  } else {
-    return ReadVarint64Fallback(value);
   }
+  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  *value = p.first;
+  return p.second;
 }
 
 // static
@@ -903,14 +933,17 @@
 }
 
 inline uint32 CodedInputStream::ReadTag() {
-  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) {
-    last_tag_ = buffer_[0];
-    Advance(1);
-    return last_tag_;
-  } else {
-    last_tag_ = ReadTagFallback();
-    return last_tag_;
+  uint32 v = 0;
+  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    v = *buffer_;
+    if (v < 0x80) {
+      last_tag_ = v;
+      Advance(1);
+      return v;
+    }
   }
+  last_tag_ = ReadTagFallback(v);
+  return last_tag_;
 }
 
 inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
@@ -918,10 +951,12 @@
   // In performance-sensitive code we can expect cutoff to be a compile-time
   // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
   // compile time.
+  uint32 first_byte_or_zero = 0;
   if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
     // Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
     // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
     // is large enough then is it better to check for the two-byte case first?
+    first_byte_or_zero = buffer_[0];
     if (static_cast<int8>(buffer_[0]) > 0) {
       const uint32 kMax1ByteVarint = 0x7f;
       uint32 tag = last_tag_ = buffer_[0];
@@ -948,7 +983,7 @@
     }
   }
   // Slow path
-  last_tag_ = ReadTagFallback();
+  last_tag_ = ReadTagFallback(first_byte_or_zero);
   return std::make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
 }
 
@@ -1177,6 +1212,11 @@
   if (recursion_budget_ < recursion_limit_) ++recursion_budget_;
 }
 
+inline void CodedInputStream::UnsafeDecrementRecursionDepth() {
+  assert(recursion_budget_ < recursion_limit_);
+  ++recursion_budget_;
+}
+
 inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
                                                    MessageFactory* factory) {
   extension_pool_ = pool;
diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h
index cd8d174..fa20f20 100644
--- a/src/google/protobuf/io/coded_stream_inl.h
+++ b/src/google/protobuf/io/coded_stream_inl.h
@@ -66,6 +66,23 @@
   return ReadStringFallback(buffer, size);
 }
 
+inline bool CodedInputStream::InternalReadRawInline(void* buffer, int size) {
+  int current_buffer_size;
+  while ((current_buffer_size = BufferSize()) < size) {
+    // Reading past end of buffer.  Copy what we have, then refresh.
+    memcpy(buffer, buffer_, current_buffer_size);
+    buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
+    size -= current_buffer_size;
+    Advance(current_buffer_size);
+    if (!Refresh()) return false;
+  }
+
+  memcpy(buffer, buffer_, size);
+  Advance(size);
+
+  return true;
+}
+
 }  // namespace io
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc
index e621ba1..3ae8c26 100644
--- a/src/google/protobuf/io/printer.cc
+++ b/src/google/protobuf/io/printer.cc
@@ -155,6 +155,78 @@
   Print(vars, text);
 }
 
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6,
+                    const char* variable7, const string& value7) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  vars[variable7] = value7;
+  Print(vars, text);
+}
+
+void Printer::Print(const char* text,
+                    const char* variable1, const string& value1,
+                    const char* variable2, const string& value2,
+                    const char* variable3, const string& value3,
+                    const char* variable4, const string& value4,
+                    const char* variable5, const string& value5,
+                    const char* variable6, const string& value6,
+                    const char* variable7, const string& value7,
+                    const char* variable8, const string& value8) {
+  map<string, string> vars;
+  vars[variable1] = value1;
+  vars[variable2] = value2;
+  vars[variable3] = value3;
+  vars[variable4] = value4;
+  vars[variable5] = value5;
+  vars[variable6] = value6;
+  vars[variable7] = value7;
+  vars[variable8] = value8;
+  Print(vars, text);
+}
+
 void Printer::Indent() {
   indent_ += "  ";
 }
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 92ce340..f1490bb 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -91,8 +91,36 @@
                                const char* variable2, const string& value2,
                                const char* variable3, const string& value3,
                                const char* variable4, const string& value4);
-  // TODO(kenton):  Overloaded versions with more variables?  Three seems
-  //   to be enough.
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6,
+                               const char* variable7, const string& value7);
+  // Like the first Print(), except the substitutions are given as parameters.
+  void Print(const char* text, const char* variable1, const string& value1,
+                               const char* variable2, const string& value2,
+                               const char* variable3, const string& value3,
+                               const char* variable4, const string& value4,
+                               const char* variable5, const string& value5,
+                               const char* variable6, const string& value6,
+                               const char* variable7, const string& value7,
+                               const char* variable8, const string& value8);
 
   // Indent text by two spaces.  After calling Indent(), two spaces will be
   // inserted at the beginning of each line of text.  Indent() may be called
diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc
index 4ea2100..1995cf0 100644
--- a/src/google/protobuf/lite_unittest.cc
+++ b/src/google/protobuf/lite_unittest.cc
@@ -34,12 +34,16 @@
 #include <iostream>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/arena_test_util.h>
+#include <google/protobuf/map_lite_unittest.pb.h>
+#include <google/protobuf/map_lite_test_util.h>
 #include <google/protobuf/test_util_lite.h>
 #include <google/protobuf/unittest_lite.pb.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/stubs/strutil.h>
 
 using namespace std;
 
@@ -84,6 +88,12 @@
 
 }  // namespace
 
+#define EXPECT_TRUE GOOGLE_CHECK
+#define ASSERT_TRUE GOOGLE_CHECK
+#define EXPECT_FALSE(COND) GOOGLE_CHECK(!(COND))
+#define EXPECT_EQ GOOGLE_CHECK_EQ
+#define ASSERT_EQ GOOGLE_CHECK_EQ
+
 int main(int argc, char* argv[]) {
   string data, data2, packed_data;
 
@@ -345,6 +355,374 @@
     GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size());
   }
 
+  // Tests for map lite =============================================
+
+  {
+    // Accessors
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    google::protobuf::MapLiteTestUtil::ModifyMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message);
+  }
+
+  {
+    // SetMapFieldsInitialized
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFieldsInitialized(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSetInitialized(message);
+  }
+
+  {
+    // Proto2SetMapFieldsInitialized
+    protobuf_unittest::TestEnumStartWithNonZeroMapLite message;
+    EXPECT_EQ(protobuf_unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE,
+              (*message.mutable_map_field())[0]);
+  }
+
+  {
+    // Clear
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    message.Clear();
+    google::protobuf::MapLiteTestUtil::ExpectClear(message);
+  }
+
+  {
+    // ClearMessageMap
+    protobuf_unittest::TestMessageMapLite message;
+
+    // Creates a TestAllTypes with default value
+    google::protobuf::TestUtilLite::ExpectClear(
+        (*message.mutable_map_int32_message())[0]);
+  }
+
+  {
+    // CopyFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    message2.CopyFrom(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Copying from self should be a no-op.
+    message2.CopyFrom(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyFromMessageMap
+    protobuf_unittest::TestMessageMapLite message1, message2;
+
+    (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+    (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+    message1.CopyFrom(message2);
+
+    // Checks repeated field is overwritten.
+    EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+    EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+  }
+
+  {
+    // SwapWithEmpty
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1);
+    google::protobuf::MapLiteTestUtil::ExpectClear(message2);
+
+    message1.Swap(&message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+    google::protobuf::MapLiteTestUtil::ExpectClear(message1);
+  }
+
+  {
+    // SwapWithSelf
+    protobuf_unittest::TestMapLite message;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+
+    message.Swap(&message);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message);
+  }
+
+  {
+    // SwapWithOther
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message2);
+    google::protobuf::MapLiteTestUtil::ModifyMapFields(&message2);
+
+    message1.Swap(&message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyConstructor
+    protobuf_unittest::TestMapLite message1;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2(message1);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // CopyAssignmentOperator
+    protobuf_unittest::TestMapLite message1;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    protobuf_unittest::TestMapLite message2;
+    message2 = message1;
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+
+    // Make sure that self-assignment does something sane.
+    message2.operator=(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // NonEmptyMergeFrom
+    protobuf_unittest::TestMapLite message1, message2;
+
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+
+    // This field will test merging into an empty spot.
+    (*message2.mutable_map_int32_int32())[1] = 1;
+    message1.mutable_map_int32_int32()->erase(1);
+
+    // This tests overwriting.
+    (*message2.mutable_map_int32_double())[1] = 1;
+    (*message1.mutable_map_int32_double())[1] = 2;
+
+    message1.MergeFrom(message2);
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1);
+  }
+
+  {
+    // MergeFromMessageMap
+    protobuf_unittest::TestMessageMapLite message1, message2;
+
+    (*message1.mutable_map_int32_message())[0].add_repeated_int32(100);
+    (*message2.mutable_map_int32_message())[0].add_repeated_int32(101);
+
+    message1.MergeFrom(message2);
+
+    // Checks repeated field is overwritten.
+    EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size());
+    EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0));
+  }
+
+  {
+    // Test the generated SerializeWithCachedSizesToArray()
+    protobuf_unittest::TestMapLite message1, message2;
+    string data;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    int size = message1.ByteSize();
+    data.resize(size);
+    ::google::protobuf::uint8* start = reinterpret_cast< ::google::protobuf::uint8*>(::google::protobuf::string_as_array(&data));
+    ::google::protobuf::uint8* end = message1.SerializeWithCachedSizesToArray(start);
+    EXPECT_EQ(size, end - start);
+    EXPECT_TRUE(message2.ParseFromString(data));
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+  {
+    // Test the generated SerializeWithCachedSizes()
+    protobuf_unittest::TestMapLite message1, message2;
+    google::protobuf::MapLiteTestUtil::SetMapFields(&message1);
+    int size = message1.ByteSize();
+    string data;
+    data.resize(size);
+    {
+      // Allow the output stream to buffer only one byte at a time.
+      google::protobuf::io::ArrayOutputStream array_stream(
+          ::google::protobuf::string_as_array(&data), size, 1);
+      google::protobuf::io::CodedOutputStream output_stream(&array_stream);
+      message1.SerializeWithCachedSizes(&output_stream);
+      EXPECT_FALSE(output_stream.HadError());
+      EXPECT_EQ(size, output_stream.ByteCount());
+    }
+    EXPECT_TRUE(message2.ParseFromString(data));
+    google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2);
+  }
+
+
+  {
+    // Proto2UnknownEnum
+    protobuf_unittest::TestEnumMapPlusExtraLite from;
+    (*from.mutable_known_map_field())[0] =
+        protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE;
+    (*from.mutable_unknown_map_field())[0] =
+        protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE;
+    string data;
+    from.SerializeToString(&data);
+
+    protobuf_unittest::TestEnumMapLite to;
+    EXPECT_TRUE(to.ParseFromString(data));
+    EXPECT_EQ(0, to.unknown_map_field().size());
+    EXPECT_FALSE(to.mutable_unknown_fields()->empty());
+    EXPECT_EQ(1, to.known_map_field().size());
+    EXPECT_EQ(protobuf_unittest::PROTO2_MAP_ENUM_FOO_LITE,
+              to.known_map_field().at(0));
+
+    data.clear();
+    from.Clear();
+    to.SerializeToString(&data);
+    EXPECT_TRUE(from.ParseFromString(data));
+    EXPECT_EQ(1, from.known_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE,
+              from.known_map_field().at(0));
+    EXPECT_EQ(1, from.unknown_map_field().size());
+    EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE,
+              from.unknown_map_field().at(0));
+  }
+
+  {
+    // StandardWireFormat
+    protobuf_unittest::TestMapLite message;
+    string data = "\x0A\x04\x08\x01\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(1));
+  }
+
+  {
+    // UnorderedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // put value before key in wire format
+    string data = "\x0A\x04\x10\x01\x08\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+
+  {
+    // DuplicatedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two key fields in wire format
+    string data = "\x0A\x06\x08\x01\x08\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(2));
+  }
+
+  {
+    // DuplicatedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Two value fields in wire format
+    string data = "\x0A\x06\x08\x01\x10\x01\x10\x02";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(2, message.map_int32_int32().at(1));
+  }
+
+  {
+    // MissedKeyWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No key field in wire format
+    string data = "\x0A\x02\x10\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(1, message.map_int32_int32().at(0));
+  }
+
+  {
+    // MissedValueWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // No value field in wire format
+    string data = "\x0A\x02\x08\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(0, message.map_int32_int32().at(1));
+  }
+
+  {
+    // UnknownFieldWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // Unknown field in wire format
+    string data = "\x0A\x06\x08\x02\x10\x03\x18\x01";
+
+    EXPECT_TRUE(message.ParseFromString(data));
+    EXPECT_EQ(1, message.map_int32_int32().size());
+    EXPECT_EQ(3, message.map_int32_int32().at(2));
+  }
+
+  {
+    // CorruptedWireFormat
+    protobuf_unittest::TestMapLite message;
+
+    // corrupted data in wire format
+    string data = "\x0A\x06\x08\x02\x11\x03";
+
+    EXPECT_FALSE(message.ParseFromString(data));
+  }
+
+  {
+    // IsInitialized
+    protobuf_unittest::TestRequiredMessageMapLite map_message;
+
+    // Add an uninitialized message.
+    (*map_message.mutable_map_field())[0];
+    EXPECT_FALSE(map_message.IsInitialized());
+
+    // Initialize uninitialized message
+    (*map_message.mutable_map_field())[0].set_a(0);
+    (*map_message.mutable_map_field())[0].set_b(0);
+    (*map_message.mutable_map_field())[0].set_c(0);
+    EXPECT_TRUE(map_message.IsInitialized());
+  }
+
+  // arena support for map  =========================================
+
+  {
+    // ParsingAndSerializingNoHeapAllocation
+
+    // Allocate a large initial block to avoid mallocs during hooked test.
+    std::vector<char> arena_block(128 * 1024);
+    google::protobuf::ArenaOptions options;
+    options.initial_block = arena_block.data();
+    options.initial_block_size = arena_block.size();
+    google::protobuf::Arena arena(options);
+    string data;
+    data.reserve(128 * 1024);
+
+    {
+      google::protobuf::internal::NoHeapChecker no_heap;
+
+      protobuf_unittest::TestArenaMapLite* from =
+          google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(
+              &arena);
+      google::protobuf::MapLiteTestUtil::SetArenaMapFields(from);
+      from->SerializeToString(&data);
+
+      protobuf_unittest::TestArenaMapLite* to =
+          google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(
+              &arena);
+      to->ParseFromString(data);
+      google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to);
+    }
+  }
+
   std::cout << "PASS" << std::endl;
   return 0;
 }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index e56af3f..1858e2f 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -422,6 +422,7 @@
   int default_enum_value_;
 
   friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
   template <typename K, typename V,
             internal::WireFormatLite::FieldType key_wire_type,
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 304fba8..2d11bea 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -267,17 +267,18 @@
   // google::protobuf::Map is enum. We cannot create a reference to int from an enum.
   static MapEntryLite* EnumWrap(const Key& key, const Value value,
                                 Arena* arena) {
-    return Arena::Create<MapEnumEntryWrapper<
+    return Arena::CreateMessage<MapEnumEntryWrapper<
         Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >(
-        arena, key, value, arena);
+        arena, key, value);
   }
 
   // Like above, but for all the other types. This avoids value copy to create
   // MapEntryLite from google::protobuf::Map in serialization.
   static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) {
-    return Arena::Create<MapEntryWrapper<Key, Value, kKeyFieldType,
-                                         kValueFieldType, default_enum_value> >(
-        arena, key, value, arena);
+    return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType,
+                                                kValueFieldType,
+                                                default_enum_value> >(
+        arena, key, value);
   }
 
  protected:
@@ -308,7 +309,7 @@
     typedef typename Base::ValCppType ValCppType;
 
    public:
-    MapEntryWrapper(const K& key, const V& value, Arena* arena)
+    MapEntryWrapper(Arena* arena, const K& key, const V& value)
         : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
           key_(key),
           value_(value) {
@@ -323,6 +324,7 @@
     const Value& value_;
 
     friend class ::google::protobuf::Arena;
+    typedef void InternalArenaConstructable_;
     typedef void DestructorSkippable_;
   };
 
@@ -341,7 +343,7 @@
     typedef typename Base::ValCppType ValCppType;
 
    public:
-    MapEnumEntryWrapper(const K& key, const V& value, Arena* arena)
+    MapEnumEntryWrapper(Arena* arena, const K& key, const V& value)
         : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
           key_(key),
           value_(value) {
@@ -355,7 +357,7 @@
     const KeyCppType& key_;
     const ValCppType value_;
 
-    friend class ::google::protobuf::Arena;
+    friend class LIBPROTOBUF_EXPORT google::protobuf::Arena;
     typedef void DestructorSkippable_;
   };
 
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc
index fd40c0d..6ff1936 100644
--- a/src/google/protobuf/map_field.cc
+++ b/src/google/protobuf/map_field.cc
@@ -104,14 +104,18 @@
 void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; }
 
 void MapFieldBase::SyncRepeatedFieldWithMap() const {
-  Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+  // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
+  // executed before state_ is checked.
+  Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
   if (state == STATE_MODIFIED_MAP) {
     mutex_.Lock();
     // Double check state, because another thread may have seen the same state
     // and done the synchronization before the current thread.
     if (state_ == STATE_MODIFIED_MAP) {
       SyncRepeatedFieldWithMapNoLock();
-      google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+      // "Release" insures state_ can only be changed "after"
+      // SyncRepeatedFieldWithMapNoLock is finished.
+      google::protobuf::internal::Release_Store(&state_, CLEAN);
     }
     mutex_.Unlock();
   }
@@ -119,19 +123,23 @@
 
 void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const {
   if (repeated_field_ == NULL) {
-    repeated_field_ = Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+    repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
   }
 }
 
 void MapFieldBase::SyncMapWithRepeatedField() const {
-  Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_);
+  // "Acquire" insures the operation after SyncMapWithRepeatedField won't get
+  // executed before state_ is checked.
+  Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
   if (state == STATE_MODIFIED_REPEATED) {
     mutex_.Lock();
     // Double check state, because another thread may have seen the same state
     // and done the synchronization before the current thread.
     if (state_ == STATE_MODIFIED_REPEATED) {
       SyncMapWithRepeatedFieldNoLock();
-      google::protobuf::internal::NoBarrier_Store(&state_, CLEAN);
+      // "Release" insures state_ can only be changed "after"
+      // SyncRepeatedFieldWithMapNoLock is finished.
+      google::protobuf::internal::Release_Store(&state_, CLEAN);
     }
     mutex_.Unlock();
   }
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 6d8b6ec..f3504f1 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -208,6 +208,7 @@
   void SetAssignDescriptorCallback(void (*callback)());
 
  private:
+  typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
 
   // MapField needs MapEntry's default instance to create new MapEntry.
diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h
index ae63c72..cbfc0c8 100644
--- a/src/google/protobuf/map_field_inl.h
+++ b/src/google/protobuf/map_field_inl.h
@@ -216,7 +216,7 @@
       repeated_field_ = new RepeatedPtrField<Message>();
     } else {
       repeated_field_ =
-          Arena::Create<RepeatedPtrField<Message> >(arena_, arena_);
+          Arena::CreateMessage<RepeatedPtrField<Message> >(arena_);
     }
   }
   const Map<Key, T>& map = GetInternalMap();
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index 549ecc0..4032285 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -109,7 +109,7 @@
 MapFieldLite<Key, T, key_wire_type, value_wire_type,
              default_enum_value>::MapFieldLite(Arena* arena)
   : arena_(arena) {
-  map_ = Arena::Create<Map<Key, T> >(arena, arena);
+  map_ = Arena::CreateMessage<Map<Key, T> >(arena);
   SetDefaultEnumValue();
 }
 
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index 61344cb..f468186 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -56,6 +56,7 @@
 
 class MapFieldBaseStub : public MapFieldBase {
  public:
+  typedef void InternalArenaConstructable_;
   typedef void DestructorSkippable_;
   MapFieldBaseStub() {}
   explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
@@ -149,10 +150,12 @@
   Arena arena(options);
 
   {
-    NoHeapChecker no_heap;
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
 
     MapFieldType* map_field =
-        Arena::Create<MapFieldType>(&arena, &arena, default_entry_);
+        Arena::CreateMessage<MapFieldType>(&arena, default_entry_);
 
     // Set content in map
     (*map_field->MutableMap())[100] = 101;
@@ -162,10 +165,12 @@
   }
 
   {
-    NoHeapChecker no_heap;
+    // TODO(liujisi): Re-write the test to ensure the memory for the map and
+    // repeated fields are allocated from arenas.
+    // NoHeapChecker no_heap;
 
     MapFieldBaseStub* map_field =
-        Arena::Create<MapFieldBaseStub>(&arena, &arena);
+        Arena::CreateMessage<MapFieldBaseStub>(&arena);
 
     // Trigger conversion to repeated field.
     EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 88cba1f..447f52d 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -2258,6 +2258,27 @@
   MapTestUtil::ExpectMapFieldsSet(dest);
 }
 
+TEST(TextFormatMapTest, Sorted) {
+  unittest::TestMap message;
+  MapTestUtil::MapReflectionTester tester(message.GetDescriptor());
+  tester.SetMapFieldsViaReflection(&message);
+
+  string expected_text;
+  GOOGLE_CHECK_OK(File::GetContents(
+      TestSourceDir() +
+          "/google/protobuf/"
+          "testdata/map_test_data.txt",
+      &expected_text, true));
+
+  EXPECT_EQ(message.DebugString(), expected_text);
+
+  // Test again on the reverse order.
+  unittest::TestMap message2;
+  tester.SetMapFieldsViaReflection(&message2);
+  tester.SwapMapsViaReflection(&message2);
+  EXPECT_EQ(message2.DebugString(), expected_text);
+}
+
 
 // arena support =================================================
 TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index 278b78a..ffdb6df 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -129,11 +129,11 @@
   // Return bytes used by value in Map.
   static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); }
   static inline void Clear(Type** value) {
-    if (*value != NULL) (*value)->Type::Clear();
+    if (*value != NULL) (*value)->Clear();
   }
   static inline void ClearMaybeByDefaultEnum(Type** value,
                                              int default_enum_value) {
-    if (*value != NULL) (*value)->Type::Clear();
+    if (*value != NULL) (*value)->Clear();
   }
   static inline void Merge(const Type& from, Type** to) {
     (*to)->MergeFrom(from);
diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto
index b6a988b..cbf747d 100644
--- a/src/google/protobuf/map_unittest.proto
+++ b/src/google/protobuf/map_unittest.proto
@@ -62,7 +62,7 @@
 }
 
 message TestMapSubmessage {
-  optional TestMap test_map = 1;
+  TestMap test_map = 1;
 }
 
 message TestMessageMap {
@@ -104,3 +104,17 @@
   map<int32   , MapEnum > map_int32_enum        = 14;
   map<int32   , ForeignMessage> map_int32_foreign_message = 15;
 }
+
+// Previously, message containing enum called Type cannot be used as value of
+// map field.
+message MessageContainingEnumCalledType {
+  enum Type {
+    TYPE_FOO = 0;
+  }
+  map<int32, MessageContainingEnumCalledType> type = 1;
+}
+
+// Previously, message cannot contain map field called "entry".
+message MessageContainingMapCalledEntry {
+  map<int32, int32> entry = 1;
+}
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index f58be84..276d7de 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -465,10 +465,21 @@
 }  // namespace internal
 
 namespace internal {
-// Macro defined in repeated_field.h. We can only define the Message-specific
-// GenericTypeHandler specializations here because we depend on Message, which
-// is not part of proto2-lite hence is not available in repeated_field.h.
-DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(Message);
+template<>
+Message* GenericTypeHandler<Message>::NewFromPrototype(
+    const Message* prototype, google::protobuf::Arena* arena) {
+  return prototype->New(arena);
+}
+template<>
+google::protobuf::Arena* GenericTypeHandler<Message>::GetArena(
+    Message* value) {
+  return value->GetArena();
+}
+template<>
+void* GenericTypeHandler<Message>::GetMaybeArenaPointer(
+    Message* value) {
+  return value->GetMaybeArenaPointer();
+}
 }  // namespace internal
 
 }  // namespace protobuf
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index 6e1929e..18c092d 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -98,11 +98,11 @@
 //
 //     // Use the reflection interface to examine the contents.
 //     const Reflection* reflection = foo->GetReflection();
-//     assert(reflection->GetString(foo, text_field) == "Hello World!");
-//     assert(reflection->FieldSize(foo, numbers_field) == 3);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5);
-//     assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42);
+//     assert(reflection->GetString(*foo, text_field) == "Hello World!");
+//     assert(reflection->FieldSize(*foo, numbers_field) == 3);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 0) == 1);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 1) == 5);
+//     assert(reflection->GetRepeatedInt32(*foo, numbers_field, 2) == 42);
 //
 //     delete foo;
 //   }
@@ -229,6 +229,11 @@
   // Computes (an estimate of) the total number of bytes currently used for
   // storing the message in memory.  The default implementation calls the
   // Reflection object's SpaceUsed() method.
+  //
+  // SpaceUsed() is noticeably slower than ByteSize(), as it is implemented
+  // using reflection (rather than the generated code implementation for
+  // ByteSize()). Like ByteSize(), its CPU time is linear in the number of
+  // fields defined for the proto.
   virtual int SpaceUsed() const;
 
   // Debugging & Testing----------------------------------------------
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 63be0e9..4f63ad2 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -337,7 +337,7 @@
 
 string MessageLite::SerializeAsString() const {
   // If the compiler implements the (Named) Return Value Optimization,
-  // the local variable 'result' will not actually reside on the stack
+  // the local variable 'output' will not actually reside on the stack
   // of this function, but will be overlaid with the object that the
   // caller supplied for the return value to be constructed in.
   string output;
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index eab61c1..4c16f4c 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -238,6 +238,9 @@
   // Computes the serialized size of the message.  This recursively calls
   // ByteSize() on all embedded messages.  If a subclass does not override
   // this, it MUST override SetCachedSize().
+  //
+  // ByteSize() is generally linear in the number of fields defined for the
+  // proto.
   virtual int ByteSize() const = 0;
 
   // Serializes the message without recomputing the size.  The message must
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
index ebfb432..75d60b8 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -45,12 +45,13 @@
 #include <sstream>
 #include <fstream>
 
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
@@ -205,6 +206,28 @@
   EXPECT_EQ("a, b, c", message.InitializationErrorString());
 }
 
+TEST(MessageTest, DynamicCastToGenerated) {
+  unittest::TestAllTypes test_all_types;
+
+  google::protobuf::Message* test_all_types_pointer = &test_all_types;
+  EXPECT_EQ(&test_all_types,
+            google::protobuf::internal::DynamicCastToGenerated<unittest::TestAllTypes>(
+                test_all_types_pointer));
+  EXPECT_EQ(NULL,
+            google::protobuf::internal::DynamicCastToGenerated<unittest::TestRequired>(
+                test_all_types_pointer));
+
+  const google::protobuf::Message* test_all_types_pointer_const = &test_all_types;
+  EXPECT_EQ(
+      &test_all_types,
+      google::protobuf::internal::DynamicCastToGenerated<const unittest::TestAllTypes>(
+          test_all_types_pointer_const));
+  EXPECT_EQ(
+      NULL,
+      google::protobuf::internal::DynamicCastToGenerated<const unittest::TestRequired>(
+          test_all_types_pointer_const));
+}
+
 #ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet.
 
 TEST(MessageTest, SerializeFailsIfNotInitialized) {
diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc
index c3b5996..da4be67 100644
--- a/src/google/protobuf/proto3_arena_unittest.cc
+++ b/src/google/protobuf/proto3_arena_unittest.cc
@@ -180,6 +180,16 @@
   EXPECT_EQ(118, nested->bb());
 }
 
+TEST(ArenaTest, MessageFieldClear) {
+  // GitHub issue #310: https://github.com/google/protobuf/issues/310
+  Arena arena;
+  TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena);
+  arena_message->mutable_optional_nested_message()->set_bb(118);
+  // This should not crash, but prior to the bugfix, it tried to use `operator
+  // delete` the nested message (which is on the arena):
+  arena_message->Clear();
+}
+
 }  // namespace
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h
index 03c761c..4ff0f6b 100755
--- a/src/google/protobuf/reflection.h
+++ b/src/google/protobuf/reflection.h
@@ -39,6 +39,7 @@
 #endif
 
 #include <google/protobuf/message.h>
+#include <google/protobuf/generated_enum_util.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 7bfdc40..5a2fb40 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -576,26 +576,21 @@
   }
 };
 
-// Macros for specializing GenericTypeHandler for base proto types, these are
-// are defined here, to allow inlining them at their callsites.
-#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Inline, TypeName)          \
-    template<> \
-    Inline TypeName* GenericTypeHandler<TypeName>::NewFromPrototype(           \
-        const TypeName* prototype, google::protobuf::Arena* arena) {                     \
-      return prototype->New(arena);                                            \
-    }                                                                          \
-    template<> \
-    Inline google::protobuf::Arena* GenericTypeHandler<TypeName>::GetArena(              \
-        TypeName* value) {                                                     \
-      return value->GetArena();                                                \
-    }                                                                          \
-    template<>                                                                 \
-    Inline void* GenericTypeHandler<TypeName>::GetMaybeArenaPointer(           \
-        TypeName* value) {                                                     \
-      return value->GetMaybeArenaPointer();                                    \
-    }
-#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(TypeName)         \
-    DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(, TypeName)
+template<>
+inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
+    const MessageLite* prototype, google::protobuf::Arena* arena) {
+  return prototype->New(arena);
+}
+template<>
+inline google::protobuf::Arena* GenericTypeHandler<MessageLite>::GetArena(
+    MessageLite* value) {
+  return value->GetArena();
+}
+template<>
+inline void* GenericTypeHandler<MessageLite>::GetMaybeArenaPointer(
+    MessageLite* value) {
+  return value->GetMaybeArenaPointer();
+}
 
 // Implements GenericTypeHandler specialization required by RepeatedPtrFields
 // to work with MessageLite type.
@@ -605,8 +600,6 @@
   to->CheckTypeAndMergeFrom(from);
 }
 
-DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(inline, MessageLite);
-
 // Declarations of the specialization as we cannot define them here, as the
 // header that defines ProtocolMessage depends on types defined in this header.
 #define DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(TypeName)                 \
@@ -1235,6 +1228,7 @@
                 kRepHeaderSize + sizeof(Element)*new_size));
   }
   rep_->arena = arena;
+  int old_total_size = total_size_;
   total_size_ = new_size;
   // Invoke placement-new on newly allocated elements. We shouldn't have to do
   // this, since Element is supposed to be POD, but a previous version of this
@@ -1253,15 +1247,17 @@
   if (current_size_ > 0) {
     MoveArray(rep_->elements, old_rep->elements, current_size_);
   }
-  // Likewise, we need to invoke destructors on the old array. If Element has no
-  // destructor, this loop will disappear.
-  e = &old_rep->elements[0];
-  limit = &old_rep->elements[current_size_];
-  for (; e < limit; e++) {
-    e->Element::~Element();
-  }
-  if (arena == NULL) {
-    delete[] reinterpret_cast<char*>(old_rep);
+  if (old_rep) {
+    // Likewise, we need to invoke destructors on the old array. If Element has
+    // no destructor, this loop will disappear.
+    e = &old_rep->elements[0];
+    limit = &old_rep->elements[old_total_size];
+    for (; e < limit; e++) {
+      e->Element::~Element();
+    }
+    if (arena == NULL) {
+      delete[] reinterpret_cast<char*>(old_rep);
+    }
   }
 }
 
@@ -1418,7 +1414,7 @@
   const int n = current_size_;
   GOOGLE_DCHECK_GE(n, 0);
   if (n > 0) {
-    void* const* elements = raw_data();
+    void* const* elements = rep_->elements;
     int i = 0;
     do {
       TypeHandler::Clear(cast<TypeHandler>(elements[i++]));
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 66e7452..af39793 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -456,6 +456,28 @@
   }
 }
 
+TEST(RepeatedField, ClearThenReserveMore) {
+  // Test that Reserve properly destroys the old internal array when it's forced
+  // to allocate a new one, even when cleared-but-not-deleted objects are
+  // present. Use a 'string' and > 16 bytes length so that the elements are
+  // non-POD and allocate -- the leak checker will catch any skipped destructor
+  // calls here.
+  RepeatedField<string> field;
+  for (int i = 0; i < 32; i++) {
+    field.Add(string("abcdefghijklmnopqrstuvwxyz0123456789"));
+  }
+  EXPECT_EQ(32, field.size());
+  field.Clear();
+  EXPECT_EQ(0, field.size());
+  EXPECT_EQ(32, field.Capacity());
+
+  field.Reserve(1024);
+  EXPECT_EQ(0, field.size());
+  EXPECT_EQ(1024, field.Capacity());
+  // Finish test -- |field| should destroy the cleared-but-not-yet-destroyed
+  // strings.
+}
+
 // ===================================================================
 // RepeatedPtrField tests.  These pretty much just mirror the RepeatedField
 // tests above.
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index 0926e74..3b3799a 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -114,7 +114,7 @@
 #endif  // !_MSC_VER
 
 SourceContext::SourceContext()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.SourceContext)
 }
@@ -277,9 +277,9 @@
 
 void SourceContext::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const SourceContext* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const SourceContext*>(
-      &from);
+  const SourceContext* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const SourceContext>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -334,7 +334,7 @@
 // SourceContext
 
 // optional string file_name = 1;
- void SourceContext::clear_file_name() {
+void SourceContext::clear_file_name() {
   file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& SourceContext::file_name() const {
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 4405a5b..30113cd 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -217,7 +217,7 @@
 #endif  // !_MSC_VER
 
 Struct::Struct()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Struct)
 }
@@ -295,7 +295,8 @@
       // map<string, .google.protobuf.Value> fields = 1;
       case 1: {
         if (tag == 10) {
-         parse_fields:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_fields:
           ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry(fields_.NewEntry());
           DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
               input, entry.get()));
@@ -303,7 +304,8 @@
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_fields;
+        if (input->ExpectTag(10)) goto parse_loop_fields;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -336,7 +338,8 @@
   {
     ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
     for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = fields().begin(); it != fields().end(); ++it) {
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
       entry.reset(fields_.NewEntryWrapper(it->first, it->second));
       ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
           1, *entry, output);
@@ -353,7 +356,8 @@
   {
     ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
     for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = fields().begin(); it != fields().end(); ++it) {
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
       entry.reset(fields_.NewEntryWrapper(it->first, it->second));
       target = ::google::protobuf::internal::WireFormatLite::
           WriteMessageNoVirtualToArray(
@@ -373,7 +377,8 @@
   {
     ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry;
     for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator
-        it = fields().begin(); it != fields().end(); ++it) {
+        it = this->fields().begin();
+        it != this->fields().end(); ++it) {
       entry.reset(fields_.NewEntryWrapper(it->first, it->second));
       total_size += ::google::protobuf::internal::WireFormatLite::
           MessageSizeNoVirtual(*entry);
@@ -388,9 +393,9 @@
 
 void Struct::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Struct* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Struct*>(
-      &from);
+  const Struct* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Struct>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -442,10 +447,10 @@
 // Struct
 
 // map<string, .google.protobuf.Value> fields = 1;
- int Struct::fields_size() const {
+int Struct::fields_size() const {
   return fields_.size();
 }
- void Struct::clear_fields() {
+void Struct::clear_fields() {
   fields_.Clear();
 }
  const ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >&
@@ -473,7 +478,7 @@
 #endif  // !_MSC_VER
 
 Value::Value()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Value)
 }
@@ -845,9 +850,9 @@
 
 void Value::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Value* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Value*>(
-      &from);
+  const Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Value>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -928,13 +933,13 @@
 // Value
 
 // optional .google.protobuf.NullValue null_value = 1;
- bool Value::has_null_value() const {
+bool Value::has_null_value() const {
   return kind_case() == kNullValue;
 }
- void Value::set_has_null_value() {
+void Value::set_has_null_value() {
   _oneof_case_[0] = kNullValue;
 }
- void Value::clear_null_value() {
+void Value::clear_null_value() {
   if (has_null_value()) {
     kind_.null_value_ = 0;
     clear_has_kind();
@@ -957,13 +962,13 @@
 }
 
 // optional double number_value = 2;
- bool Value::has_number_value() const {
+bool Value::has_number_value() const {
   return kind_case() == kNumberValue;
 }
- void Value::set_has_number_value() {
+void Value::set_has_number_value() {
   _oneof_case_[0] = kNumberValue;
 }
- void Value::clear_number_value() {
+void Value::clear_number_value() {
   if (has_number_value()) {
     kind_.number_value_ = 0;
     clear_has_kind();
@@ -986,13 +991,13 @@
 }
 
 // optional string string_value = 3;
- bool Value::has_string_value() const {
+bool Value::has_string_value() const {
   return kind_case() == kStringValue;
 }
- void Value::set_has_string_value() {
+void Value::set_has_string_value() {
   _oneof_case_[0] = kStringValue;
 }
- void Value::clear_string_value() {
+void Value::clear_string_value() {
   if (has_string_value()) {
     kind_.string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
     clear_has_kind();
@@ -1066,13 +1071,13 @@
 }
 
 // optional bool bool_value = 4;
- bool Value::has_bool_value() const {
+bool Value::has_bool_value() const {
   return kind_case() == kBoolValue;
 }
- void Value::set_has_bool_value() {
+void Value::set_has_bool_value() {
   _oneof_case_[0] = kBoolValue;
 }
- void Value::clear_bool_value() {
+void Value::clear_bool_value() {
   if (has_bool_value()) {
     kind_.bool_value_ = false;
     clear_has_kind();
@@ -1095,13 +1100,13 @@
 }
 
 // optional .google.protobuf.Struct struct_value = 5;
- bool Value::has_struct_value() const {
+bool Value::has_struct_value() const {
   return kind_case() == kStructValue;
 }
- void Value::set_has_struct_value() {
+void Value::set_has_struct_value() {
   _oneof_case_[0] = kStructValue;
 }
- void Value::clear_struct_value() {
+void Value::clear_struct_value() {
   if (has_struct_value()) {
     delete kind_.struct_value_;
     clear_has_kind();
@@ -1141,13 +1146,13 @@
 }
 
 // optional .google.protobuf.ListValue list_value = 6;
- bool Value::has_list_value() const {
+bool Value::has_list_value() const {
   return kind_case() == kListValue;
 }
- void Value::set_has_list_value() {
+void Value::set_has_list_value() {
   _oneof_case_[0] = kListValue;
 }
- void Value::clear_list_value() {
+void Value::clear_list_value() {
   if (has_list_value()) {
     delete kind_.list_value_;
     clear_has_kind();
@@ -1186,10 +1191,10 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value)
 }
 
- bool Value::has_kind() const {
+bool Value::has_kind() const {
   return kind_case() != KIND_NOT_SET;
 }
- void Value::clear_has_kind() {
+void Value::clear_has_kind() {
   _oneof_case_[0] = KIND_NOT_SET;
 }
 Value::KindCase Value::kind_case() const {
@@ -1204,7 +1209,7 @@
 #endif  // !_MSC_VER
 
 ListValue::ListValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.ListValue)
 }
@@ -1278,13 +1283,15 @@
       // repeated .google.protobuf.Value values = 1;
       case 1: {
         if (tag == 10) {
-         parse_values:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_values:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_values()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(10)) goto parse_values;
+        if (input->ExpectTag(10)) goto parse_loop_values;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1355,9 +1362,9 @@
 
 void ListValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const ListValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const ListValue*>(
-      &from);
+  const ListValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const ListValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1409,10 +1416,10 @@
 // ListValue
 
 // repeated .google.protobuf.Value values = 1;
- int ListValue::values_size() const {
+int ListValue::values_size() const {
   return values_.size();
 }
- void ListValue::clear_values() {
+void ListValue::clear_values() {
   values_.Clear();
 }
  const ::google::protobuf::Value& ListValue::values(int index) const {
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 4648214..2889c8f 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -735,6 +735,10 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 37123c7..3acaeba 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -1141,6 +1141,14 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex);
 };
 
+// Undefine the macros  to workaround the conflicts with Google internal
+// MutexLock implementation.
+// TODO(liujisi): Remove the undef once internal macros are removed.
+#undef MutexLock
+#undef ReaderMutexLock
+#undef WriterMutexLock
+#undef MutexLockMaybe
+
 // MutexLock(mu) acquires mu when constructed and releases it when destroyed.
 class LIBPROTOBUF_EXPORT MutexLock {
  public:
diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc
index 7955d26..7ecc17e 100644
--- a/src/google/protobuf/stubs/strutil.cc
+++ b/src/google/protobuf/stubs/strutil.cc
@@ -1285,24 +1285,6 @@
   return buffer;
 }
 
-string ToHex(uint64 num) {
-  if (num == 0) {
-    return string("0");
-  }
-
-  // Compute hex bytes in reverse order, writing to the back of the
-  // buffer.
-  char buf[16];  // No more than 16 hex digits needed.
-  char* bufptr = buf + 16;
-  static const char kHexChars[] = "0123456789abcdef";
-  while (num != 0) {
-    *--bufptr = kHexChars[num & 0xf];
-    num >>= 4;
-  }
-
-  return string(bufptr, buf + 16 - bufptr);
-}
-
 namespace strings {
 
 AlphaNum::AlphaNum(strings::Hex hex) {
diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h
index 920701e..5faa81e 100644
--- a/src/google/protobuf/stubs/strutil.h
+++ b/src/google/protobuf/stubs/strutil.h
@@ -683,12 +683,6 @@
 }
 
 // ----------------------------------------------------------------------
-// ToHex()
-//    Return a lower-case hex string representation of the given integer.
-// ----------------------------------------------------------------------
-LIBPROTOBUF_EXPORT string ToHex(uint64 num);
-
-// ----------------------------------------------------------------------
 // GlobalReplaceSubstring()
 //    Replaces all instances of a substring in a string.  Does nothing
 //    if 'substring' is empty.  Returns the number of replacements.
diff --git a/src/google/protobuf/testdata/golden_message_proto3 b/src/google/protobuf/testdata/golden_message_proto3
index 934f36f..bd646a0 100644
--- a/src/google/protobuf/testdata/golden_message_proto3
+++ b/src/google/protobuf/testdata/golden_message_proto3
Binary files differ
diff --git a/src/google/protobuf/testdata/map_test_data.txt b/src/google/protobuf/testdata/map_test_data.txt
new file mode 100644
index 0000000..bc27232
--- /dev/null
+++ b/src/google/protobuf/testdata/map_test_data.txt
@@ -0,0 +1,140 @@
+map_int32_int32 {
+  key: 0
+  value: 0
+}
+map_int32_int32 {
+  key: 1
+  value: 1
+}
+map_int64_int64 {
+  key: 0
+  value: 0
+}
+map_int64_int64 {
+  key: 1
+  value: 1
+}
+map_uint32_uint32 {
+  key: 0
+  value: 0
+}
+map_uint32_uint32 {
+  key: 1
+  value: 1
+}
+map_uint64_uint64 {
+  key: 0
+  value: 0
+}
+map_uint64_uint64 {
+  key: 1
+  value: 1
+}
+map_sint32_sint32 {
+  key: 0
+  value: 0
+}
+map_sint32_sint32 {
+  key: 1
+  value: 1
+}
+map_sint64_sint64 {
+  key: 0
+  value: 0
+}
+map_sint64_sint64 {
+  key: 1
+  value: 1
+}
+map_fixed32_fixed32 {
+  key: 0
+  value: 0
+}
+map_fixed32_fixed32 {
+  key: 1
+  value: 1
+}
+map_fixed64_fixed64 {
+  key: 0
+  value: 0
+}
+map_fixed64_fixed64 {
+  key: 1
+  value: 1
+}
+map_sfixed32_sfixed32 {
+  key: 0
+  value: 0
+}
+map_sfixed32_sfixed32 {
+  key: 1
+  value: 1
+}
+map_sfixed64_sfixed64 {
+  key: 0
+  value: 0
+}
+map_sfixed64_sfixed64 {
+  key: 1
+  value: 1
+}
+map_int32_float {
+  key: 0
+  value: 0
+}
+map_int32_float {
+  key: 1
+  value: 1
+}
+map_int32_double {
+  key: 0
+  value: 0
+}
+map_int32_double {
+  key: 1
+  value: 1
+}
+map_bool_bool {
+  key: false
+  value: false
+}
+map_bool_bool {
+  key: true
+  value: true
+}
+map_string_string {
+  key: "0"
+  value: "0"
+}
+map_string_string {
+  key: "1"
+  value: "1"
+}
+map_int32_bytes {
+  key: 0
+  value: "0"
+}
+map_int32_bytes {
+  key: 1
+  value: "1"
+}
+map_int32_enum {
+  key: 0
+  value: MAP_ENUM_BAR
+}
+map_int32_enum {
+  key: 1
+  value: MAP_ENUM_BAZ
+}
+map_int32_foreign_message {
+  key: 0
+  value {
+    c: 0
+  }
+}
+map_int32_foreign_message {
+  key: 1
+  value {
+    c: 1
+  }
+}
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index ec070c5..61dfa5d 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -43,6 +43,8 @@
 #include <google/protobuf/text_format.h>
 
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -50,6 +52,7 @@
 #include <google/protobuf/unknown_field_set.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/any.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/map_util.h>
@@ -70,6 +73,18 @@
           (str[1] >= '0' && str[1] < '8'));
 }
 
+inline bool GetAnyFieldDescriptors(const Message& message,
+                                   const FieldDescriptor** type_url_field,
+                                   const FieldDescriptor** value_field) {
+    const Descriptor* descriptor = message.GetDescriptor();
+    *type_url_field = descriptor->FindFieldByNumber(1);
+    *value_field = descriptor->FindFieldByNumber(2);
+    return (*type_url_field != NULL &&
+            (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
+            *value_field != NULL &&
+            (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
+}
+
 }  // namespace
 
 string Message::DebugString() const {
@@ -330,7 +345,17 @@
 
     // Confirm that we have a valid ending delimiter.
     DO(Consume(delimiter));
+    return true;
+  }
 
+  // Consume either "<" or "{".
+  bool ConsumeMessageDelimiter(string* delimiter) {
+    if (TryConsume("<")) {
+      *delimiter = ">";
+    } else {
+      DO(Consume("{"));
+      *delimiter = "}";
+    }
     return true;
   }
 
@@ -347,15 +372,28 @@
     int start_line = tokenizer_.current().line;
     int start_column = tokenizer_.current().column;
 
+    const FieldDescriptor* any_type_url_field;
+    const FieldDescriptor* any_value_field;
+    if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field,
+                                         &any_value_field) &&
+        TryConsume("[")) {
+      string full_type_name;
+      DO(ConsumeAnyTypeUrl(&full_type_name));
+      DO(Consume("]"));
+      string serialized_value;
+      DO(ConsumeAnyValue(full_type_name,
+                         message->GetDescriptor()->file()->pool(),
+                         &serialized_value));
+      reflection->SetString(
+          message, any_type_url_field,
+          string(internal::kTypeGoogleApisComPrefix) + full_type_name);
+      reflection->SetString(message, any_value_field, serialized_value);
+      return true;
+      // Fall through.
+    }
     if (TryConsume("[")) {
       // Extension.
-      DO(ConsumeIdentifier(&field_name));
-      while (TryConsume(".")) {
-        string part;
-        DO(ConsumeIdentifier(&part));
-        field_name += ".";
-        field_name += part;
-      }
+      DO(ConsumeFullTypeName(&field_name));
       DO(Consume("]"));
 
       field = (finder_ != NULL
@@ -512,13 +550,7 @@
     string field_name;
     if (TryConsume("[")) {
       // Extension name.
-      DO(ConsumeIdentifier(&field_name));
-      while (TryConsume(".")) {
-        string part;
-        DO(ConsumeIdentifier(&part));
-        field_name += ".";
-        field_name += part;
-      }
+      DO(ConsumeFullTypeName(&field_name));
       DO(Consume("]"));
     } else {
       DO(ConsumeIdentifier(&field_name));
@@ -553,13 +585,7 @@
     }
 
     string delimiter;
-    if (TryConsume("<")) {
-      delimiter = ">";
-    } else {
-      DO(Consume("{"));
-      delimiter = "}";
-    }
-
+    DO(ConsumeMessageDelimiter(&delimiter));
     if (field->is_repeated()) {
       DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter));
     } else {
@@ -576,12 +602,7 @@
   // the ending delimiter.
   bool SkipFieldMessage() {
     string delimiter;
-    if (TryConsume("<")) {
-      delimiter = ">";
-    } else {
-      DO(Consume("{"));
-      delimiter = "}";
-    }
+    DO(ConsumeMessageDelimiter(&delimiter));
     while (!LookingAt(">") &&  !LookingAt("}")) {
       DO(SkipField());
     }
@@ -808,6 +829,18 @@
     return false;
   }
 
+  // Consume a string of form "<id1>.<id2>....<idN>".
+  bool ConsumeFullTypeName(string* name) {
+    DO(ConsumeIdentifier(name));
+    while (TryConsume(".")) {
+      string part;
+      DO(ConsumeIdentifier(&part));
+      *name += ".";
+      *name += part;
+    }
+    return true;
+  }
+
   // Consumes a string and saves its value in the text parameter.
   // Returns false if the token is not of type STRING.
   bool ConsumeString(string* text) {
@@ -947,6 +980,54 @@
     return true;
   }
 
+  // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name"
+  bool ConsumeAnyTypeUrl(string* full_type_name) {
+    // TODO(saito) Extend Consume() to consume multiple tokens at once, so that
+    // this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
+    string url1, url2, url3;
+    DO(ConsumeIdentifier(&url1));  // type
+    DO(Consume("."));
+    DO(ConsumeIdentifier(&url2));  // googleapis
+    DO(Consume("."));
+    DO(ConsumeIdentifier(&url3));  // com
+    DO(Consume("/"));
+    DO(ConsumeFullTypeName(full_type_name));
+
+    const string prefix = url1 + "." + url2 + "." + url3 + "/";
+    if (prefix != internal::kTypeGoogleApisComPrefix) {
+      ReportError("TextFormat::Parser for Any supports only "
+                  "type.googleapi.com, but found \"" + prefix + "\"");
+      return false;
+    }
+    return true;
+  }
+
+  // A helper function for reconstructing Any::value. Consumes a text of
+  // full_type_name, then serializes it into serialized_value. "pool" is used to
+  // look up and create a temporary object with full_type_name.
+  bool ConsumeAnyValue(const string& full_type_name, const DescriptorPool* pool,
+                       string* serialized_value) {
+    const Descriptor* value_descriptor =
+        pool->FindMessageTypeByName(full_type_name);
+    if (value_descriptor == NULL) {
+      ReportError("Could not find type \"" + full_type_name +
+                  "\" stored in google.protobuf.Any.");
+      return false;
+    }
+    DynamicMessageFactory factory;
+    const Message* value_prototype = factory.GetPrototype(value_descriptor);
+    if (value_prototype == NULL) {
+      return false;
+    }
+    google::protobuf::scoped_ptr<Message> value(value_prototype->New());
+    string sub_delimiter;
+    DO(ConsumeMessageDelimiter(&sub_delimiter));
+    DO(ConsumeMessage(value.get(), sub_delimiter));
+
+    value->AppendToString(serialized_value);
+    return true;
+  }
+
   // Consumes a token and confirms that it matches that specified in the
   // value parameter. Returns false if the token found does not match that
   // which was specified.
@@ -1338,7 +1419,8 @@
     use_field_number_(false),
     use_short_repeated_primitives_(false),
     hide_unknown_fields_(false),
-    print_message_fields_in_index_order_(false) {
+    print_message_fields_in_index_order_(false),
+    expand_any_(false) {
   SetUseUtf8StringEscaping(false);
 }
 
@@ -1413,11 +1495,63 @@
     return left->index() < right->index();
   }
 };
+
 }  // namespace
 
+bool TextFormat::Printer::PrintAny(const Message& message,
+                                   TextGenerator& generator) const {
+  const FieldDescriptor* type_url_field;
+  const FieldDescriptor* value_field;
+  if (!internal::GetAnyFieldDescriptors(message, &type_url_field,
+                                        &value_field)) {
+    return false;
+  }
+
+  const Reflection* reflection = message.GetReflection();
+
+  // Extract the full type name from the type_url field.
+  const string& type_url = reflection->GetString(message, type_url_field);
+  string full_type_name;
+  if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+    return false;
+  }
+
+  // Print the "value" in text.
+  const google::protobuf::Descriptor* value_descriptor =
+      message.GetDescriptor()->file()->pool()->FindMessageTypeByName(
+          full_type_name);
+  if (value_descriptor == NULL) {
+    GOOGLE_LOG(WARNING) << "Proto type " << type_url << " not found";
+    return false;
+  }
+  DynamicMessageFactory factory;
+  google::protobuf::scoped_ptr<google::protobuf::Message> value_message(
+      factory.GetPrototype(value_descriptor)->New());
+  string serialized_value = reflection->GetString(message, value_field);
+  if (!value_message->ParseFromString(serialized_value)) {
+    GOOGLE_LOG(WARNING) << type_url << ": failed to parse contents";
+    return false;
+  }
+  generator.Print(StrCat("[", type_url, "]"));
+  const FieldValuePrinter* printer = FindWithDefault(
+      custom_printers_, value_field, default_field_value_printer_.get());
+  generator.Print(
+      printer->PrintMessageStart(message, -1, 0, single_line_mode_));
+  generator.Indent();
+  Print(*value_message, generator);
+  generator.Outdent();
+  generator.Print(printer->PrintMessageEnd(message, -1, 0, single_line_mode_));
+  return true;
+}
+
 void TextFormat::Printer::Print(const Message& message,
                                 TextGenerator& generator) const {
+  const Descriptor* descriptor = message.GetDescriptor();
   const Reflection* reflection = message.GetReflection();
+  if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
+      PrintAny(message, generator)) {
+    return;
+  }
   vector<const FieldDescriptor*> fields;
   reflection->ListFields(message, &fields);
   if (print_message_fields_in_index_order_) {
@@ -1446,6 +1580,54 @@
   PrintFieldValue(message, message.GetReflection(), field, index, generator);
 }
 
+class MapEntryMessageComparator {
+ public:
+  explicit MapEntryMessageComparator(const Descriptor* descriptor)
+      : field_(descriptor->field(0)) {}
+
+  bool operator()(const Message* a, const Message* b) {
+    const Reflection* reflection = a->GetReflection();
+    switch (field_->cpp_type()) {
+      case FieldDescriptor::CPPTYPE_BOOL: {
+          bool first = reflection->GetBool(*a, field_);
+          bool second = reflection->GetBool(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT32: {
+          int32 first = reflection->GetInt32(*a, field_);
+          int32 second = reflection->GetInt32(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_INT64: {
+          int64 first = reflection->GetInt64(*a, field_);
+          int64 second = reflection->GetInt64(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT32: {
+          uint32 first = reflection->GetUInt32(*a, field_);
+          uint32 second = reflection->GetUInt32(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_UINT64: {
+          uint64 first = reflection->GetUInt64(*a, field_);
+          uint64 second = reflection->GetUInt64(*b, field_);
+          return first < second;
+      }
+      case FieldDescriptor::CPPTYPE_STRING: {
+          string first = reflection->GetString(*a, field_);
+          string second = reflection->GetString(*b, field_);
+          return first < second;
+      }
+      default:
+        GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
+        return true;
+    }
+  }
+
+ private:
+  const FieldDescriptor* field_;
+};
+
 void TextFormat::Printer::PrintField(const Message& message,
                                      const Reflection* reflection,
                                      const FieldDescriptor* field,
@@ -1466,6 +1648,21 @@
     count = 1;
   }
 
+  std::vector<const Message*> sorted_map_field;
+  if (field->is_map()) {
+    const RepeatedPtrField<Message>& map_field =
+        reflection->GetRepeatedPtrField<Message>(message, field);
+    for (RepeatedPtrField<Message>::const_pointer_iterator it =
+             map_field.pointer_begin();
+         it != map_field.pointer_end(); ++it) {
+      sorted_map_field.push_back(*it);
+    }
+
+    MapEntryMessageComparator comparator(field->message_type());
+    std::stable_sort(sorted_map_field.begin(), sorted_map_field.end(),
+                     comparator);
+  }
+
   for (int j = 0; j < count; ++j) {
     const int field_index = field->is_repeated() ? j : -1;
 
@@ -1475,8 +1672,10 @@
       const FieldValuePrinter* printer = FindWithDefault(
           custom_printers_, field, default_field_value_printer_.get());
       const Message& sub_message =
-              field->is_repeated()
-              ? reflection->GetRepeatedMessage(message, field, j)
+          field->is_repeated()
+              ? (field->is_map()
+                     ? *sorted_map_field[j]
+                     : reflection->GetRepeatedMessage(message, field, j))
               : reflection->GetMessage(message, field);
       generator.Print(
           printer->PrintMessageStart(
@@ -1680,8 +1879,8 @@
       case UnknownField::TYPE_FIXED32: {
         generator.Print(field_number);
         generator.Print(": 0x");
-        char buffer[kFastToBufferSize];
-        generator.Print(FastHex32ToBuffer(field.fixed32(), buffer));
+        generator.Print(
+            StrCat(strings::Hex(field.fixed32(), strings::Hex::ZERO_PAD_8)));
         if (single_line_mode_) {
           generator.Print(" ");
         } else {
@@ -1692,8 +1891,8 @@
       case UnknownField::TYPE_FIXED64: {
         generator.Print(field_number);
         generator.Print(": 0x");
-        char buffer[kFastToBufferSize];
-        generator.Print(FastHex64ToBuffer(field.fixed64(), buffer));
+        generator.Print(
+            StrCat(strings::Hex(field.fixed64(), strings::Hex::ZERO_PAD_16)));
         if (single_line_mode_) {
           generator.Print(" ");
         } else {
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 9e2cb07..6717aec 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -208,6 +208,17 @@
           print_message_fields_in_index_order;
     }
 
+    // If expand==true, expand google.protobuf.Any payloads. The output
+    // will be of form
+    //    [type_url] { <value_printed_in_text> }
+    //
+    // If expand==false, print Any using the default printer. The output will
+    // look like
+    //    type_url: "<type_url>"  value: "serialized_content"
+    void SetExpandAny(bool expand) {
+      expand_any_ = expand;
+    }
+
     // Register a custom field-specific FieldValuePrinter for fields
     // with a particular FieldDescriptor.
     // Returns "true" if the registration succeeded, or "false", if there is
@@ -259,6 +270,8 @@
     void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
                             TextGenerator& generator) const;
 
+    bool PrintAny(const Message& message, TextGenerator& generator) const;
+
     int initial_indent_level_;
 
     bool single_line_mode_;
@@ -271,6 +284,8 @@
 
     bool print_message_fields_in_index_order_;
 
+    bool expand_any_;
+
     google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
     typedef map<const FieldDescriptor*,
                 const FieldValuePrinter*> CustomPrinterMap;
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 477fdcb..1b18c5e 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -32,23 +32,24 @@
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
+#include <google/protobuf/text_format.h>
+
 #include <math.h>
 #include <stdlib.h>
 #include <limits>
 
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/io/tokenizer.h>
-#include <google/protobuf/unittest.pb.h>
-#include <google/protobuf/unittest_mset.pb.h>
-#include <google/protobuf/test_util.h>
-
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>
-#include <google/protobuf/testing/googletest.h>
-#include <gtest/gtest.h>
+#include <google/protobuf/test_util.h>
+#include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_mset.pb.h>
+#include <google/protobuf/io/tokenizer.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/testing/googletest.h>
+#include <gtest/gtest.h>
+
 
 namespace google {
 namespace protobuf {
@@ -451,7 +452,7 @@
 class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
   virtual string PrintInt32(int32 v) const {
-    return StrCat(FieldValuePrinter::PrintInt32(v), "  # x", ToHex(v));
+    return StrCat(FieldValuePrinter::PrintInt32(v), "  # x", strings::Hex(v));
   }
 
   virtual string PrintMessageStart(const Message& message,
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 6edfe05..877dc8f 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -117,7 +117,7 @@
 #endif  // !_MSC_VER
 
 Timestamp::Timestamp()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Timestamp)
 }
@@ -310,9 +310,9 @@
 
 void Timestamp::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Timestamp* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Timestamp*>(
-      &from);
+  const Timestamp* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Timestamp>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -370,7 +370,7 @@
 // Timestamp
 
 // optional int64 seconds = 1;
- void Timestamp::clear_seconds() {
+void Timestamp::clear_seconds() {
   seconds_ = GOOGLE_LONGLONG(0);
 }
  ::google::protobuf::int64 Timestamp::seconds() const {
@@ -384,7 +384,7 @@
 }
 
 // optional int32 nanos = 2;
- void Timestamp::clear_nanos() {
+void Timestamp::clear_nanos() {
   nanos_ = 0;
 }
  ::google::protobuf::int32 Timestamp::nanos() const {
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index d77bc6c..8b08909 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -267,7 +267,7 @@
 #endif  // !_MSC_VER
 
 Type::Type()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Type)
 }
@@ -332,7 +332,7 @@
 
 void Type::Clear() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
   fields_.Clear();
   oneofs_.Clear();
@@ -369,12 +369,15 @@
       case 2: {
         if (tag == 18) {
          parse_fields:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_fields:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_fields()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_fields;
+        if (input->ExpectTag(18)) goto parse_loop_fields;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(26)) goto parse_oneofs;
         break;
       }
@@ -402,12 +405,15 @@
       case 4: {
         if (tag == 34) {
          parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(34)) goto parse_options;
+        if (input->ExpectTag(34)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(42)) goto parse_source_context;
         break;
       }
@@ -587,9 +593,9 @@
 
 void Type::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Type* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Type*>(
-      &from);
+  const Type* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Type>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -654,7 +660,7 @@
 // Type
 
 // optional string name = 1;
- void Type::clear_name() {
+void Type::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Type::name() const {
@@ -697,10 +703,10 @@
 }
 
 // repeated .google.protobuf.Field fields = 2;
- int Type::fields_size() const {
+int Type::fields_size() const {
   return fields_.size();
 }
- void Type::clear_fields() {
+void Type::clear_fields() {
   fields_.Clear();
 }
  const ::google::protobuf::Field& Type::fields(int index) const {
@@ -727,10 +733,10 @@
 }
 
 // repeated string oneofs = 3;
- int Type::oneofs_size() const {
+int Type::oneofs_size() const {
   return oneofs_.size();
 }
- void Type::clear_oneofs() {
+void Type::clear_oneofs() {
   oneofs_.Clear();
 }
  const ::std::string& Type::oneofs(int index) const {
@@ -781,10 +787,10 @@
 }
 
 // repeated .google.protobuf.Option options = 4;
- int Type::options_size() const {
+int Type::options_size() const {
   return options_.size();
 }
- void Type::clear_options() {
+void Type::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& Type::options(int index) const {
@@ -811,11 +817,11 @@
 }
 
 // optional .google.protobuf.SourceContext source_context = 5;
- bool Type::has_source_context() const {
+bool Type::has_source_context() const {
   return !_is_default_instance_ && source_context_ != NULL;
 }
- void Type::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+void Type::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
  const ::google::protobuf::SourceContext& Type::source_context() const {
@@ -941,7 +947,7 @@
 #endif  // !_MSC_VER
 
 Field::Field()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Field)
 }
@@ -1153,12 +1159,15 @@
       case 9: {
         if (tag == 74) {
          parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(74)) goto parse_options;
+        if (input->ExpectTag(74)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -1370,9 +1379,9 @@
 
 void Field::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Field* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Field*>(
-      &from);
+  const Field* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Field>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1454,7 +1463,7 @@
 // Field
 
 // optional .google.protobuf.Field.Kind kind = 1;
- void Field::clear_kind() {
+void Field::clear_kind() {
   kind_ = 0;
 }
  ::google::protobuf::Field_Kind Field::kind() const {
@@ -1468,7 +1477,7 @@
 }
 
 // optional .google.protobuf.Field.Cardinality cardinality = 2;
- void Field::clear_cardinality() {
+void Field::clear_cardinality() {
   cardinality_ = 0;
 }
  ::google::protobuf::Field_Cardinality Field::cardinality() const {
@@ -1482,7 +1491,7 @@
 }
 
 // optional int32 number = 3;
- void Field::clear_number() {
+void Field::clear_number() {
   number_ = 0;
 }
  ::google::protobuf::int32 Field::number() const {
@@ -1496,7 +1505,7 @@
 }
 
 // optional string name = 4;
- void Field::clear_name() {
+void Field::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Field::name() const {
@@ -1539,7 +1548,7 @@
 }
 
 // optional string type_url = 6;
- void Field::clear_type_url() {
+void Field::clear_type_url() {
   type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Field::type_url() const {
@@ -1582,7 +1591,7 @@
 }
 
 // optional int32 oneof_index = 7;
- void Field::clear_oneof_index() {
+void Field::clear_oneof_index() {
   oneof_index_ = 0;
 }
  ::google::protobuf::int32 Field::oneof_index() const {
@@ -1596,7 +1605,7 @@
 }
 
 // optional bool packed = 8;
- void Field::clear_packed() {
+void Field::clear_packed() {
   packed_ = false;
 }
  bool Field::packed() const {
@@ -1610,10 +1619,10 @@
 }
 
 // repeated .google.protobuf.Option options = 9;
- int Field::options_size() const {
+int Field::options_size() const {
   return options_.size();
 }
- void Field::clear_options() {
+void Field::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& Field::options(int index) const {
@@ -1651,7 +1660,7 @@
 #endif  // !_MSC_VER
 
 Enum::Enum()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Enum)
 }
@@ -1716,7 +1725,7 @@
 
 void Enum::Clear() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
   enumvalue_.Clear();
   options_.Clear();
@@ -1752,26 +1761,31 @@
       case 2: {
         if (tag == 18) {
          parse_enumvalue:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_enumvalue:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_enumvalue()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(18)) goto parse_enumvalue;
-        if (input->ExpectTag(26)) goto parse_options;
+        if (input->ExpectTag(18)) goto parse_loop_enumvalue;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         break;
       }
 
       // repeated .google.protobuf.Option options = 3;
       case 3: {
         if (tag == 26) {
-         parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(26)) goto parse_options;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectTag(34)) goto parse_source_context;
         break;
       }
@@ -1924,9 +1938,9 @@
 
 void Enum::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Enum* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Enum*>(
-      &from);
+  const Enum* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Enum>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1989,7 +2003,7 @@
 // Enum
 
 // optional string name = 1;
- void Enum::clear_name() {
+void Enum::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Enum::name() const {
@@ -2032,10 +2046,10 @@
 }
 
 // repeated .google.protobuf.EnumValue enumvalue = 2;
- int Enum::enumvalue_size() const {
+int Enum::enumvalue_size() const {
   return enumvalue_.size();
 }
- void Enum::clear_enumvalue() {
+void Enum::clear_enumvalue() {
   enumvalue_.Clear();
 }
  const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const {
@@ -2062,10 +2076,10 @@
 }
 
 // repeated .google.protobuf.Option options = 3;
- int Enum::options_size() const {
+int Enum::options_size() const {
   return options_.size();
 }
- void Enum::clear_options() {
+void Enum::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& Enum::options(int index) const {
@@ -2092,11 +2106,11 @@
 }
 
 // optional .google.protobuf.SourceContext source_context = 4;
- bool Enum::has_source_context() const {
+bool Enum::has_source_context() const {
   return !_is_default_instance_ && source_context_ != NULL;
 }
- void Enum::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+void Enum::clear_source_context() {
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
  const ::google::protobuf::SourceContext& Enum::source_context() const {
@@ -2139,7 +2153,7 @@
 #endif  // !_MSC_VER
 
 EnumValue::EnumValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.EnumValue)
 }
@@ -2251,12 +2265,15 @@
       case 3: {
         if (tag == 26) {
          parse_options:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
                 input, add_options()));
         } else {
           goto handle_unusual;
         }
-        if (input->ExpectTag(26)) goto parse_options;
+        if (input->ExpectTag(26)) goto parse_loop_options;
+        input->UnsafeDecrementRecursionDepth();
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -2372,9 +2389,9 @@
 
 void EnumValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const EnumValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const EnumValue*>(
-      &from);
+  const EnumValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const EnumValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2435,7 +2452,7 @@
 // EnumValue
 
 // optional string name = 1;
- void EnumValue::clear_name() {
+void EnumValue::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& EnumValue::name() const {
@@ -2478,7 +2495,7 @@
 }
 
 // optional int32 number = 2;
- void EnumValue::clear_number() {
+void EnumValue::clear_number() {
   number_ = 0;
 }
  ::google::protobuf::int32 EnumValue::number() const {
@@ -2492,10 +2509,10 @@
 }
 
 // repeated .google.protobuf.Option options = 3;
- int EnumValue::options_size() const {
+int EnumValue::options_size() const {
   return options_.size();
 }
- void EnumValue::clear_options() {
+void EnumValue::clear_options() {
   options_.Clear();
 }
  const ::google::protobuf::Option& EnumValue::options(int index) const {
@@ -2531,7 +2548,7 @@
 #endif  // !_MSC_VER
 
 Option::Option()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Option)
 }
@@ -2596,7 +2613,7 @@
 
 void Option::Clear() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
-  if (value_ != NULL) delete value_;
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
   value_ = NULL;
 }
 
@@ -2732,9 +2749,9 @@
 
 void Option::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Option* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Option*>(
-      &from);
+  const Option* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Option>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2793,7 +2810,7 @@
 // Option
 
 // optional string name = 1;
- void Option::clear_name() {
+void Option::clear_name() {
   name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& Option::name() const {
@@ -2836,11 +2853,11 @@
 }
 
 // optional .google.protobuf.Any value = 2;
- bool Option::has_value() const {
+bool Option::has_value() const {
   return !_is_default_instance_ && value_ != NULL;
 }
- void Option::clear_value() {
-  if (value_ != NULL) delete value_;
+void Option::clear_value() {
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
   value_ = NULL;
 }
  const ::google::protobuf::Any& Option::value() const {
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index a14edd4..c9952ef 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -936,7 +936,7 @@
   return !_is_default_instance_ && source_context_ != NULL;
 }
 inline void Type::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
 inline const ::google::protobuf::SourceContext& Type::source_context() const {
@@ -1270,7 +1270,7 @@
   return !_is_default_instance_ && source_context_ != NULL;
 }
 inline void Enum::clear_source_context() {
-  if (source_context_ != NULL) delete source_context_;
+  if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_;
   source_context_ = NULL;
 }
 inline const ::google::protobuf::SourceContext& Enum::source_context() const {
@@ -1445,7 +1445,7 @@
   return !_is_default_instance_ && value_ != NULL;
 }
 inline void Option::clear_value() {
-  if (value_ != NULL) delete value_;
+  if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_;
   value_ = NULL;
 }
 inline const ::google::protobuf::Any& Option::value() const {
@@ -1478,6 +1478,14 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index a32291e..834c9b5 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -185,6 +185,7 @@
 message NestedTestAllTypes {
   optional NestedTestAllTypes child = 1;
   optional TestAllTypes payload = 2;
+  repeated NestedTestAllTypes repeated_child = 3;
 }
 
 message TestDeprecatedFields {
@@ -203,6 +204,11 @@
   FOREIGN_BAZ = 6;
 }
 
+message TestReservedFields {
+  reserved 2, 15, 9 to 11;
+  reserved "bar", "baz";
+}
+
 message TestAllExtensions {
   extensions 1 to max;
 }
diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto
index 1b35fad..faaddc6 100644
--- a/src/google/protobuf/unittest_drop_unknown_fields.proto
+++ b/src/google/protobuf/unittest_drop_unknown_fields.proto
@@ -41,8 +41,8 @@
     BAR = 1;
     BAZ = 2;
   }
-  optional int32 int32_value = 1;
-  optional NestedEnum enum_value = 2;
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
 }
 
 message FooWithExtraFields {
@@ -52,7 +52,7 @@
     BAZ = 2;
     QUX = 3;
   }
-  optional int32 int32_value = 1;
-  optional NestedEnum enum_value = 2;
-  optional int32 extra_int32_value = 3;
+  int32 int32_value = 1;
+  NestedEnum enum_value = 2;
+  int32 extra_int32_value = 3;
 }
diff --git a/src/google/protobuf/unittest_no_field_presence.proto b/src/google/protobuf/unittest_no_field_presence.proto
index f261b58..f5cc4cc 100644
--- a/src/google/protobuf/unittest_no_field_presence.proto
+++ b/src/google/protobuf/unittest_no_field_presence.proto
@@ -43,7 +43,7 @@
 // forms.
 message TestAllTypes {
   message NestedMessage {
-    optional int32 bb = 1;
+    int32 bb = 1;
   }
 
   enum NestedEnum {
@@ -55,36 +55,36 @@
   // Singular
   // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make
   // 'optional' optional.
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
 
-  optional NestedMessage                        optional_nested_message  = 18;
-  optional ForeignMessage                       optional_foreign_message = 19;
-  optional protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest.TestAllTypes         optional_proto2_message = 20;
 
-  optional NestedEnum                           optional_nested_enum     = 21;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
   // N.B.: proto2-enum-type fields not allowed, because their default values
   // might not be zero.
   //optional protobuf_unittest.ForeignEnum          optional_proto2_enum     = 23;
 
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
 
-  optional NestedMessage optional_lazy_message = 30 [lazy=true];
+  NestedMessage optional_lazy_message = 30 [lazy=true];
 
   // Repeated
   repeated    int32 repeated_int32    = 31;
@@ -124,13 +124,13 @@
 }
 
 message TestProto2Required {
-  optional protobuf_unittest.TestRequired proto2 = 1;
+  protobuf_unittest.TestRequired proto2 = 1;
 }
 
 // Define these after TestAllTypes to make sure the compiler can handle
 // that.
 message ForeignMessage {
-  optional int32 c = 1;
+  int32 c = 1;
 }
 
 enum ForeignEnum {
diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto
index 24e6828..abc3de2 100644
--- a/src/google/protobuf/unittest_preserve_unknown_enum.proto
+++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto
@@ -49,7 +49,7 @@
 }
 
 message MyMessage {
-  optional MyEnum e = 1;
+  MyEnum e = 1;
   repeated MyEnum repeated_e = 2;
   repeated MyEnum repeated_packed_e = 3 [packed=true];
   repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4;  // not packed
@@ -60,7 +60,7 @@
 }
 
 message MyMessagePlusExtra {
-  optional MyEnumPlusExtra e = 1;
+  MyEnumPlusExtra e = 1;
   repeated MyEnumPlusExtra repeated_e = 2;
   repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true];
   repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4 [packed=true];
diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto
index 6d7bada..b835a6b 100644
--- a/src/google/protobuf/unittest_proto3_arena.proto
+++ b/src/google/protobuf/unittest_proto3_arena.proto
@@ -43,7 +43,7 @@
     // The field name "b" fails to compile in proto1 because it conflicts with
     // a local variable named "b" in one of the generated methods.  Doh.
     // This file needs to compile in proto1 to test backwards-compatibility.
-    optional int32 bb = 1;
+    int32 bb = 1;
   }
 
   enum NestedEnum {
@@ -55,46 +55,47 @@
   }
 
   // Singular
-  optional    int32 optional_int32    =  1;
-  optional    int64 optional_int64    =  2;
-  optional   uint32 optional_uint32   =  3;
-  optional   uint64 optional_uint64   =  4;
-  optional   sint32 optional_sint32   =  5;
-  optional   sint64 optional_sint64   =  6;
-  optional  fixed32 optional_fixed32  =  7;
-  optional  fixed64 optional_fixed64  =  8;
-  optional sfixed32 optional_sfixed32 =  9;
-  optional sfixed64 optional_sfixed64 = 10;
-  optional    float optional_float    = 11;
-  optional   double optional_double   = 12;
-  optional     bool optional_bool     = 13;
-  optional   string optional_string   = 14;
-  optional    bytes optional_bytes    = 15;
+     int32 optional_int32    =  1;
+     int64 optional_int64    =  2;
+    uint32 optional_uint32   =  3;
+    uint64 optional_uint64   =  4;
+    sint32 optional_sint32   =  5;
+    sint64 optional_sint64   =  6;
+   fixed32 optional_fixed32  =  7;
+   fixed64 optional_fixed64  =  8;
+  sfixed32 optional_sfixed32 =  9;
+  sfixed64 optional_sfixed64 = 10;
+     float optional_float    = 11;
+    double optional_double   = 12;
+      bool optional_bool     = 13;
+    string optional_string   = 14;
+     bytes optional_bytes    = 15;
 
-  optional group OptionalGroup = 16 {
-    optional int32 a = 17;
-  }
+  // Groups are not allowed in proto3.
+  // optional group OptionalGroup = 16 {
+  //   optional int32 a = 17;
+  // }
 
-  optional NestedMessage                        optional_nested_message  = 18;
-  optional ForeignMessage                       optional_foreign_message = 19;
-  optional protobuf_unittest_import.ImportMessage optional_import_message  = 20;
+  NestedMessage                        optional_nested_message  = 18;
+  ForeignMessage                       optional_foreign_message = 19;
+  protobuf_unittest_import.ImportMessage optional_import_message  = 20;
 
-  optional NestedEnum                           optional_nested_enum     = 21;
-  optional ForeignEnum                          optional_foreign_enum    = 22;
+  NestedEnum                           optional_nested_enum     = 21;
+  ForeignEnum                          optional_foreign_enum    = 22;
 
   // Omitted (compared to unittest.proto) because proto2 enums are not allowed
   // inside proto2 messages.
   //
   // optional protobuf_unittest_import.ImportEnum    optional_import_enum  = 23;
 
-  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
-  optional string optional_cord = 25 [ctype=CORD];
+  string optional_string_piece = 24 [ctype=STRING_PIECE];
+  string optional_cord = 25 [ctype=CORD];
 
   // Defined in unittest_import_public.proto
-  optional protobuf_unittest_import.PublicImportMessage
+  protobuf_unittest_import.PublicImportMessage
       optional_public_import_message = 26;
 
-  optional NestedMessage optional_lazy_message = 27 [lazy=true];
+  NestedMessage optional_lazy_message = 27 [lazy=true];
 
   // Repeated
   repeated    int32 repeated_int32    = 31;
@@ -113,9 +114,10 @@
   repeated   string repeated_string   = 44;
   repeated    bytes repeated_bytes    = 45;
 
-  repeated group RepeatedGroup = 46 {
-    optional int32 a = 47;
-  }
+  // Groups are not allowed in proto3.
+  // repeated group RepeatedGroup = 46 {
+  //   optional int32 a = 47;
+  // }
 
   repeated NestedMessage                        repeated_nested_message  = 48;
   repeated ForeignMessage                       repeated_foreign_message = 49;
@@ -161,6 +163,24 @@
   repeated ForeignEnum packed_enum  = 103 [packed = true];
 }
 
+// Explicitly set packed to false
+message TestUnpackedTypes {
+  repeated    int32 repeated_int32    =  1 [packed = false];
+  repeated    int64 repeated_int64    =  2 [packed = false];
+  repeated   uint32 repeated_uint32   =  3 [packed = false];
+  repeated   uint64 repeated_uint64   =  4 [packed = false];
+  repeated   sint32 repeated_sint32   =  5 [packed = false];
+  repeated   sint64 repeated_sint64   =  6 [packed = false];
+  repeated  fixed32 repeated_fixed32  =  7 [packed = false];
+  repeated  fixed64 repeated_fixed64  =  8 [packed = false];
+  repeated sfixed32 repeated_sfixed32 =  9 [packed = false];
+  repeated sfixed64 repeated_sfixed64 = 10 [packed = false];
+  repeated    float repeated_float    = 11 [packed = false];
+  repeated   double repeated_double   = 12 [packed = false];
+  repeated     bool repeated_bool     = 13 [packed = false];
+  repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false];
+}
+
 // This proto includes a recusively nested message.
 message NestedTestAllTypes {
   NestedTestAllTypes child = 1;
@@ -170,7 +190,7 @@
 // Define these after TestAllTypes to make sure the compiler can handle
 // that.
 message ForeignMessage {
-  optional int32 c = 1;
+  int32 c = 1;
 }
 
 enum ForeignEnum {
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index e15280c..7664490 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -93,7 +93,7 @@
     fields_ = new vector<UnknownField>();
     for (int i = 0; i < other_field_count; i++) {
       fields_->push_back((*other.fields_)[i]);
-      fields_->back().DeepCopy();
+      fields_->back().DeepCopy((*other.fields_)[i]);
     }
   }
 }
@@ -104,7 +104,7 @@
     if (fields_ == NULL) fields_ = new vector<UnknownField>();
     for (int i = 0; i < other_field_count; i++) {
       fields_->push_back((*other.fields_)[i]);
-      fields_->back().DeepCopy();
+      fields_->back().DeepCopy((*other.fields_)[i]);
     }
   }
 }
@@ -202,7 +202,7 @@
 void UnknownFieldSet::AddField(const UnknownField& field) {
   if (fields_ == NULL) fields_ = new vector<UnknownField>();
   fields_->push_back(field);
-  fields_->back().DeepCopy();
+  fields_->back().DeepCopy(field);
 }
 
 void UnknownFieldSet::DeleteSubrange(int start, int num) {
@@ -303,7 +303,7 @@
   }
 }
 
-void UnknownField::DeepCopy() {
+void UnknownField::DeepCopy(const UnknownField& other) {
   switch (type()) {
     case UnknownField::TYPE_LENGTH_DELIMITED:
       length_delimited_.string_value_ = new string(
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 987b197..6781cd0 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -216,7 +216,7 @@
   void Reset();
 
   // Make a deep copy of any pointers in this UnknownField.
-  void DeepCopy();
+  void DeepCopy(const UnknownField& other);
 
   // Set the wire type of this UnknownField. Should only be used when this
   // UnknownField is being created.
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index c5bbbf2..54cd653 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -829,7 +829,7 @@
     count = 1;
   }
 
-  const bool is_packed = field->options().packed();
+  const bool is_packed = field->is_packed();
   if (is_packed && count > 0) {
     WireFormatLite::WriteTag(field->number(),
         WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
@@ -996,7 +996,7 @@
 
   const int data_size = FieldDataOnlyByteSize(field, message);
   int our_size = data_size;
-  if (field->options().packed()) {
+  if (field->is_packed()) {
     if (data_size > 0) {
       // Packed fields get serialized like a string, not their native type.
       // Technically this doesn't really matter; the size only changes if it's
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 76bc75a..ac83abd 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -330,6 +330,17 @@
   template<typename MessageType>
   static inline bool ReadMessageNoVirtual(input, MessageType* value);
 
+  // The same, but do not modify input's recursion depth.  This is useful
+  // when reading a bunch of groups or messages in a loop, because then the
+  // recursion depth can be incremented before the loop and decremented after.
+  template<typename MessageType>
+  static inline bool ReadGroupNoVirtualNoRecursionDepth(field_number, input,
+                                                        MessageType* value);
+
+  template<typename MessageType>
+  static inline bool ReadMessageNoVirtualNoRecursionDepth(input,
+                                                          MessageType* value);
+
   // Write a tag.  The Write*() functions typically include the tag, so
   // normally there's no need to call this unless using the Write*NoTag()
   // variants.
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 129fc63..d073ff9 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -470,7 +470,7 @@
   if (!value->
       MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
     return false;
-  input->DecrementRecursionDepth();
+  input->UnsafeDecrementRecursionDepth();
   // Make sure the last thing read was an end tag for this group.
   if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) {
     return false;
@@ -478,6 +478,14 @@
   return true;
 }
 template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadGroupNoVirtualNoRecursionDepth(
+    int field_number, io::CodedInputStream* input,
+    MessageType_WorkAroundCppLookupDefect* value) {
+  return value->MessageType_WorkAroundCppLookupDefect::
+             MergePartialFromCodedStream(input) &&
+         input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP));
+}
+template<typename MessageType_WorkAroundCppLookupDefect>
 inline bool WireFormatLite::ReadMessageNoVirtual(
     io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
   uint32 length;
@@ -491,6 +499,17 @@
   // tag.
   return input->DecrementRecursionDepthAndPopLimit(p.first);
 }
+template<typename MessageType_WorkAroundCppLookupDefect>
+inline bool WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+    io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
+  io::CodedInputStream::Limit old_limit = input->ReadLengthAndPushLimit();
+  if (!value->
+      MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input))
+    return false;
+  // Make sure that parsing stopped when the limit was hit, not at an endgroup
+  // tag.
+  return input->CheckEntireMessageConsumedAndPopLimit(old_limit);
+}
 
 // ===================================================================
 
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index a3062a6..e80c5a7 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -38,6 +38,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/unittest.pb.h>
+#include <google/protobuf/unittest_proto3_arena.pb.h>
 #include <google/protobuf/unittest_mset.pb.h>
 #include <google/protobuf/test_util.h>
 
@@ -794,6 +795,137 @@
   ASSERT_EQ(static_cast<uint32>(data), msg5.data());
 }
 
+class Proto3PrimitiveRepeatedWireFormatTest
+    : public ::testing::TestWithParam<bool> {
+ protected:
+  template <class Proto>
+  void SetProto3PrimitiveRepeatedFields(Proto* message) {
+    message->add_repeated_int32(1);
+    message->add_repeated_int64(1);
+    message->add_repeated_uint32(1);
+    message->add_repeated_uint64(1);
+    message->add_repeated_sint32(1);
+    message->add_repeated_sint64(1);
+    message->add_repeated_fixed32(1);
+    message->add_repeated_fixed64(1);
+    message->add_repeated_sfixed32(1);
+    message->add_repeated_sfixed64(1);
+    message->add_repeated_float(1.0);
+    message->add_repeated_double(1.0);
+    message->add_repeated_bool(true);
+    message->add_repeated_nested_enum(
+        proto3_arena_unittest::TestAllTypes_NestedEnum_FOO);
+  }
+
+  template <class Proto>
+  void ExpectProto3PrimitiveRepeatedFieldsSet(const Proto& message) {
+    EXPECT_EQ(1, message.repeated_int32(0));
+    EXPECT_EQ(1, message.repeated_int64(0));
+    EXPECT_EQ(1, message.repeated_uint32(0));
+    EXPECT_EQ(1, message.repeated_uint64(0));
+    EXPECT_EQ(1, message.repeated_sint32(0));
+    EXPECT_EQ(1, message.repeated_sint64(0));
+    EXPECT_EQ(1, message.repeated_fixed32(0));
+    EXPECT_EQ(1, message.repeated_fixed64(0));
+    EXPECT_EQ(1, message.repeated_sfixed32(0));
+    EXPECT_EQ(1, message.repeated_sfixed64(0));
+    EXPECT_EQ(1.0, message.repeated_float(0));
+    EXPECT_EQ(1.0, message.repeated_double(0));
+    EXPECT_EQ(true, message.repeated_bool(0));
+    EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_FOO,
+              message.repeated_nested_enum(0));
+  }
+
+  template <class Proto>
+  void TestProto3PrimitiveRepeatedFields(Proto* message,
+                                         const string& expected) {
+    SetProto3PrimitiveRepeatedFields(message);
+
+    int size = message->ByteSize();
+
+    // Serialize using the generated code.
+    string generated_data;
+    {
+      io::StringOutputStream raw_output(&generated_data);
+      io::CodedOutputStream output(&raw_output);
+      message->SerializeWithCachedSizes(&output);
+      ASSERT_FALSE(output.HadError());
+    }
+
+    EXPECT_TRUE(expected == generated_data);
+
+    message->Clear();
+    message->ParseFromString(generated_data);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+
+    // Serialize using the dynamic code.
+    string dynamic_data;
+    {
+      io::StringOutputStream raw_output(&dynamic_data);
+      io::CodedOutputStream output(&raw_output);
+      WireFormat::SerializeWithCachedSizes(*message, size, &output);
+      ASSERT_FALSE(output.HadError());
+    }
+
+    EXPECT_TRUE(expected == dynamic_data);
+
+    message->Clear();
+    io::CodedInputStream input(
+        reinterpret_cast<const uint8*>(dynamic_data.data()),
+        dynamic_data.size());
+    WireFormat::ParseAndMergePartial(&input, message);
+    ExpectProto3PrimitiveRepeatedFieldsSet(*message);
+  }
+};
+INSTANTIATE_TEST_CASE_P(SetPacked,
+                        Proto3PrimitiveRepeatedWireFormatTest,
+                        ::testing::Values(false, true));
+
+TEST_P(Proto3PrimitiveRepeatedWireFormatTest, Proto3PrimitiveRepeated) {
+  proto3_arena_unittest::TestAllTypes packed_message;
+  proto3_arena_unittest::TestUnpackedTypes unpacked_message;
+
+  const string packedExpected(
+      "\xFA\x01\x01\x01"
+      "\x82\x02\x01\x01"
+      "\x8A\x02\x01\x01"
+      "\x92\x02\x01\x01"
+      "\x9A\x02\x01\x02"
+      "\xA2\x02\x01\x02"
+      "\xAA\x02\x04\x01\x00\x00\x00"
+      "\xB2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+      "\xBA\x02\x04\x01\x00\x00\x00"
+      "\xC2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00"
+      "\xCA\x02\x04\x00\x00\x80\x3f"
+      "\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xf0\x3f"
+      "\xDA\x02\x01\x01"
+      "\x9A\x03\x01\x01",
+      86);
+
+  const string unpackedExpected(
+      "\x08\x01"
+      "\x10\x01"
+      "\x18\x01"
+      "\x20\x01"
+      "\x28\x02"
+      "\x30\x02"
+      "\x3D\x01\x00\x00\x00"
+      "\x41\x01\x00\x00\x00\x00\x00\x00\x00"
+      "\x4D\x01\x00\x00\x00"
+      "\x51\x01\x00\x00\x00\x00\x00\x00\x00"
+      "\x5D\x00\x00\x80\x3f"
+      "\x61\x00\x00\x00\x00\x00\x00\xf0\x3f"
+      "\x68\x01"
+      "\x70\x01",
+      58);
+
+  if (GetParam()) {
+    TestProto3PrimitiveRepeatedFields(&packed_message, packedExpected);
+  } else {
+    TestProto3PrimitiveRepeatedFields(&unpacked_message, unpackedExpected);
+  }
+}
+
 class WireFormatInvalidInputTest : public testing::Test {
  protected:
   // Make a serialized TestAllTypes in which the field optional_nested_message
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 4d91ed5..ffc77f1 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -312,7 +312,7 @@
 #endif  // !_MSC_VER
 
 DoubleValue::DoubleValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.DoubleValue)
 }
@@ -458,9 +458,9 @@
 
 void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const DoubleValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const DoubleValue*>(
-      &from);
+  const DoubleValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const DoubleValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -514,7 +514,7 @@
 // DoubleValue
 
 // optional double value = 1;
- void DoubleValue::clear_value() {
+void DoubleValue::clear_value() {
   value_ = 0;
 }
  double DoubleValue::value() const {
@@ -536,7 +536,7 @@
 #endif  // !_MSC_VER
 
 FloatValue::FloatValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.FloatValue)
 }
@@ -682,9 +682,9 @@
 
 void FloatValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const FloatValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const FloatValue*>(
-      &from);
+  const FloatValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const FloatValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -738,7 +738,7 @@
 // FloatValue
 
 // optional float value = 1;
- void FloatValue::clear_value() {
+void FloatValue::clear_value() {
   value_ = 0;
 }
  float FloatValue::value() const {
@@ -760,7 +760,7 @@
 #endif  // !_MSC_VER
 
 Int64Value::Int64Value()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Int64Value)
 }
@@ -908,9 +908,9 @@
 
 void Int64Value::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Int64Value* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Int64Value*>(
-      &from);
+  const Int64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int64Value>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -964,7 +964,7 @@
 // Int64Value
 
 // optional int64 value = 1;
- void Int64Value::clear_value() {
+void Int64Value::clear_value() {
   value_ = GOOGLE_LONGLONG(0);
 }
  ::google::protobuf::int64 Int64Value::value() const {
@@ -986,7 +986,7 @@
 #endif  // !_MSC_VER
 
 UInt64Value::UInt64Value()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UInt64Value)
 }
@@ -1134,9 +1134,9 @@
 
 void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UInt64Value* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UInt64Value*>(
-      &from);
+  const UInt64Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt64Value>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1190,7 +1190,7 @@
 // UInt64Value
 
 // optional uint64 value = 1;
- void UInt64Value::clear_value() {
+void UInt64Value::clear_value() {
   value_ = GOOGLE_ULONGLONG(0);
 }
  ::google::protobuf::uint64 UInt64Value::value() const {
@@ -1212,7 +1212,7 @@
 #endif  // !_MSC_VER
 
 Int32Value::Int32Value()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.Int32Value)
 }
@@ -1360,9 +1360,9 @@
 
 void Int32Value::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const Int32Value* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const Int32Value*>(
-      &from);
+  const Int32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const Int32Value>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1416,7 +1416,7 @@
 // Int32Value
 
 // optional int32 value = 1;
- void Int32Value::clear_value() {
+void Int32Value::clear_value() {
   value_ = 0;
 }
  ::google::protobuf::int32 Int32Value::value() const {
@@ -1438,7 +1438,7 @@
 #endif  // !_MSC_VER
 
 UInt32Value::UInt32Value()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.UInt32Value)
 }
@@ -1586,9 +1586,9 @@
 
 void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const UInt32Value* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const UInt32Value*>(
-      &from);
+  const UInt32Value* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const UInt32Value>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1642,7 +1642,7 @@
 // UInt32Value
 
 // optional uint32 value = 1;
- void UInt32Value::clear_value() {
+void UInt32Value::clear_value() {
   value_ = 0u;
 }
  ::google::protobuf::uint32 UInt32Value::value() const {
@@ -1664,7 +1664,7 @@
 #endif  // !_MSC_VER
 
 BoolValue::BoolValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.BoolValue)
 }
@@ -1810,9 +1810,9 @@
 
 void BoolValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const BoolValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const BoolValue*>(
-      &from);
+  const BoolValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BoolValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -1866,7 +1866,7 @@
 // BoolValue
 
 // optional bool value = 1;
- void BoolValue::clear_value() {
+void BoolValue::clear_value() {
   value_ = false;
 }
  bool BoolValue::value() const {
@@ -1888,7 +1888,7 @@
 #endif  // !_MSC_VER
 
 StringValue::StringValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.StringValue)
 }
@@ -2051,9 +2051,9 @@
 
 void StringValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const StringValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const StringValue*>(
-      &from);
+  const StringValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const StringValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2108,7 +2108,7 @@
 // StringValue
 
 // optional string value = 1;
- void StringValue::clear_value() {
+void StringValue::clear_value() {
   value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& StringValue::value() const {
@@ -2159,7 +2159,7 @@
 #endif  // !_MSC_VER
 
 BytesValue::BytesValue()
-  : ::google::protobuf::Message() , _internal_metadata_(NULL)  {
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
   SharedCtor();
   // @@protoc_insertion_point(constructor:google.protobuf.BytesValue)
 }
@@ -2310,9 +2310,9 @@
 
 void BytesValue::MergeFrom(const ::google::protobuf::Message& from) {
   if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
-  const BytesValue* source =
-    ::google::protobuf::internal::dynamic_cast_if_available<const BytesValue*>(
-      &from);
+  const BytesValue* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const BytesValue>(
+          &from);
   if (source == NULL) {
     ::google::protobuf::internal::ReflectionOps::Merge(from, this);
   } else {
@@ -2367,7 +2367,7 @@
 // BytesValue
 
 // optional bytes value = 1;
- void BytesValue::clear_value() {
+void BytesValue::clear_value() {
   value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
 }
  const ::std::string& BytesValue::value() const {
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index c318f95..387ebd7 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -984,6 +984,22 @@
 }
 
 #endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj
index d1f065e..3474d21 100644
--- a/vsprojects/libprotoc.vcproj
+++ b/vsprojects/libprotoc.vcproj
@@ -296,6 +296,10 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_enum_field_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_extension.h"
         >
       </File>
@@ -324,14 +328,34 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_message.h"
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_lite.h"
+        >
+      </File>
+      <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_builder.h"
+        >
+      </File>
+      <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_builder_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_message_field.h"
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_field_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.h"
         >
       </File>
@@ -340,6 +364,10 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_service.h"
         >
       </File>
@@ -352,6 +380,10 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_string_field_lite.h"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_doc_comment.h"
         >
       </File>
@@ -608,18 +640,42 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_map_field.cc"
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_map_field_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_message.cc"
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_lite.cc"
+        >
+      </File>
+      <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_builder.cc"
+        >
+      </File>
+      <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_builder_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_message_field.cc"
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_message_field_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_name_resolver.cc"
         >
       </File>
@@ -628,6 +684,10 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\java\java_service.cc"
         >
       </File>
@@ -640,6 +700,10 @@
         >
       </File>
       <File
+        RelativePath="..\src\google\protobuf\compiler\java\java_string_field_lite.cc"
+        >
+      </File>
+      <File
         RelativePath="..\src\google\protobuf\compiler\javanano\javanano_enum.cc"
         >
       </File>