Submit recent changes from internal branch. See CHANGES.txt for more details.
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc
index 3413a36..455c239 100644
--- a/src/google/protobuf/compiler/code_generator.cc
+++ b/src/google/protobuf/compiler/code_generator.cc
@@ -42,14 +42,19 @@
 namespace compiler {
 
 CodeGenerator::~CodeGenerator() {}
-OutputDirectory::~OutputDirectory() {}
+GeneratorContext::~GeneratorContext() {}
 
-io::ZeroCopyOutputStream* OutputDirectory::OpenForInsert(
+io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
     const string& filename, const string& insertion_point) {
-  GOOGLE_LOG(FATAL) << "This OutputDirectory does not support insertion.";
+  GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
   return NULL;  // make compiler happy
 }
 
+void GeneratorContext::ListParsedFiles(
+    vector<const FileDescriptor*>* output) {
+  GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
+}
+
 // Parses a set of comma-delimited name/value pairs.
 void ParseGeneratorParameter(const string& text,
                              vector<pair<string, string> >* output) {
diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h
index ea094cd..252f68d 100644
--- a/src/google/protobuf/compiler/code_generator.h
+++ b/src/google/protobuf/compiler/code_generator.h
@@ -53,7 +53,7 @@
 
 // Defined in this file.
 class CodeGenerator;
-class OutputDirectory;
+class GeneratorContext;
 
 // The abstract interface to a class which generates code implementing a
 // particular proto file in a particular language.  A number of these may
@@ -76,7 +76,7 @@
   // the problem (e.g. "invalid parameter") and returns false.
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* generator_context,
                         string* error) const = 0;
 
  private:
@@ -85,11 +85,12 @@
 
 // CodeGenerators generate one or more files in a given directory.  This
 // abstract interface represents the directory to which the CodeGenerator is
-// to write.
-class LIBPROTOC_EXPORT OutputDirectory {
+// to write and other information about the context in which the Generator
+// runs.
+class LIBPROTOC_EXPORT GeneratorContext {
  public:
-  inline OutputDirectory() {}
-  virtual ~OutputDirectory();
+  inline GeneratorContext() {}
+  virtual ~GeneratorContext();
 
   // Opens the given file, truncating it if it exists, and returns a
   // ZeroCopyOutputStream that writes to the file.  The caller takes ownership
@@ -112,10 +113,19 @@
   virtual io::ZeroCopyOutputStream* OpenForInsert(
       const string& filename, const string& insertion_point);
 
+  // Returns a vector of FileDescriptors for all the files being compiled
+  // in this run.  Useful for languages, such as Go, that treat files
+  // differently when compiled as a set rather than individually.
+  virtual void ListParsedFiles(vector<const FileDescriptor*>* output);
+
  private:
-  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory);
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext);
 };
 
+// The type GeneratorContext was once called OutputDirectory. This typedef
+// provides backward compatibility.
+typedef GeneratorContext OutputDirectory;
+
 // Several code generators treat the parameter argument as holding a
 // list of options separated by commas.  This helper function parses
 // a set of comma-delimited name/value pairs: e.g.,
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 02c3e0f..9e9849c 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -48,6 +48,9 @@
 #include <iostream>
 #include <ctype.h>
 
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/plugin.pb.h>
@@ -58,12 +61,10 @@
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/map-util.h>
 #include <google/protobuf/stubs/stl_util-inl.h>
-#include <google/protobuf/stubs/hash.h>
 
 
 namespace google {
@@ -182,7 +183,7 @@
 class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
                                            public io::ErrorCollector {
  public:
-  ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL) 
+  ErrorPrinter(ErrorFormat format, DiskSourceTree *tree = NULL)
     : format_(format), tree_(tree) {}
   ~ErrorPrinter() {}
 
@@ -191,8 +192,8 @@
                 const string& message) {
 
     // Print full path when running under MSVS
-    std::string dfile;
-    if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && 
+    string dfile;
+    if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS &&
         tree_ != NULL &&
         tree_->VirtualFileToDiskFile(filename, &dfile)) {
       cerr << dfile;
@@ -229,12 +230,12 @@
 
 // -------------------------------------------------------------------
 
-// An OutputDirectory implementation that buffers files in memory, then dumps
+// A GeneratorContext implementation that buffers files in memory, then dumps
 // them all to disk on demand.
-class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory {
+class CommandLineInterface::GeneratorContextImpl : public GeneratorContext {
  public:
-  MemoryOutputDirectory();
-  ~MemoryOutputDirectory();
+  GeneratorContextImpl(const vector<const FileDescriptor*>& parsed_files);
+  ~GeneratorContextImpl();
 
   // Write all files in the directory to disk at the given output location,
   // which must end in a '/'.
@@ -248,10 +249,13 @@
   // format, unless one has already been written.
   void AddJarManifest();
 
-  // implements OutputDirectory --------------------------------------
+  // implements GeneratorContext --------------------------------------
   io::ZeroCopyOutputStream* Open(const string& filename);
   io::ZeroCopyOutputStream* OpenForInsert(
       const string& filename, const string& insertion_point);
+  void ListParsedFiles(vector<const FileDescriptor*>* output) {
+    *output = parsed_files_;
+  }
 
  private:
   friend class MemoryOutputStream;
@@ -259,14 +263,15 @@
   // map instead of hash_map so that files are written in order (good when
   // writing zips).
   map<string, string*> files_;
+  const vector<const FileDescriptor*>& parsed_files_;
   bool had_error_;
 };
 
 class CommandLineInterface::MemoryOutputStream
     : public io::ZeroCopyOutputStream {
  public:
-  MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename);
-  MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename,
+  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename);
+  MemoryOutputStream(GeneratorContextImpl* directory, const string& filename,
                      const string& insertion_point);
   virtual ~MemoryOutputStream();
 
@@ -277,7 +282,7 @@
 
  private:
   // Where to insert the string when it's done.
-  MemoryOutputDirectory* directory_;
+  GeneratorContextImpl* directory_;
   string filename_;
   string insertion_point_;
 
@@ -290,14 +295,17 @@
 
 // -------------------------------------------------------------------
 
-CommandLineInterface::MemoryOutputDirectory::MemoryOutputDirectory()
-    : had_error_(false) {}
+CommandLineInterface::GeneratorContextImpl::GeneratorContextImpl(
+    const vector<const FileDescriptor*>& parsed_files)
+    : parsed_files_(parsed_files),
+      had_error_(false) {
+}
 
-CommandLineInterface::MemoryOutputDirectory::~MemoryOutputDirectory() {
+CommandLineInterface::GeneratorContextImpl::~GeneratorContextImpl() {
   STLDeleteValues(&files_);
 }
 
-bool CommandLineInterface::MemoryOutputDirectory::WriteAllToDisk(
+bool CommandLineInterface::GeneratorContextImpl::WriteAllToDisk(
     const string& prefix) {
   if (had_error_) {
     return false;
@@ -372,7 +380,7 @@
   return true;
 }
 
-bool CommandLineInterface::MemoryOutputDirectory::WriteAllToZip(
+bool CommandLineInterface::GeneratorContextImpl::WriteAllToZip(
     const string& filename) {
   if (had_error_) {
     return false;
@@ -413,7 +421,7 @@
   return true;
 }
 
-void CommandLineInterface::MemoryOutputDirectory::AddJarManifest() {
+void CommandLineInterface::GeneratorContextImpl::AddJarManifest() {
   string** map_slot = &files_["META-INF/MANIFEST.MF"];
   if (*map_slot == NULL) {
     *map_slot = new string(
@@ -423,13 +431,13 @@
   }
 }
 
-io::ZeroCopyOutputStream* CommandLineInterface::MemoryOutputDirectory::Open(
+io::ZeroCopyOutputStream* CommandLineInterface::GeneratorContextImpl::Open(
     const string& filename) {
   return new MemoryOutputStream(this, filename);
 }
 
 io::ZeroCopyOutputStream*
-CommandLineInterface::MemoryOutputDirectory::OpenForInsert(
+CommandLineInterface::GeneratorContextImpl::OpenForInsert(
     const string& filename, const string& insertion_point) {
   return new MemoryOutputStream(this, filename, insertion_point);
 }
@@ -437,14 +445,14 @@
 // -------------------------------------------------------------------
 
 CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
-    MemoryOutputDirectory* directory, const string& filename)
+    GeneratorContextImpl* directory, const string& filename)
     : directory_(directory),
       filename_(filename),
       inner_(new io::StringOutputStream(&data_)) {
 }
 
 CommandLineInterface::MemoryOutputStream::MemoryOutputStream(
-    MemoryOutputDirectory* directory, const string& filename,
+    GeneratorContextImpl* directory, const string& filename,
     const string& insertion_point)
     : directory_(directory),
       filename_(filename),
@@ -613,11 +621,11 @@
     }
   }
 
-  // We construct a separate OutputDirectory for each output location.  Note
+  // We construct a separate GeneratorContext for each output location.  Note
   // that two code generators may output to the same location, in which case
-  // they should share a single OutputDirectory (so that OpenForInsert() works).
-  typedef hash_map<string, MemoryOutputDirectory*> OutputDirectoryMap;
-  OutputDirectoryMap output_directories;
+  // they should share a single GeneratorContext so that OpenForInsert() works.
+  typedef hash_map<string, GeneratorContextImpl*> GeneratorContextMap;
+  GeneratorContextMap output_directories;
 
   // Generate output.
   if (mode_ == MODE_COMPILE) {
@@ -627,11 +635,11 @@
           !HasSuffixString(output_location, ".jar")) {
         AddTrailingSlash(&output_location);
       }
-      MemoryOutputDirectory** map_slot = &output_directories[output_location];
+      GeneratorContextImpl** map_slot = &output_directories[output_location];
 
       if (*map_slot == NULL) {
         // First time we've seen this output location.
-        *map_slot = new MemoryOutputDirectory;
+        *map_slot = new GeneratorContextImpl(parsed_files);
       }
 
       if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) {
@@ -642,10 +650,10 @@
   }
 
   // Write all output to disk.
-  for (OutputDirectoryMap::iterator iter = output_directories.begin();
+  for (GeneratorContextMap::iterator iter = output_directories.begin();
        iter != output_directories.end(); ++iter) {
     const string& location = iter->first;
-    MemoryOutputDirectory* directory = iter->second;
+    GeneratorContextImpl* directory = iter->second;
     if (HasSuffixString(location, "/")) {
       if (!directory->WriteAllToDisk(location)) {
         STLDeleteValues(&output_directories);
@@ -1107,7 +1115,7 @@
 bool CommandLineInterface::GenerateOutput(
     const vector<const FileDescriptor*>& parsed_files,
     const OutputDirective& output_directive,
-    OutputDirectory* output_directory) {
+    GeneratorContext* generator_context) {
   // Call the generator.
   string error;
   if (output_directive.generator == NULL) {
@@ -1122,7 +1130,7 @@
 
     if (!GeneratePluginOutput(parsed_files, plugin_name,
                               output_directive.parameter,
-                              output_directory, &error)) {
+                              generator_context, &error)) {
       cerr << output_directive.name << ": " << error << endl;
       return false;
     }
@@ -1131,7 +1139,7 @@
     for (int i = 0; i < parsed_files.size(); i++) {
       if (!output_directive.generator->Generate(
           parsed_files[i], output_directive.parameter,
-          output_directory, &error)) {
+          generator_context, &error)) {
         // Generator returned an error.
         cerr << output_directive.name << ": " << parsed_files[i]->name() << ": "
              << error << endl;
@@ -1147,7 +1155,7 @@
     const vector<const FileDescriptor*>& parsed_files,
     const string& plugin_name,
     const string& parameter,
-    OutputDirectory* output_directory,
+    GeneratorContext* generator_context,
     string* error) {
   CodeGeneratorRequest request;
   CodeGeneratorResponse response;
@@ -1190,14 +1198,14 @@
       // We reset current_output to NULL first so that the old file is closed
       // before the new one is opened.
       current_output.reset();
-      current_output.reset(output_directory->OpenForInsert(
+      current_output.reset(generator_context->OpenForInsert(
           output_file.name(), output_file.insertion_point()));
     } else if (!output_file.name().empty()) {
       // Starting a new file.  Open it.
       // We reset current_output to NULL first so that the old file is closed
       // before the new one is opened.
       current_output.reset();
-      current_output.reset(output_directory->Open(output_file.name()));
+      current_output.reset(generator_context->Open(output_file.name()));
     } else if (current_output == NULL) {
       *error = strings::Substitute(
         "$0: First file chunk returned by plugin did not specify a file name.",
diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h
index d25a50e..0b507d8 100644
--- a/src/google/protobuf/compiler/command_line_interface.h
+++ b/src/google/protobuf/compiler/command_line_interface.h
@@ -56,7 +56,7 @@
 namespace compiler {
 
 class CodeGenerator;        // code_generator.h
-class OutputDirectory;      // code_generator.h
+class GeneratorContext;      // code_generator.h
 class DiskSourceTree;       // importer.h
 
 // This class implements the command-line interface to the protocol compiler.
@@ -174,7 +174,7 @@
   // -----------------------------------------------------------------
 
   class ErrorPrinter;
-  class MemoryOutputDirectory;
+  class GeneratorContextImpl;
   class MemoryOutputStream;
 
   // Clear state from previous Run().
@@ -212,11 +212,11 @@
   struct OutputDirective;  // see below
   bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files,
                       const OutputDirective& output_directive,
-                      OutputDirectory* output_directory);
+                      GeneratorContext* generator_context);
   bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files,
                             const string& plugin_name,
                             const string& parameter,
-                            OutputDirectory* output_directory,
+                            GeneratorContext* generator_context,
                             string* error);
 
   // Implements --encode and --decode.
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index bdf37ad..6634b67 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -143,6 +143,10 @@
                        const string& proto_name,
                        const string& message_name,
                        const string& output_directory);
+  void ExpectGeneratedWithMultipleInputs(const string& generator_name,
+                                         const string& all_proto_names,
+                                         const string& proto_name,
+                                         const string& message_name);
   void ExpectGeneratedWithInsertions(const string& generator_name,
                                      const string& parameter,
                                      const string& insertions,
@@ -190,7 +194,7 @@
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file,
                 const string& parameter,
-                OutputDirectory* output_directory,
+                GeneratorContext* context,
                 string* error) const {
     called_ = true;
     parameter_ = parameter;
@@ -251,7 +255,6 @@
 
   if (!disallow_plugins_) {
     cli_.AllowPlugins("prefix-");
-
     const char* possible_paths[] = {
       // When building with shared libraries, libtool hides the real executable
       // in .libs and puts a fake wrapper in the current directory.
@@ -353,7 +356,8 @@
     const string& proto_name,
     const string& message_name) {
   MockCodeGenerator::ExpectGenerated(
-      generator_name, parameter, "", proto_name, message_name, temp_directory_);
+      generator_name, parameter, "", proto_name, message_name, proto_name,
+      temp_directory_);
 }
 
 void CommandLineInterfaceTest::ExpectGenerated(
@@ -363,10 +367,21 @@
     const string& message_name,
     const string& output_directory) {
   MockCodeGenerator::ExpectGenerated(
-      generator_name, parameter, "", proto_name, message_name,
+      generator_name, parameter, "", proto_name, message_name, proto_name,
       temp_directory_ + "/" + output_directory);
 }
 
+void CommandLineInterfaceTest::ExpectGeneratedWithMultipleInputs(
+    const string& generator_name,
+    const string& all_proto_names,
+    const string& proto_name,
+    const string& message_name) {
+  MockCodeGenerator::ExpectGenerated(
+      generator_name, "", "", proto_name, message_name,
+      all_proto_names,
+      temp_directory_);
+}
+
 void CommandLineInterfaceTest::ExpectGeneratedWithInsertions(
     const string& generator_name,
     const string& parameter,
@@ -375,7 +390,7 @@
     const string& message_name) {
   MockCodeGenerator::ExpectGenerated(
       generator_name, parameter, insertions, proto_name, message_name,
-      temp_directory_);
+      proto_name, temp_directory_);
 }
 
 void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled(
@@ -455,8 +470,44 @@
       "--proto_path=$tmpdir foo.proto bar.proto");
 
   ExpectNoErrors();
-  ExpectGenerated("test_generator", "", "foo.proto", "Foo");
-  ExpectGenerated("test_generator", "", "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+}
+
+TEST_F(CommandLineInterfaceTest, MultipleInputsWithImport) {
+  // Test parsing multiple input files with an import of a separate file.
+
+  CreateTempFile("foo.proto",
+    "syntax = \"proto2\";\n"
+    "message Foo {}\n");
+  CreateTempFile("bar.proto",
+    "syntax = \"proto2\";\n"
+    "import \"baz.proto\";\n"
+    "message Bar {\n"
+    "  optional Baz a = 1;\n"
+    "}\n");
+  CreateTempFile("baz.proto",
+    "syntax = \"proto2\";\n"
+    "message Baz {}\n");
+
+  Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir "
+      "--proto_path=$tmpdir foo.proto bar.proto");
+
+  ExpectNoErrors();
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_generator", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "foo.proto", "Foo");
+  ExpectGeneratedWithMultipleInputs("test_plugin", "foo.proto,bar.proto",
+                                    "bar.proto", "Bar");
 }
 
 TEST_F(CommandLineInterfaceTest, CreateDirectory) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
index 30b1d2b..bcfa502 100644
--- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
@@ -79,10 +79,10 @@
   }
 };
 
-class MockOutputDirectory : public OutputDirectory {
+class MockGeneratorContext : public GeneratorContext {
  public:
-  MockOutputDirectory() {}
-  ~MockOutputDirectory() {
+  MockGeneratorContext() {}
+  ~MockGeneratorContext() {
     STLDeleteValues(&files_);
   }
 
@@ -102,7 +102,7 @@
          "to your CL.";
   }
 
-  // implements OutputDirectory --------------------------------------
+  // implements GeneratorContext --------------------------------------
 
   virtual io::ZeroCopyOutputStream* Open(const string& filename) {
     string** map_slot = &files_[filename];
@@ -130,24 +130,24 @@
   ASSERT_TRUE(plugin_proto_file != NULL);
 
   CppGenerator generator;
-  MockOutputDirectory output_directory;
+  MockGeneratorContext context;
   string error;
   string parameter;
   parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
   ASSERT_TRUE(generator.Generate(proto_file, parameter,
-                                 &output_directory, &error));
+                                 &context, &error));
   parameter = "dllexport_decl=LIBPROTOC_EXPORT";
   ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter,
-                                 &output_directory, &error));
+                                 &context, &error));
 
-  output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h",
-                                     "google/protobuf/descriptor.pb.h");
-  output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc",
-                                     "google/protobuf/descriptor.pb.cc");
-  output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h",
-                                     "google/protobuf/compiler/plugin.pb.h");
-  output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc",
-                                     "google/protobuf/compiler/plugin.pb.cc");
+  context.ExpectFileMatches("google/protobuf/descriptor.pb.h",
+                            "google/protobuf/descriptor.pb.h");
+  context.ExpectFileMatches("google/protobuf/descriptor.pb.cc",
+                            "google/protobuf/descriptor.pb.cc");
+  context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h",
+                            "google/protobuf/compiler/plugin.pb.h");
+  context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc",
+                            "google/protobuf/compiler/plugin.pb.cc");
 }
 
 }  // namespace
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 91ce493..a369f41 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -85,7 +85,7 @@
     "}\n"
     "inline void $classname$::set_$name$($type$ value) {\n"
     "  GOOGLE_DCHECK($type$_IsValid(value));\n"
-    "  _set_bit($index$);\n"
+    "  set_has_$name$();\n"
     "  $name$_ = value;\n"
     "}\n");
 }
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index e31cb42..22d6fdb 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -283,6 +283,7 @@
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "\n"
+
     // The generated code calls accessors that might be deprecated. We don't
     // want the compiler to warn in generated code.
     "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index d67d350..bb84e2a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -53,7 +53,7 @@
 
 bool CppGenerator::Generate(const FileDescriptor* file,
                             const string& parameter,
-                            OutputDirectory* output_directory,
+                            GeneratorContext* generator_context,
                             string* error) const {
   vector<pair<string, string> > options;
   ParseGeneratorParameter(parameter, &options);
@@ -100,7 +100,7 @@
   // Generate header.
   {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      output_directory->Open(basename + ".h"));
+      generator_context->Open(basename + ".h"));
     io::Printer printer(output.get(), '$');
     file_generator.GenerateHeader(&printer);
   }
@@ -108,7 +108,7 @@
   // Generate cc file.
   {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      output_directory->Open(basename + ".cc"));
+      generator_context->Open(basename + ".cc"));
     io::Printer printer(output.get(), '$');
     file_generator.GenerateSource(&printer);
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h
index f52e886..a90e84d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.h
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.h
@@ -57,7 +57,7 @@
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file,
                 const string& parameter,
-                OutputDirectory* output_directory,
+                GeneratorContext* generator_context,
                 string* error) const;
 
  private:
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index cbdcce8..c4e6fb2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -35,6 +35,7 @@
 #include <algorithm>
 #include <google/protobuf/stubs/hash.h>
 #include <map>
+#include <utility>
 #include <vector>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
@@ -143,6 +144,137 @@
   return HasRequiredFields(type, &already_seen);
 }
 
+// This returns an estimate of the compiler's alignment for the field.  This
+// can't guarantee to be correct because the generated code could be compiled on
+// different systems with different alignment rules.  The estimates below assume
+// 64-bit pointers.
+int EstimateAlignmentSize(const FieldDescriptor* field) {
+  if (field == NULL) return 0;
+  if (field->is_repeated()) return 8;
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return 1;
+
+    case FieldDescriptor::CPPTYPE_INT32:
+    case FieldDescriptor::CPPTYPE_UINT32:
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return 4;
+
+    case FieldDescriptor::CPPTYPE_INT64:
+    case FieldDescriptor::CPPTYPE_UINT64:
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return 8;
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return -1;  // Make compiler happy.
+}
+
+// FieldGroup is just a helper for OptimizePadding below.  It holds a vector of
+// fields that are grouped together because they have compatible alignment, and
+// a preferred location in the final field ordering.
+class FieldGroup {
+ public:
+  FieldGroup()
+      : preferred_location_(0) {}
+
+  // A group with a single field.
+  FieldGroup(float preferred_location, const FieldDescriptor* field)
+      : preferred_location_(preferred_location),
+        fields_(1, field) {}
+
+  // Append the fields in 'other' to this group.
+  void Append(const FieldGroup& other) {
+    if (other.fields_.empty()) {
+      return;
+    }
+    // Preferred location is the average among all the fields, so we weight by
+    // the number of fields on each FieldGroup object.
+    preferred_location_ =
+        (preferred_location_ * fields_.size() +
+         (other.preferred_location_ * other.fields_.size())) /
+        (fields_.size() + other.fields_.size());
+    fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end());
+  }
+
+  void SetPreferredLocation(float location) { preferred_location_ = location; }
+  const vector<const FieldDescriptor*>& fields() const { return fields_; }
+
+  // FieldGroup objects sort by their preferred location.
+  bool operator<(const FieldGroup& other) const {
+    return preferred_location_ < other.preferred_location_;
+  }
+
+ private:
+  // "preferred_location_" is an estimate of where this group should go in the
+  // final list of fields.  We compute this by taking the average index of each
+  // field in this group in the original ordering of fields.  This is very
+  // approximate, but should put this group close to where its member fields
+  // originally went.
+  float preferred_location_;
+  vector<const FieldDescriptor*> fields_;
+  // We rely on the default copy constructor and operator= so this type can be
+  // used in a vector.
+};
+
+// Reorder 'fields' so that if the fields are output into a c++ class in the new
+// order, the alignment padding is minimized.  We try to do this while keeping
+// each field as close as possible to its original position so that we don't
+// reduce cache locality much for function that access each field in order.
+void OptimizePadding(vector<const FieldDescriptor*>* fields) {
+  // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes.
+  vector<FieldGroup> aligned_to_1, aligned_to_4, aligned_to_8;
+  for (int i = 0; i < fields->size(); ++i) {
+    switch (EstimateAlignmentSize((*fields)[i])) {
+      case 1: aligned_to_1.push_back(FieldGroup(i, (*fields)[i])); break;
+      case 4: aligned_to_4.push_back(FieldGroup(i, (*fields)[i])); break;
+      case 8: aligned_to_8.push_back(FieldGroup(i, (*fields)[i])); break;
+      default:
+        GOOGLE_LOG(FATAL) << "Unknown alignment size.";
+    }
+  }
+
+  // Now group fields aligned to 1 byte into sets of 4, and treat those like a
+  // single field aligned to 4 bytes.
+  for (int i = 0; i < aligned_to_1.size(); i += 4) {
+    FieldGroup field_group;
+    for (int j = i; j < aligned_to_1.size() && j < i + 4; ++j) {
+      field_group.Append(aligned_to_1[j]);
+    }
+    aligned_to_4.push_back(field_group);
+  }
+  // Sort by preferred location to keep fields as close to their original
+  // location as possible.
+  sort(aligned_to_4.begin(), aligned_to_4.end());
+
+  // Now group fields aligned to 4 bytes (or the 4-field groups created above)
+  // into pairs, and treat those like a single field aligned to 8 bytes.
+  for (int i = 0; i < aligned_to_4.size(); i += 2) {
+    FieldGroup field_group;
+    for (int j = i; j < aligned_to_4.size() && j < i + 2; ++j) {
+      field_group.Append(aligned_to_4[j]);
+    }
+    if (i == aligned_to_4.size() - 1) {
+      // Move incomplete 4-byte block to the end.
+      field_group.SetPreferredLocation(fields->size() + 1);
+    }
+    aligned_to_8.push_back(field_group);
+  }
+  // Sort by preferred location to keep fields as close to their original
+  // location as possible.
+  sort(aligned_to_8.begin(), aligned_to_8.end());
+
+  // Now pull out all the FieldDescriptors in order.
+  fields->clear();
+  for (int i = 0; i < aligned_to_8.size(); ++i) {
+    fields->insert(fields->end(),
+                   aligned_to_8[i].fields().begin(),
+                   aligned_to_8[i].fields().end());
+  }
+}
+
 }
 
 // ===================================================================
@@ -264,10 +396,20 @@
         "}\n");
     } else {
       // Singular field.
+      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_bit($index$);\n"
-        "}\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"
+        );
     }
 
     // Generate clear_$name$()
@@ -279,7 +421,8 @@
     printer->Outdent();
 
     if (!field->is_repeated()) {
-      printer->Print(vars, "  _clear_bit($index$);\n");
+      printer->Print(vars,
+                     "  clear_has_$name$();\n");
     }
 
     printer->Print("}\n");
@@ -444,28 +587,74 @@
     "// @@protoc_insertion_point(class_scope:$full_name$)\n",
     "full_name", descriptor_->full_name());
 
-  // Generate private members for fields.
+  // Generate private members.
   printer->Outdent();
   printer->Print(" private:\n");
   printer->Indent();
 
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    if (!descriptor_->field(i)->is_repeated()) {
+      printer->Print(
+        "inline void set_has_$name$();\n",
+        "name", FieldName(descriptor_->field(i)));
+      printer->Print(
+        "inline void clear_has_$name$();\n",
+        "name", FieldName(descriptor_->field(i)));
+    }
+  }
+  printer->Print("\n");
+
+  // To minimize padding, data members are divided into three sections:
+  // (1) members assumed to align to 8 bytes
+  // (2) members corresponding to message fields, re-ordered to optimize
+  //     alignment.
+  // (3) members assumed to align to 4 bytes.
+
+  // Members assumed to align to 8 bytes:
+
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
-      "::google::protobuf::internal::ExtensionSet _extensions_;\n");
+      "::google::protobuf::internal::ExtensionSet _extensions_;\n"
+      "\n");
   }
 
   if (HasUnknownFields(descriptor_->file())) {
     printer->Print(
-      "::google::protobuf::UnknownFieldSet _unknown_fields_;\n");
+      "::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
+      "\n");
   }
 
+  // Field members:
+
+  vector<const FieldDescriptor*> fields;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    fields.push_back(descriptor_->field(i));
+  }
+  OptimizePadding(&fields);
+  for (int i = 0; i < fields.size(); ++i) {
+    field_generators_.get(fields[i]).GeneratePrivateMembers(printer);
+  }
+
+  // Members assumed to align to 4 bytes:
+
   // TODO(kenton):  Make _cached_size_ an atomic<int> when C++ supports it.
   printer->Print(
-    "mutable int _cached_size_;\n"
-    "\n");
-  for (int i = 0; i < descriptor_->field_count(); i++) {
-    field_generators_.get(descriptor_->field(i))
-                     .GeneratePrivateMembers(printer);
+      "\n"
+      "mutable int _cached_size_;\n");
+
+  // Generate _has_bits_.
+  if (descriptor_->field_count() > 0) {
+    printer->Print(vars,
+      "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n"
+      "\n");
+  } else {
+    // Zero-size arrays aren't technically allowed, and MSVC in particular
+    // doesn't like them.  We still need to declare these arrays to make
+    // other code compile.  Since this is an uncommon case, we'll just declare
+    // them with size 1 and waste some space.  Oh well.
+    printer->Print(
+      "::google::protobuf::uint32 _has_bits_[1];\n"
+      "\n");
   }
 
   // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as
@@ -484,32 +673,7 @@
       GlobalAssignDescriptorsName(descriptor_->file()->name()),
     "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name()));
 
-  // Generate offsets and _has_bits_ boilerplate.
-  if (descriptor_->field_count() > 0) {
-    printer->Print(vars,
-      "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n");
-  } else {
-    // Zero-size arrays aren't technically allowed, and MSVC in particular
-    // doesn't like them.  We still need to declare these arrays to make
-    // other code compile.  Since this is an uncommon case, we'll just declare
-    // them with size 1 and waste some space.  Oh well.
-    printer->Print(
-      "::google::protobuf::uint32 _has_bits_[1];\n");
-  }
-
   printer->Print(
-    "\n"
-    "// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?\n"
-    "inline bool _has_bit(int index) const {\n"
-    "  return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;\n"
-    "}\n"
-    "inline void _set_bit(int index) {\n"
-    "  _has_bits_[index / 32] |= (1u << (index % 32));\n"
-    "}\n"
-    "inline void _clear_bit(int index) {\n"
-    "  _has_bits_[index / 32] &= ~(1u << (index % 32));\n"
-    "}\n"
-    "\n"
     "void InitAsDefaultInstance();\n"
     "static $classname$* default_instance_;\n",
     "classname", classname_);
@@ -961,9 +1125,6 @@
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (!field->is_repeated()) {
-      map<string, string> vars;
-      vars["index"] = SimpleItoa(field->index());
-
       // We can use the fact that _has_bits_ is a giant bitfield to our
       // advantage:  We can check up to 32 bits at a time for equality to
       // zero, and skip the whole range if so.  This can improve the speed
@@ -975,8 +1136,9 @@
           printer->Outdent();
           printer->Print("}\n");
         }
-        printer->Print(vars,
-          "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
+        printer->Print(
+          "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
+          "index", SimpleItoa(field->index()));
         printer->Indent();
       }
       last_index = i;
@@ -989,7 +1151,9 @@
         field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
 
       if (should_check_bit) {
-        printer->Print(vars, "if (_has_bit($index$)) {\n");
+        printer->Print(
+          "if (has_$name$()) {\n",
+          "name", FieldName(field));
         printer->Indent();
       }
 
@@ -1129,24 +1293,23 @@
     const FieldDescriptor* field = descriptor_->field(i);
 
     if (!field->is_repeated()) {
-      map<string, string> vars;
-      vars["index"] = SimpleItoa(field->index());
-
       // See above in GenerateClear for an explanation of this.
       if (i / 8 != last_index / 8 || last_index < 0) {
         if (last_index >= 0) {
           printer->Outdent();
           printer->Print("}\n");
         }
-        printer->Print(vars,
-          "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n");
+        printer->Print(
+          "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
+          "index", SimpleItoa(field->index()));
         printer->Indent();
       }
 
       last_index = i;
 
-      printer->Print(vars,
-        "if (from._has_bit($index$)) {\n");
+      printer->Print(
+        "if (from.has_$name$()) {\n",
+        "name", FieldName(field));
       printer->Indent();
 
       field_generators_.get(field).GenerateMergingCode(printer);
@@ -1423,8 +1586,8 @@
 
   if (!field->is_repeated()) {
     printer->Print(
-      "if (_has_bit($index$)) {\n",
-      "index", SimpleItoa(field->index()));
+      "if (has_$name$()) {\n",
+      "name", FieldName(field));
     printer->Indent();
   }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index c04bdc6..23e75b8 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -75,7 +75,8 @@
 GenerateAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
     "inline const $type$& $name$() const$deprecation$;\n"
-    "inline $type$* mutable_$name$()$deprecation$;\n");
+    "inline $type$* mutable_$name$()$deprecation$;\n"
+    "inline $type$* release_$name$()$deprecation$;\n");
 }
 
 void MessageFieldGenerator::
@@ -85,9 +86,15 @@
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n"
     "}\n"
     "inline $type$* $classname$::mutable_$name$() {\n"
-    "  _set_bit($index$);\n"
+    "  set_has_$name$();\n"
     "  if ($name$_ == NULL) $name$_ = new $type$;\n"
     "  return $name$_;\n"
+    "}\n"
+    "inline $type$* $classname$::release_$name$() {\n"
+    "  clear_has_$name$();\n"
+    "  $type$* temp = $name$_;\n"
+    "  $name$_ = NULL;\n"
+    "  return temp;\n"
     "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 440b716..5c4aa4f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -56,24 +56,24 @@
 
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* context,
                         string* error) const {
-    TryInsert("test.pb.h", "includes", output_directory);
-    TryInsert("test.pb.h", "namespace_scope", output_directory);
-    TryInsert("test.pb.h", "global_scope", output_directory);
-    TryInsert("test.pb.h", "class_scope:foo.Bar", output_directory);
-    TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", output_directory);
+    TryInsert("test.pb.h", "includes", context);
+    TryInsert("test.pb.h", "namespace_scope", context);
+    TryInsert("test.pb.h", "global_scope", context);
+    TryInsert("test.pb.h", "class_scope:foo.Bar", context);
+    TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context);
 
-    TryInsert("test.pb.cc", "includes", output_directory);
-    TryInsert("test.pb.cc", "namespace_scope", output_directory);
-    TryInsert("test.pb.cc", "global_scope", output_directory);
+    TryInsert("test.pb.cc", "includes", context);
+    TryInsert("test.pb.cc", "namespace_scope", context);
+    TryInsert("test.pb.cc", "global_scope", context);
     return true;
   }
 
   void TryInsert(const string& filename, const string& insertion_point,
-                 OutputDirectory* output_directory) const {
+                 GeneratorContext* context) const {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      output_directory->OpenForInsert(filename, insertion_point));
+      context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
   }
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index a69c48b..5e8df0f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -125,7 +125,7 @@
     "  return $name$_;\n"
     "}\n"
     "inline void $classname$::set_$name$($type$ value) {\n"
-    "  _set_bit($index$);\n"
+    "  set_has_$name$();\n"
     "  $name$_ = value;\n"
     "}\n");
 }
@@ -156,7 +156,7 @@
     "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
     "         $type$, $wire_format_field_type$>(\n"
     "       input, &$name$_)));\n"
-    "_set_bit($index$);\n");
+    "set_has_$name$();\n");
 }
 
 void PrimitiveFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index ea6809a..67d7eae 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -50,6 +50,9 @@
   SetCommonFieldVariables(descriptor, variables);
   (*variables)["default"] =
     "\"" + CEscape(descriptor->default_value_string()) + "\"";
+  (*variables)["default_variable"] = descriptor->default_value_string().empty()
+      ? "::google::protobuf::internal::kEmptyString"
+      : "_default_" + FieldName(descriptor) + "_";
   (*variables)["pointer_type"] =
       descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
 }
@@ -68,9 +71,10 @@
 
 void StringFieldGenerator::
 GeneratePrivateMembers(io::Printer* printer) const {
-  printer->Print(variables_,
-    "::std::string* $name$_;\n"
-    "static const ::std::string _default_$name$_;\n");
+  printer->Print(variables_, "::std::string* $name$_;\n");
+  if (!descriptor_->default_value_string().empty()) {
+    printer->Print(variables_, "static const ::std::string $default_variable$;\n");
+  }
 }
 
 void StringFieldGenerator::
@@ -105,7 +109,8 @@
     "inline void set_$name$(const char* value)$deprecation$;\n"
     "inline void set_$name$(const $pointer_type$* value, size_t size)"
                  "$deprecation$;\n"
-    "inline ::std::string* mutable_$name$()$deprecation$;\n");
+    "inline ::std::string* mutable_$name$()$deprecation$;\n"
+    "inline ::std::string* release_$name$()$deprecation$;\n");
 
   if (descriptor_->options().ctype() != FieldOptions::STRING) {
     printer->Outdent();
@@ -121,51 +126,58 @@
     "  return *$name$_;\n"
     "}\n"
     "inline void $classname$::set_$name$(const ::std::string& value) {\n"
-    "  _set_bit($index$);\n"
-    "  if ($name$_ == &_default_$name$_) {\n"
+    "  set_has_$name$();\n"
+    "  if ($name$_ == &$default_variable$) {\n"
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(value);\n"
     "}\n"
     "inline void $classname$::set_$name$(const char* value) {\n"
-    "  _set_bit($index$);\n"
-    "  if ($name$_ == &_default_$name$_) {\n"
+    "  set_has_$name$();\n"
+    "  if ($name$_ == &$default_variable$) {\n"
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(value);\n"
     "}\n"
     "inline "
     "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
-    "  _set_bit($index$);\n"
-    "  if ($name$_ == &_default_$name$_) {\n"
+    "  set_has_$name$();\n"
+    "  if ($name$_ == &$default_variable$) {\n"
     "    $name$_ = new ::std::string;\n"
     "  }\n"
     "  $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
     "}\n"
     "inline ::std::string* $classname$::mutable_$name$() {\n"
-    "  _set_bit($index$);\n"
-    "  if ($name$_ == &_default_$name$_) {\n");
+    "  set_has_$name$();\n"
+    "  if ($name$_ == &$default_variable$) {\n");
   if (descriptor_->default_value_string().empty()) {
     printer->Print(variables_,
       "    $name$_ = new ::std::string;\n");
   } else {
     printer->Print(variables_,
-      "    $name$_ = new ::std::string(_default_$name$_);\n");
+      "    $name$_ = new ::std::string($default_variable$);\n");
   }
   printer->Print(variables_,
     "  }\n"
     "  return $name$_;\n"
+    "}\n"
+    "inline ::std::string* $classname$::release_$name$() {\n"
+    "  clear_has_$name$();\n"
+    "  if ($name$_ == &$default_variable$) {\n"
+    "    return NULL;\n"
+    "  } else {\n"
+    "    ::std::string* temp = $name$_;\n"
+    "    $name$_ = const_cast< ::std::string*>(&$default_variable$);\n"
+    "    return temp;\n"
+    "  }\n"
     "}\n");
 }
 
 void StringFieldGenerator::
 GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
-  if (descriptor_->default_value_string().empty()) {
+  if (!descriptor_->default_value_string().empty()) {
     printer->Print(variables_,
-      "const ::std::string $classname$::_default_$name$_;\n");
-  } else {
-    printer->Print(variables_,
-      "const ::std::string $classname$::_default_$name$_($default$);\n");
+      "const ::std::string $classname$::$default_variable$($default$);\n");
   }
 }
 
@@ -173,13 +185,13 @@
 GenerateClearingCode(io::Printer* printer) const {
   if (descriptor_->default_value_string().empty()) {
     printer->Print(variables_,
-      "if ($name$_ != &_default_$name$_) {\n"
+      "if ($name$_ != &$default_variable$) {\n"
       "  $name$_->clear();\n"
       "}\n");
   } else {
     printer->Print(variables_,
-      "if ($name$_ != &_default_$name$_) {\n"
-      "  $name$_->assign(_default_$name$_);\n"
+      "if ($name$_ != &$default_variable$) {\n"
+      "  $name$_->assign($default_variable$);\n"
       "}\n");
   }
 }
@@ -197,13 +209,13 @@
 void StringFieldGenerator::
 GenerateConstructorCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$_ = const_cast< ::std::string*>(&_default_$name$_);\n");
+    "$name$_ = const_cast< ::std::string*>(&$default_variable$);\n");
 }
 
 void StringFieldGenerator::
 GenerateDestructorCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if ($name$_ != &_default_$name$_) {\n"
+    "if ($name$_ != &$default_variable$) {\n"
     "  delete $name$_;\n"
     "}\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 79971a9..54d830f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -36,6 +36,10 @@
 // though the same identifiers are used internally by the C++ code generator.
 
 
+// Some generic_services option(s) added automatically.
+// See:  http://go/proto2-generic-services-default
+option cc_generic_services = true;     // auto-added
+
 // We don't put this in a package within proto2 because we need to make sure
 // that the generated code doesn't depend on being in the proto2 namespace.
 package protobuf_unittest;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index a7e852d..41ba5e4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -195,6 +195,48 @@
   EXPECT_EQ("hello", *message.mutable_default_string());
 }
 
+TEST(GeneratedMessageTest, ReleaseString) {
+  // Check that release_foo() starts out NULL, and gives us a value
+  // that we can delete after it's been set.
+  unittest::TestAllTypes message;
+
+  EXPECT_EQ(NULL, message.release_default_string());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_EQ("hello", message.default_string());
+
+  message.set_default_string("blah");
+  EXPECT_TRUE(message.has_default_string());
+  string* str = message.release_default_string();
+  EXPECT_FALSE(message.has_default_string());
+  ASSERT_TRUE(str != NULL);
+  EXPECT_EQ("blah", *str);
+  delete str;
+
+  EXPECT_EQ(NULL, message.release_default_string());
+  EXPECT_FALSE(message.has_default_string());
+  EXPECT_EQ("hello", message.default_string());
+}
+
+TEST(GeneratedMessageTest, ReleaseMessage) {
+  // Check that release_foo() starts out NULL, and gives us a value
+  // that we can delete after it's been set.
+  unittest::TestAllTypes message;
+
+  EXPECT_EQ(NULL, message.release_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_nested_message());
+
+  message.mutable_optional_nested_message()->set_bb(1);
+  unittest::TestAllTypes::NestedMessage* nest =
+      message.release_optional_nested_message();
+  EXPECT_FALSE(message.has_optional_nested_message());
+  ASSERT_TRUE(nest != NULL);
+  EXPECT_EQ(1, nest->bb());
+  delete nest;
+
+  EXPECT_EQ(NULL, message.release_optional_nested_message());
+  EXPECT_FALSE(message.has_optional_nested_message());
+}
+
 TEST(GeneratedMessageTest, Clear) {
   // Set every field to a unique value, clear the message, then check that
   // it is cleared.
@@ -282,6 +324,7 @@
   TestUtil::ExpectAllFieldsSet(message2);
 }
 
+
 TEST(GeneratedMessageTest, SwapWithEmpty) {
   unittest::TestAllTypes message1, message2;
   TestUtil::SetAllFields(&message1);
@@ -376,7 +419,7 @@
   TestUtil::ExpectAllFieldsSet(message2);
 
   // Make sure that self-assignment does something sane.
-  message2 = message2;
+  message2.operator=(message2);
   TestUtil::ExpectAllFieldsSet(message2);
 }
 
@@ -718,6 +761,7 @@
 
 #endif  // !PROTOBUF_TEST_NO_DESCRIPTORS
 
+
 TEST(GeneratedMessageTest, FieldConstantValues) {
   unittest::TestRequired message;
   EXPECT_EQ(unittest::TestAllTypes_NestedMessage::kBbFieldNumber, 1);
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index e796587..9d7bcab 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -104,6 +104,15 @@
       "public static final $classname$ $name$ = $canonical_name$;\n");
   }
 
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    map<string, string> vars;
+    vars["name"] = descriptor_->value(i)->name();
+    vars["number"] = SimpleItoa(descriptor_->value(i)->number());
+    printer->Print(vars,
+      "public static final int $name$_VALUE = $number$;\n");
+  }
+  printer->Print("\n");
+
   // -----------------------------------------------------------------
 
   printer->Print(
@@ -219,17 +228,6 @@
     "  this.value = value;\n"
     "}\n");
 
-  if (HasDescriptorMethods(descriptor_)) {
-    // Force the static initialization code for the file to run, since it may
-    // initialize static variables declared in this class.
-    printer->Print(
-      "\n"
-      "static {\n"
-      "  $file$.getDescriptor();\n"
-      "}\n",
-      "file", ClassName(descriptor_->file()));
-  }
-
   printer->Print(
     "\n"
     "// @@protoc_insertion_point(enum_scope:$full_name$)\n",
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index af6b1cd..72caa10 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -52,17 +52,44 @@
 // TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
 //   repeat code between this and the other field types.
 void SetEnumVariables(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex,
                       map<string, string>* variables) {
   (*variables)["name"] =
     UnderscoresToCamelCase(descriptor);
   (*variables)["capitalized_name"] =
     UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["constant_name"] = FieldConstantName(descriptor);
   (*variables)["number"] = SimpleItoa(descriptor->number());
   (*variables)["type"] = ClassName(descriptor->enum_type());
   (*variables)["default"] = DefaultValue(descriptor);
   (*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();" : "";
+
+  // For singular messages and builders, one bit is used for the hasField bit.
+  (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+  (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_has_field_bit_builder"] =
+      GenerateClearBit(builderBitIndex);
+
+  // For repated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
 }
 
 }  // namespace
@@ -70,52 +97,88 @@
 // ===================================================================
 
 EnumFieldGenerator::
-EnumFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetEnumVariables(descriptor, &variables_);
+EnumFieldGenerator(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
 }
 
 EnumFieldGenerator::~EnumFieldGenerator() {}
 
+int EnumFieldGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int EnumFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void EnumFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$boolean has$capitalized_name$();\n"
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
 void EnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private boolean has$capitalized_name$;\n"
     "private $type$ $name$_;\n"
-    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
-    "public $type$ get$capitalized_name$() { return $name$_; }\n");
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n"
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
 }
 
 void EnumFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "public boolean has$capitalized_name$() {\n"
-    "  return result.has$capitalized_name$();\n"
+    "private $type$ $name$_ = $default$;\n"
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_builder$;\n"
     "}\n"
-    "public $type$ get$capitalized_name$() {\n"
-    "  return result.get$capitalized_name$();\n"
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
     "}\n"
-    "public Builder set$capitalized_name$($type$ value) {\n"
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
     "  if (value == null) {\n"
     "    throw new NullPointerException();\n"
     "  }\n"
-    "  result.has$capitalized_name$ = true;\n"
-    "  result.$name$_ = value;\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $name$_ = value;\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.has$capitalized_name$ = false;\n"
-    "  result.$name$_ = $default$;\n"
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_builder$;\n"
+    "  $name$_ = $default$;\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n");
 }
 
 void EnumFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void EnumFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
   printer->Print(variables_, "$name$_ = $default$;\n");
 }
 
 void EnumFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+      "$name$_ = $default$;\n"
+      "$clear_has_field_bit_builder$;\n");
+}
+
+void EnumFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (other.has$capitalized_name$()) {\n"
@@ -125,7 +188,11 @@
 
 void EnumFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
-  // Nothing to do here for enum types.
+  printer->Print(variables_,
+    "if ($get_has_field_bit_from_local$) {\n"
+    "  $set_has_field_bit_to_local$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
 }
 
 void EnumFieldGenerator::
@@ -143,27 +210,42 @@
       "if (value != null) {\n");
   }
   printer->Print(variables_,
-    "  set$capitalized_name$(value);\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $name$_ = value;\n"
     "}\n");
 }
 
 void EnumFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
-    "  output.writeEnum($number$, get$capitalized_name$().getNumber());\n"
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.writeEnum($number$, $name$_.getNumber());\n"
     "}\n");
 }
 
 void EnumFieldGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
+    "if ($get_has_field_bit_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSize($number$, get$capitalized_name$().getNumber());\n"
+    "    .computeEnumSize($number$, $name$_.getNumber());\n"
     "}\n");
 }
 
+void EnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result &&\n"
+    "    (get$capitalized_name$() == other.get$capitalized_name$());\n");
+}
+
+void EnumFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + hashEnum(get$capitalized_name$());\n");
+}
+
 string EnumFieldGenerator::GetBoxedType() const {
   return ClassName(descriptor_->enum_type());
 }
@@ -171,23 +253,43 @@
 // ===================================================================
 
 RepeatedEnumFieldGenerator::
-RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetEnumVariables(descriptor, &variables_);
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_);
 }
 
 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
 
+int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"
+    "$deprecation$int get$capitalized_name$Count();\n"
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+}
+
 void RepeatedEnumFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.util.List<$type$> $name$_ =\n"
-    "  java.util.Collections.emptyList();\n"
-    "public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "private java.util.List<$type$> $name$_;\n"
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
     "  return $name$_;\n"   // note:  unmodifiable list
     "}\n"
-    "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n"
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
     "  return $name$_.get(index);\n"
     "}\n");
 
@@ -201,73 +303,119 @@
 void RepeatedEnumFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(variables_,
+    // One field is the list and the other field keeps track of whether the
+    // list is immutable. If it's immutable, the invariant is that it must
+    // either an instance of Collections.emptyList() or it's an ArrayList
+    // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+    // a refererence to the underlying ArrayList. This invariant allows us to
+    // share instances of lists between protocol buffers avoiding expensive
+    // memory allocations. Note, immutable is a strong guarantee here -- not
+    // just that the list cannot be modified via the reference but that the
+    // list can never be modified.
+    "private java.util.List<$type$> $name$_ =\n"
+    "  java.util.Collections.emptyList();\n"
+
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$get_mutable_bit_builder$) {\n"
+    "    $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
+    "    $set_mutable_bit_builder$;\n"
+    "  }\n"
+    "}\n"
+
     // Note:  We return an unmodifiable list because otherwise the caller
     //   could hold on to the returned list and modify it after the message
     //   has been built, thus mutating the message which is supposed to be
     //   immutable.
-    "public java.util.List<$type$> get$capitalized_name$List() {\n"
-    "  return java.util.Collections.unmodifiableList(result.$name$_);\n"
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList($name$_);\n"
     "}\n"
-    "public int get$capitalized_name$Count() {\n"
-    "  return result.get$capitalized_name$Count();\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
     "}\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
-    "  return result.get$capitalized_name$(index);\n"
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
     "}\n"
-    "public Builder set$capitalized_name$(int index, $type$ value) {\n"
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
     "  if (value == null) {\n"
     "    throw new NullPointerException();\n"
     "  }\n"
-    "  result.$name$_.set(index, value);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder add$capitalized_name$($type$ value) {\n"
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
     "  if (value == null) {\n"
     "    throw new NullPointerException();\n"
     "  }\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
-    "  }\n"
-    "  result.$name$_.add(value);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder addAll$capitalized_name$(\n"
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
     "    java.lang.Iterable<? extends $type$> values) {\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
-    "  }\n"
-    "  super.addAll(values, result.$name$_);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  super.addAll(values, $name$_);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.$name$_ = java.util.Collections.emptyList();\n"
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $name$_ = java.util.Collections.emptyList();\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n");
 }
 
 void RepeatedEnumFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for enums
+}
+
+void RepeatedEnumFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  // Initialized inline.
+  printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = java.util.Collections.emptyList();\n"
+    "$clear_mutable_bit_builder$;\n");
 }
 
 void RepeatedEnumFieldGenerator::
 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 (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "    $clear_mutable_bit_builder$;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  result.$name$_.addAll(other.$name$_);\n"
+    "  $on_changed$\n"
     "}\n");
 }
 
 void RepeatedEnumFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
   printer->Print(variables_,
-    "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
-    "  result.$name$_ =\n"
-    "    java.util.Collections.unmodifiableList(result.$name$_);\n"
-    "}\n");
+    "if ($get_mutable_bit_builder$) {\n"
+    "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
 }
 
 void RepeatedEnumFieldGenerator::
@@ -316,13 +464,13 @@
       "  output.writeRawVarint32($tag$);\n"
       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
       "}\n"
-      "for ($type$ element : get$capitalized_name$List()) {\n"
-      "  output.writeEnumNoTag(element.getNumber());\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnumNoTag($name$_.get(i).getNumber());\n"
       "}\n");
   } else {
     printer->Print(variables_,
-      "for ($type$ element : get$capitalized_name$List()) {\n"
-      "  output.writeEnum($number$, element.getNumber());\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.writeEnum($number$, $name$_.get(i).getNumber());\n"
       "}\n");
   }
 }
@@ -335,9 +483,9 @@
   printer->Indent();
 
   printer->Print(variables_,
-    "for ($type$ element : get$capitalized_name$List()) {\n"
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
     "  dataSize += com.google.protobuf.CodedOutputStream\n"
-    "    .computeEnumSizeNoTag(element.getNumber());\n"
+    "    .computeEnumSizeNoTag($name$_.get(i).getNumber());\n"
     "}\n");
   printer->Print(
     "size += dataSize;\n");
@@ -350,7 +498,7 @@
       "}");
   } else {
     printer->Print(variables_,
-      "size += $tag_size$ * get$capitalized_name$List().size();\n");
+      "size += $tag_size$ * $name$_.size();\n");
   }
 
   // cache the data size for packed fields.
@@ -363,6 +511,22 @@
   printer->Print("}\n");
 }
 
+void RepeatedEnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (get$capitalized_name$Count() > 0) {\n"
+    "  hash = (37 * hash) + $constant_name$;\n"
+    "  hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n"
+    "}\n");
+}
+
 string RepeatedEnumFieldGenerator::GetBoxedType() const {
   return ClassName(descriptor_->enum_type());
 }
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index c54a0fa..0cad6be 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -46,49 +46,69 @@
 
 class EnumFieldGenerator : public FieldGenerator {
  public:
-  explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
+  explicit EnumFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~EnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
 };
 
 class RepeatedEnumFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~RepeatedEnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(io::Printer* printer) const;
   void GenerateParsingCodeFromPacked(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
 };
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 903b0a9..9b147c7 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -86,105 +86,120 @@
 
 ExtensionGenerator::~ExtensionGenerator() {}
 
-void ExtensionGenerator::Generate(io::Printer* printer) {
-  map<string, string> vars;
-  vars["name"] = UnderscoresToCamelCase(descriptor_);
-  vars["containing_type"] = ClassName(descriptor_->containing_type());
-  vars["number"] = SimpleItoa(descriptor_->number());
-  vars["constant_name"] = FieldConstantName(descriptor_);
-  vars["lite"] = HasDescriptorMethods(descriptor_->file()) ? "" : "Lite";
-
-  JavaType java_type = GetJavaType(descriptor_);
-  string singular_type;
-  switch (java_type) {
-    case JAVATYPE_MESSAGE:
-      vars["type"] = ClassName(descriptor_->message_type());
-      break;
-    case JAVATYPE_ENUM:
-      vars["type"] = ClassName(descriptor_->enum_type());
-      break;
-    default:
-      vars["type"] = BoxedPrimitiveTypeName(java_type);
-      break;
-  }
-
-  printer->Print(vars,
-    "public static final int $constant_name$ = $number$;\n");
-  if (descriptor_->is_repeated()) {
-    printer->Print(vars,
-      "public static final\n"
-      "  com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
-      "    $containing_type$,\n"
-      "    java.util.List<$type$>> $name$ =\n"
-      "      com.google.protobuf.GeneratedMessage$lite$\n"
-      "        .newGeneratedExtension();\n");
-  } else {
-    printer->Print(vars,
-      "public static final\n"
-      "  com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n"
-      "    $containing_type$,\n"
-      "    $type$> $name$ =\n"
-      "      com.google.protobuf.GeneratedMessage$lite$\n"
-      "        .newGeneratedExtension();\n");
-  }
-}
-
-void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) {
-  map<string, string> vars;
-  vars["name"] = UnderscoresToCamelCase(descriptor_);
-  vars["scope"] = scope_;
-  vars["index"] = SimpleItoa(descriptor_->index());
-  vars["extendee"] = ClassName(descriptor_->containing_type());
-  vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_);
-  vars["number"] = SimpleItoa(descriptor_->number());
-  vars["type_constant"] = TypeName(GetType(descriptor_));
-  vars["packed"] = descriptor_->options().packed() ? "true" : "false";
+// Initializes the vars referenced in the generated code templates.
+void InitTemplateVars(const FieldDescriptor* descriptor,
+                      const string& scope,
+                      map<string, string>* vars_pointer) {
+  map<string, string> &vars = *vars_pointer;
+  vars["scope"] = scope;
+  vars["name"] = UnderscoresToCamelCase(descriptor);
+  vars["containing_type"] = ClassName(descriptor->containing_type());
+  vars["number"] = SimpleItoa(descriptor->number());
+  vars["constant_name"] = FieldConstantName(descriptor);
+  vars["index"] = SimpleItoa(descriptor->index());
+  vars["default"] =
+      descriptor->is_repeated() ? "" : DefaultValue(descriptor);
+  vars["type_constant"] = TypeName(GetType(descriptor));
+  vars["packed"] = descriptor->options().packed() ? "true" : "false";
   vars["enum_map"] = "null";
   vars["prototype"] = "null";
 
-  JavaType java_type = GetJavaType(descriptor_);
+  JavaType java_type = GetJavaType(descriptor);
   string singular_type;
   switch (java_type) {
     case JAVATYPE_MESSAGE:
-      vars["type"] = ClassName(descriptor_->message_type());
-      vars["prototype"] = ClassName(descriptor_->message_type()) +
-                          ".getDefaultInstance()";
+      singular_type = ClassName(descriptor->message_type());
+      vars["prototype"] = singular_type + ".getDefaultInstance()";
       break;
     case JAVATYPE_ENUM:
-      vars["type"] = ClassName(descriptor_->enum_type());
-      vars["enum_map"] = ClassName(descriptor_->enum_type()) +
-                         ".internalGetValueMap()";
+      singular_type = ClassName(descriptor->enum_type());
+      vars["enum_map"] = singular_type + ".internalGetValueMap()";
       break;
     default:
-      vars["type"] = BoxedPrimitiveTypeName(java_type);
+      singular_type = BoxedPrimitiveTypeName(java_type);
       break;
   }
+  vars["type"] = descriptor->is_repeated() ?
+      "java.util.List<" + singular_type + ">" : singular_type;
+  vars["singular_type"] = singular_type;
+}
+
+void ExtensionGenerator::Generate(io::Printer* printer) {
+  map<string, string> vars;
+  InitTemplateVars(descriptor_, scope_, &vars);
+  printer->Print(vars,
+      "public static final int $constant_name$ = $number$;\n");
 
   if (HasDescriptorMethods(descriptor_->file())) {
-    printer->Print(vars,
-      "$scope$.$name$.internalInit(\n"
-      "    $scope$.getDescriptor().getExtensions().get($index$),\n"
-      "    $type$.class);\n");
-  } else {
-    if (descriptor_->is_repeated()) {
-      printer->Print(vars,
-        "$scope$.$name$.internalInitRepeated(\n"
-        "    $extendee$.getDefaultInstance(),\n"
-        "    $prototype$,\n"
-        "    $enum_map$,\n"
-        "    $number$,\n"
-        "    com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
-        "    $packed$);\n");
+    // Non-lite extensions
+    if (descriptor_->extension_scope() == NULL) {
+      // Non-nested
+      printer->Print(
+          vars,
+          "public static final\n"
+          "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+          "    $containing_type$,\n"
+          "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+          "        .newFileScopedGeneratedExtension(\n"
+          "      $singular_type$.class,\n"
+          "      $prototype$);\n");
     } else {
-      printer->Print(vars,
-        "$scope$.$name$.internalInitSingular(\n"
-        "    $extendee$.getDefaultInstance(),\n"
-        "    $default$,\n"
-        "    $prototype$,\n"
-        "    $enum_map$,\n"
-        "    $number$,\n"
-        "    com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
+      // Nested
+      printer->Print(
+          vars,
+          "public static final\n"
+          "  com.google.protobuf.GeneratedMessage.GeneratedExtension<\n"
+          "    $containing_type$,\n"
+          "    $type$> $name$ = com.google.protobuf.GeneratedMessage\n"
+          "        .newMessageScopedGeneratedExtension(\n"
+          "      $scope$.getDefaultInstance(),\n"
+          "      $index$,\n"
+          "      $singular_type$.class,\n"
+          "      $prototype$);\n");
     }
+  } else {
+    // Lite extensions
+    if (descriptor_->is_repeated()) {
+      printer->Print(
+          vars,
+          "public static final\n"
+          "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+          "    $containing_type$,\n"
+          "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+          "        .newRepeatedGeneratedExtension(\n"
+          "      $containing_type$.getDefaultInstance(),\n"
+          "      $prototype$,\n"
+          "      $enum_map$,\n"
+          "      $number$,\n"
+          "      com.google.protobuf.WireFormat.FieldType.$type_constant$,\n"
+          "      $packed$);\n");
+    } else {
+      printer->Print(
+          vars,
+          "public static final\n"
+          "  com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n"
+          "    $containing_type$,\n"
+          "    $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n"
+          "        .newSingularGeneratedExtension(\n"
+          "      $containing_type$.getDefaultInstance(),\n"
+          "      $default$,\n"
+          "      $prototype$,\n"
+          "      $enum_map$,\n"
+          "      $number$,\n"
+          "      com.google.protobuf.WireFormat.FieldType.$type_constant$);\n");
+    }
+  }
+}
+
+void ExtensionGenerator::GenerateNonNestedInitializationCode(
+    io::Printer* printer) {
+  if (descriptor_->extension_scope() == NULL &&
+      HasDescriptorMethods(descriptor_->file())) {
+    // Only applies to non-nested, non-lite extensions.
+    printer->Print(
+        "$name$.internalInit(descriptor.getExtensions().get($index$));\n",
+        "name", UnderscoresToCamelCase(descriptor_),
+        "index", SimpleItoa(descriptor_->index()));
   }
 }
 
diff --git a/src/google/protobuf/compiler/java/java_extension.h b/src/google/protobuf/compiler/java/java_extension.h
index 1e42304..009ed9f 100644
--- a/src/google/protobuf/compiler/java/java_extension.h
+++ b/src/google/protobuf/compiler/java/java_extension.h
@@ -60,7 +60,7 @@
   ~ExtensionGenerator();
 
   void Generate(io::Printer* printer);
-  void GenerateInitializationCode(io::Printer* printer);
+  void GenerateNonNestedInitializationCode(io::Printer* printer);
   void GenerateRegistrationCode(io::Printer* printer);
 
  private:
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index 978c8f3..c7d433c 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -37,6 +37,7 @@
 #include <google/protobuf/compiler/java/java_primitive_field.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
 #include <google/protobuf/compiler/java/java_message_field.h>
+#include <google/protobuf/compiler/java/java_string_field.h>
 #include <google/protobuf/stubs/common.h>
 
 namespace google {
@@ -63,33 +64,57 @@
     extension_generators_(
       new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
 
-  // Construct all the FieldGenerators.
+  // 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++) {
-    field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
+    FieldGenerator* generator = MakeGenerator(descriptor->field(i),
+        messageBitIndex, builderBitIndex);
+    field_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+    builderBitIndex += generator->GetNumBitsForBuilder();
   }
   for (int i = 0; i < descriptor->extension_count(); i++) {
-    extension_generators_[i].reset(MakeGenerator(descriptor->extension(i)));
+    FieldGenerator* generator = MakeGenerator(descriptor->extension(i),
+        messageBitIndex, builderBitIndex);
+    extension_generators_[i].reset(generator);
+    messageBitIndex += generator->GetNumBitsForMessage();
+    builderBitIndex += generator->GetNumBitsForBuilder();
   }
 }
 
-FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
+FieldGenerator* FieldGeneratorMap::MakeGenerator(
+    const FieldDescriptor* field, int messageBitIndex, int builderBitIndex) {
   if (field->is_repeated()) {
     switch (GetJavaType(field)) {
       case JAVATYPE_MESSAGE:
-        return new RepeatedMessageFieldGenerator(field);
+        return new RepeatedMessageFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
       case JAVATYPE_ENUM:
-        return new RepeatedEnumFieldGenerator(field);
+        return new RepeatedEnumFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
+      case JAVATYPE_STRING:
+        return new RepeatedStringFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
       default:
-        return new RepeatedPrimitiveFieldGenerator(field);
+        return new RepeatedPrimitiveFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
     }
   } else {
     switch (GetJavaType(field)) {
       case JAVATYPE_MESSAGE:
-        return new MessageFieldGenerator(field);
+        return new MessageFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
       case JAVATYPE_ENUM:
-        return new EnumFieldGenerator(field);
+        return new EnumFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
+      case JAVATYPE_STRING:
+        return new StringFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
       default:
-        return new PrimitiveFieldGenerator(field);
+        return new PrimitiveFieldGenerator(
+            field, messageBitIndex, builderBitIndex);
     }
   }
 }
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index f5bef7a..6097f35 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -55,15 +55,24 @@
   FieldGenerator() {}
   virtual ~FieldGenerator();
 
+  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 GenerateBuilderClearCode(io::Printer* printer) const = 0;
   virtual void GenerateMergingCode(io::Printer* printer) const = 0;
   virtual void GenerateBuildingCode(io::Printer* printer) const = 0;
   virtual void GenerateParsingCode(io::Printer* printer) const = 0;
   virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const;
   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;
 
@@ -85,7 +94,8 @@
   scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
   scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
 
-  static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
+  static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+      int messageBitIndex, int builderBitIndex);
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
 };
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 7ea127c..8968069 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -88,7 +88,8 @@
 FileGenerator::FileGenerator(const FileDescriptor* file)
   : file_(file),
     java_package_(FileJavaPackage(file)),
-    classname_(FileClassName(file)) {}
+    classname_(FileClassName(file)) {
+}
 
 FileGenerator::~FileGenerator() {}
 
@@ -179,7 +180,9 @@
       EnumGenerator(file_->enum_type(i)).Generate(printer);
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
-      MessageGenerator(file_->message_type(i)).Generate(printer);
+      MessageGenerator messageGenerator(file_->message_type(i));
+      messageGenerator.GenerateInterface(printer);
+      messageGenerator.Generate(printer);
     }
     if (HasGenericServices(file_)) {
       for (int i = 0; i < file_->service_count(); i++) {
@@ -215,24 +218,11 @@
         .GenerateStaticVariableInitializers(printer);
     }
 
-    for (int i = 0; i < file_->extension_count(); i++) {
-      // TODO(kenton):  Reuse ExtensionGenerator objects?
-      ExtensionGenerator(file_->extension(i))
-        .GenerateInitializationCode(printer);
-    }
-
     printer->Outdent();
     printer->Print(
       "}\n");
   }
 
-  // Dummy function we can use to force the static initialization block to
-  // run.  Needed by inner classes.  Cannot be private due to
-  // java_multiple_files option.
-  printer->Print(
-    "\n"
-    "public static void internalForceInit() {}\n");
-
   printer->Print(
     "\n"
     "// @@protoc_insertion_point(outer_class_scope)\n");
@@ -310,11 +300,10 @@
     MessageGenerator(file_->message_type(i))
       .GenerateStaticVariableInitializers(printer);
   }
-
   for (int i = 0; i < file_->extension_count(); i++) {
     // TODO(kenton):  Reuse ExtensionGenerator objects?
     ExtensionGenerator(file_->extension(i))
-      .GenerateInitializationCode(printer);
+        .GenerateNonNestedInitializationCode(printer);
   }
 
   if (UsesExtensions(file_proto)) {
@@ -325,9 +314,11 @@
       "  com.google.protobuf.ExtensionRegistry.newInstance();\n"
       "registerAllExtensions(registry);\n");
     for (int i = 0; i < file_->dependency_count(); i++) {
-      printer->Print(
-        "$dependency$.registerAllExtensions(registry);\n",
-        "dependency", ClassName(file_->dependency(i)));
+      if (ShouldIncludeDependency(file_->dependency(i))) {
+        printer->Print(
+            "$dependency$.registerAllExtensions(registry);\n",
+            "dependency", ClassName(file_->dependency(i)));
+      }
     }
     printer->Print(
       "return registry;\n");
@@ -372,13 +363,14 @@
 static void GenerateSibling(const string& package_dir,
                             const string& java_package,
                             const DescriptorClass* descriptor,
-                            OutputDirectory* output_directory,
-                            vector<string>* file_list) {
-  string filename = package_dir + descriptor->name() + ".java";
+                            GeneratorContext* context,
+                            vector<string>* file_list,
+                            const string& name_suffix,
+                            void (GeneratorClass::*pfn)(io::Printer* printer)) {
+  string filename = package_dir + descriptor->name() + name_suffix + ".java";
   file_list->push_back(filename);
 
-  scoped_ptr<io::ZeroCopyOutputStream> output(
-    output_directory->Open(filename));
+  scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
   io::Printer printer(output.get(), '$');
 
   printer.Print(
@@ -391,28 +383,36 @@
       "package", java_package);
   }
 
-  GeneratorClass(descriptor).Generate(&printer);
+  GeneratorClass generator(descriptor);
+  (generator.*pfn)(&printer);
 }
 
 void FileGenerator::GenerateSiblings(const string& package_dir,
-                                     OutputDirectory* output_directory,
+                                     GeneratorContext* context,
                                      vector<string>* file_list) {
   if (file_->options().java_multiple_files()) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
       GenerateSibling<EnumGenerator>(package_dir, java_package_,
                                      file_->enum_type(i),
-                                     output_directory, file_list);
+                                     context, file_list, "",
+                                     &EnumGenerator::Generate);
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       GenerateSibling<MessageGenerator>(package_dir, java_package_,
                                         file_->message_type(i),
-                                        output_directory, file_list);
+                                        context, file_list, "OrBuilder",
+                                        &MessageGenerator::GenerateInterface);
+      GenerateSibling<MessageGenerator>(package_dir, java_package_,
+                                        file_->message_type(i),
+                                        context, file_list, "",
+                                        &MessageGenerator::Generate);
     }
     if (HasGenericServices(file_)) {
       for (int i = 0; i < file_->service_count(); i++) {
         GenerateSibling<ServiceGenerator>(package_dir, java_package_,
                                           file_->service(i),
-                                          output_directory, file_list);
+                                          context, file_list, "",
+                                          &ServiceGenerator::Generate);
       }
     }
   }
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 9e35d33..5991146 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -46,7 +46,7 @@
     class Printer;             // printer.h
   }
   namespace compiler {
-    class OutputDirectory;     // code_generator.h
+    class GeneratorContext;     // code_generator.h
   }
 }
 
@@ -70,12 +70,13 @@
   // files other than the outer file (i.e. one for each message, enum, and
   // service type).
   void GenerateSiblings(const string& package_dir,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* generator_context,
                         vector<string>* file_list);
 
   const string& java_package() { return java_package_; }
   const string& classname()    { return classname_;    }
 
+
  private:
   // Returns whether the dependency should be included in the output file.
   // Always returns true for opensource, but used internally at Google to help
@@ -86,6 +87,7 @@
   string java_package_;
   string classname_;
 
+
   void GenerateEmbeddedDescriptor(io::Printer* printer);
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index 745b55a..e6c79ab 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -51,11 +51,8 @@
 
 bool JavaGenerator::Generate(const FileDescriptor* file,
                              const string& parameter,
-                             OutputDirectory* output_directory,
+                             GeneratorContext* context,
                              string* error) const {
-  vector<pair<string, string> > options;
-  ParseGeneratorParameter(parameter, &options);
-
   // -----------------------------------------------------------------
   // parse generator options
 
@@ -63,6 +60,10 @@
   // per line.
   string output_list_file;
 
+
+  vector<pair<string, string> > options;
+  ParseGeneratorParameter(parameter, &options);
+
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "output_list_file") {
       output_list_file = options[i].second;
@@ -72,18 +73,23 @@
     }
   }
 
-
   // -----------------------------------------------------------------
 
 
+  if (file->options().optimize_for() == FileOptions::LITE_RUNTIME &&
+      file->options().java_generate_equals_and_hash()) {
+    *error = "The \"java_generate_equals_and_hash\" option is incompatible "
+             "with \"optimize_for = LITE_RUNTIME\".  You must optimize for "
+             "SPEED or CODE_SIZE if you want to use this option.";
+    return false;
+  }
+
   FileGenerator file_generator(file);
   if (!file_generator.Validate(error)) {
     return false;
   }
 
-  string package_dir =
-    StringReplace(file_generator.java_package(), ".", "/", true);
-  if (!package_dir.empty()) package_dir += "/";
+  string package_dir = JavaPackageToDir(file_generator.java_package());
 
   vector<string> all_files;
 
@@ -94,19 +100,19 @@
 
   // Generate main java file.
   scoped_ptr<io::ZeroCopyOutputStream> output(
-    output_directory->Open(java_filename));
+    context->Open(java_filename));
   io::Printer printer(output.get(), '$');
   file_generator.Generate(&printer);
 
   // Generate sibling files.
-  file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
+  file_generator.GenerateSiblings(package_dir, context, &all_files);
 
   // Generate output list if requested.
   if (!output_list_file.empty()) {
     // Generate output list.  This is just a simple text file placed in a
     // deterministic location which lists the .java files being generated.
     scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
-      output_directory->Open(output_list_file));
+      context->Open(output_list_file));
     io::Printer srclist_printer(srclist_raw_output.get(), '$');
     for (int i = 0; i < all_files.size(); i++) {
       srclist_printer.Print("$filename$\n", "filename", all_files[i]);
diff --git a/src/google/protobuf/compiler/java/java_generator.h b/src/google/protobuf/compiler/java/java_generator.h
index c91c905..888b8d8 100644
--- a/src/google/protobuf/compiler/java/java_generator.h
+++ b/src/google/protobuf/compiler/java/java_generator.h
@@ -57,7 +57,7 @@
   // implements CodeGenerator ----------------------------------------
   bool Generate(const FileDescriptor* file,
                 const string& parameter,
-                OutputDirectory* output_directory,
+                GeneratorContext* context,
                 string* error) const;
 
  private:
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 7ed0c3c..1b6f165 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -134,16 +134,27 @@
 }
 
 string FileJavaPackage(const FileDescriptor* file) {
+  string result;
+
   if (file->options().has_java_package()) {
-    return file->options().java_package();
+    result = file->options().java_package();
   } else {
-    string result = kDefaultPackage;
+    result = kDefaultPackage;
     if (!file->package().empty()) {
       if (!result.empty()) result += '.';
       result += file->package();
     }
-    return result;
   }
+
+
+  return result;
+}
+
+string JavaPackageToDir(string package_name) {
+  string package_dir =
+    StringReplace(package_name, ".", "/", true);
+  if (!package_dir.empty()) package_dir += "/";
+  return package_dir;
 }
 
 string ToJavaName(const string& full_name, const FileDescriptor* file) {
@@ -335,6 +346,132 @@
   return "";
 }
 
+bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
+  // Switch on CppType since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return field->default_value_int32() == 0;
+    case FieldDescriptor::CPPTYPE_UINT32:
+      return field->default_value_uint32() == 0;
+    case FieldDescriptor::CPPTYPE_INT64:
+      return field->default_value_int64() == 0L;
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return field->default_value_uint64() == 0L;
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return field->default_value_double() == 0.0;
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return field->default_value_float() == 0.0;
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() == false;
+
+    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_ENUM:
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return false;
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+const char* bit_masks[] = {
+  "0x00000001",
+  "0x00000002",
+  "0x00000004",
+  "0x00000008",
+  "0x00000010",
+  "0x00000020",
+  "0x00000040",
+  "0x00000080",
+
+  "0x00000100",
+  "0x00000200",
+  "0x00000400",
+  "0x00000800",
+  "0x00001000",
+  "0x00002000",
+  "0x00004000",
+  "0x00008000",
+
+  "0x00010000",
+  "0x00020000",
+  "0x00040000",
+  "0x00080000",
+  "0x00100000",
+  "0x00200000",
+  "0x00400000",
+  "0x00800000",
+
+  "0x01000000",
+  "0x02000000",
+  "0x04000000",
+  "0x08000000",
+  "0x10000000",
+  "0x20000000",
+  "0x40000000",
+  "0x80000000",
+};
+
+string GetBitFieldName(int index) {
+  string varName = "bitField";
+  varName += SimpleItoa(index);
+  varName += "_";
+  return varName;
+}
+
+string GetBitFieldNameForBit(int bitIndex) {
+  return GetBitFieldName(bitIndex / 32);
+}
+
+string GenerateGetBit(int bitIndex) {
+  string varName = GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  string mask = bit_masks[bitInVarIndex];
+  string result = "((" + varName + " & " + mask + ") == " + mask + ")";
+  return result;
+}
+
+string GenerateSetBit(int bitIndex) {
+  string varName = GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  string mask = bit_masks[bitInVarIndex];
+  string result = varName + " |= " + mask;
+  return result;
+}
+
+string GenerateClearBit(int bitIndex) {
+  string varName = GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  string mask = bit_masks[bitInVarIndex];
+  string result = varName + " = (" + varName + " & ~" + mask + ")";
+  return result;
+}
+
+string GenerateGetBitFromLocal(int bitIndex) {
+  string varName = "from_" + GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  string mask = bit_masks[bitInVarIndex];
+  string result = "((" + varName + " & " + mask + ") == " + mask + ")";
+  return result;
+}
+
+string GenerateSetBitToLocal(int bitIndex) {
+  string varName = "to_" + GetBitFieldNameForBit(bitIndex);
+  int bitInVarIndex = bitIndex % 32;
+
+  string mask = bit_masks[bitInVarIndex];
+  string result = varName + " |= " + mask;
+  return result;
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 3c8974c..4ae07f1 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -68,6 +68,9 @@
 // Returns the file's Java package name.
 string FileJavaPackage(const FileDescriptor* file);
 
+// Returns output directory for the given package name.
+string JavaPackageToDir(string package_name);
+
 // Converts the given fully-qualified name in the proto namespace to its
 // fully-qualified name in the Java namespace, given that it is in the given
 // file.
@@ -118,6 +121,7 @@
 const char* BoxedPrimitiveTypeName(JavaType type);
 
 string DefaultValue(const FieldDescriptor* field);
+bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
 
 // Does this message class keep track of unknown fields?
 inline bool HasUnknownFields(const Descriptor* descriptor) {
@@ -132,6 +136,11 @@
            FileOptions::CODE_SIZE;
 }
 
+// Does this message have specialized equals() and hashCode() methods?
+inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
+  return descriptor->file()->options().java_generate_equals_and_hash();
+}
+
 // Does this message class have descriptor and reflection methods?
 inline bool HasDescriptorMethods(const Descriptor* descriptor) {
   return descriptor->file()->options().optimize_for() !=
@@ -146,6 +155,12 @@
            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 &&
@@ -153,6 +168,43 @@
          file->options().java_generic_services();
 }
 
+
+// Methods for shared bitfields.
+
+// Gets the name of the shared bitfield for the given index.
+string GetBitFieldName(int index);
+
+// Gets the name of the shared bitfield for the given bit index.
+// Effectively, GetBitFieldName(bitIndex / 32)
+string GetBitFieldNameForBit(int bitIndex);
+
+// Generates the java code for the expression that returns the boolean value
+// of the bit of the shared bitfields for the given bit index.
+// Example: "((bitField1_ & 0x04) == 0x04)"
+string GenerateGetBit(int bitIndex);
+
+// Generates the java code for the expression that sets the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ | 0x04)"
+string GenerateSetBit(int bitIndex);
+
+// Generates the java code for the expression that clears the bit of the shared
+// bitfields for the given bit index.
+// Example: "bitField1_ = (bitField1_ & ~0x04)"
+string GenerateClearBit(int bitIndex);
+
+// Does the same as GenerateGetBit but operates on the bit field on a local
+// variable. This is used by the builder to copy the value in the builder to
+// the message.
+// Example: "((from_bitField1_ & 0x04) == 0x04)"
+string GenerateGetBitFromLocal(int bitIndex);
+
+// Does the same as GenerateSetBit but operates on the bit field on a local
+// variable. This is used by the builder to copy the value in the builder to
+// the message.
+// Example: "to_bitField1_ = (to_bitField1_ | 0x04)"
+string GenerateSetBitToLocal(int bitIndex);
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 8b91193..47ee84c 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -245,14 +245,54 @@
     MessageGenerator(descriptor_->nested_type(i))
       .GenerateStaticVariableInitializers(printer);
   }
-
-  for (int i = 0; i < descriptor_->extension_count(); i++) {
-    // TODO(kenton):  Reuse ExtensionGenerator objects?
-    ExtensionGenerator(descriptor_->extension(i))
-      .GenerateInitializationCode(printer);
-  }
 }
 
+// ===================================================================
+
+void MessageGenerator::GenerateInterface(io::Printer* printer) {
+
+  if (descriptor_->extension_range_count() > 0) {
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public interface $classname$OrBuilder extends\n"
+        "    com.google.protobuf.GeneratedMessage.\n"
+        "        ExtendableMessageOrBuilder<$classname$> {\n",
+        "classname", descriptor_->name());
+    } else {
+      printer->Print(
+        "public interface $classname$OrBuilder extends \n"
+        "     com.google.protobuf.GeneratedMessageLite.\n"
+        "          ExtendableMessageOrBuilder<$classname$> {\n",
+        "classname", descriptor_->name());
+    }
+  } else {
+    if (HasDescriptorMethods(descriptor_)) {
+      printer->Print(
+        "public interface $classname$OrBuilder\n"
+        "    extends com.google.protobuf.MessageOrBuilder {\n",
+        "classname", descriptor_->name());
+    } else {
+      printer->Print(
+        "public interface $classname$OrBuilder\n"
+        "    extends com.google.protobuf.MessageLiteOrBuilder {\n",
+        "classname", descriptor_->name());
+    }
+  }
+
+  printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      printer->Print("\n");
+      PrintFieldComment(printer, descriptor_->field(i));
+      field_generators_.get(descriptor_->field(i))
+                       .GenerateInterfaceMembers(printer);
+    }
+  printer->Outdent();
+
+  printer->Print("}\n");
+}
+
+// ===================================================================
+
 void MessageGenerator::Generate(io::Printer* printer) {
   bool is_own_file =
     descriptor_->containing_type() == NULL &&
@@ -263,14 +303,14 @@
       printer->Print(
         "public $static$ final class $classname$ extends\n"
         "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-        "      $classname$> {\n",
+        "      $classname$> implements $classname$OrBuilder {\n",
         "static", is_own_file ? "" : "static",
         "classname", descriptor_->name());
     } else {
       printer->Print(
         "public $static$ final class $classname$ extends\n"
         "    com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n"
-        "      $classname$> {\n",
+        "      $classname$> implements $classname$OrBuilder {\n",
         "static", is_own_file ? "" : "static",
         "classname", descriptor_->name());
     }
@@ -278,13 +318,15 @@
     if (HasDescriptorMethods(descriptor_)) {
       printer->Print(
         "public $static$ final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessage {\n",
+        "    com.google.protobuf.GeneratedMessage\n"
+        "    implements $classname$OrBuilder {\n",
         "static", is_own_file ? "" : "static",
         "classname", descriptor_->name());
     } else {
       printer->Print(
         "public $static$ final class $classname$ extends\n"
-        "    com.google.protobuf.GeneratedMessageLite {\n",
+        "    com.google.protobuf.GeneratedMessageLite\n"
+        "    implements $classname$OrBuilder {\n",
         "static", is_own_file ? "" : "static",
         "classname", descriptor_->name());
     }
@@ -292,8 +334,8 @@
   printer->Indent();
   printer->Print(
     "// Use $classname$.newBuilder() to construct.\n"
-    "private $classname$() {\n"
-    "  initFields();\n"
+    "private $classname$(Builder builder) {\n"
+    "  super(builder);\n"
     "}\n"
     // Used when constructing the default instance, which cannot be initialized
     // immediately because it may cyclically refer to other default instances.
@@ -310,33 +352,29 @@
     "\n",
     "classname", descriptor_->name());
 
-  if (HasDescriptorMethods(descriptor_)) {
-    printer->Print(
-      "public static final com.google.protobuf.Descriptors.Descriptor\n"
-      "    getDescriptor() {\n"
-      "  return $fileclass$.internal_$identifier$_descriptor;\n"
-      "}\n"
-      "\n"
-      "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
-      "    internalGetFieldAccessorTable() {\n"
-      "  return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
-      "}\n"
-      "\n",
-      "fileclass", ClassName(descriptor_->file()),
-      "identifier", UniqueFileScopeIdentifier(descriptor_));
-  }
+  GenerateDescriptorMethods(printer);
 
-  // Nested types and extensions
+  // Nested types
   for (int i = 0; i < descriptor_->enum_type_count(); i++) {
     EnumGenerator(descriptor_->enum_type(i)).Generate(printer);
   }
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
-    MessageGenerator(descriptor_->nested_type(i)).Generate(printer);
+    MessageGenerator messageGenerator(descriptor_->nested_type(i));
+    messageGenerator.GenerateInterface(printer);
+    messageGenerator.Generate(printer);
   }
 
-  for (int i = 0; i < descriptor_->extension_count(); i++) {
-    ExtensionGenerator(descriptor_->extension(i)).Generate(printer);
+  // 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));
   }
 
   // Fields
@@ -361,35 +399,42 @@
   printer->Print("}\n");
 
   if (HasGeneratedMethods(descriptor_)) {
-    GenerateIsInitialized(printer);
+    GenerateIsInitialized(printer, MEMOIZE);
     GenerateMessageSerializationMethods(printer);
   }
 
+  if (HasEqualsAndHashCode(descriptor_)) {
+    GenerateEqualsAndHashCode(printer);
+  }
+
   GenerateParseFromMethods(printer);
   GenerateBuilder(printer);
 
-  // Force initialization of outer class.  Otherwise, nested extensions may
-  // not be initialized.  Also carefully initialize the default instance in
-  // such a way that it doesn't conflict with other initialization.
+  // Carefully initialize the default instance in such a way that it doesn't
+  // conflict with other initialization.
   printer->Print(
     "\n"
     "static {\n"
     "  defaultInstance = new $classname$(true);\n"
-    "  $file$.internalForceInit();\n"
     "  defaultInstance.initFields();\n"
-    "}\n",
-    "file", ClassName(descriptor_->file()),
-    "classname", descriptor_->name());
-
-  printer->Print(
+    "}\n"
     "\n"
     "// @@protoc_insertion_point(class_scope:$full_name$)\n",
+    "classname", descriptor_->name(),
     "full_name", descriptor_->full_name());
 
+  // Extensions must be declared after the defaultInstance is initialized
+  // because the defaultInstance is used by the extension to lazily retrieve
+  // the outer class's FileDescriptor.
+  for (int i = 0; i < descriptor_->extension_count(); i++) {
+    ExtensionGenerator(descriptor_->extension(i)).Generate(printer);
+  }
+
   printer->Outdent();
   printer->Print("}\n\n");
 }
 
+
 // ===================================================================
 
 void MessageGenerator::
@@ -502,6 +547,13 @@
     "  return size;\n"
     "}\n"
     "\n");
+
+  printer->Print(
+    "@java.lang.Override\n"
+    "protected Object writeReplace() throws java.io.ObjectStreamException {\n"
+    "  return super.writeReplace();\n"
+    "}\n"
+    "\n");
 }
 
 void MessageGenerator::
@@ -605,42 +657,68 @@
     "\n",
     "classname", ClassName(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");
+  }
+
   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> {\n",
+        "      $classname$, Builder> implements $classname$OrBuilder {\n",
         "classname", ClassName(descriptor_));
     } else {
       printer->Print(
         "public static final class Builder extends\n"
         "    com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n"
-        "      $classname$, Builder> {\n",
+        "      $classname$, Builder> implements $classname$OrBuilder {\n",
         "classname", ClassName(descriptor_));
     }
   } else {
     if (HasDescriptorMethods(descriptor_)) {
       printer->Print(
         "public static final class Builder extends\n"
-        "    com.google.protobuf.GeneratedMessage.Builder<Builder> {\n",
+        "    com.google.protobuf.GeneratedMessage.Builder<Builder>\n"
+         "   implements $classname$OrBuilder {\n",
         "classname", ClassName(descriptor_));
     } else {
       printer->Print(
         "public static final class Builder extends\n"
         "    com.google.protobuf.GeneratedMessageLite.Builder<\n"
-        "      $classname$, Builder> {\n",
+        "      $classname$, Builder>\n"
+        "    implements $classname$OrBuilder {\n",
         "classname", ClassName(descriptor_));
     }
   }
   printer->Indent();
 
+  GenerateDescriptorMethods(printer);
   GenerateCommonBuilderMethods(printer);
 
   if (HasGeneratedMethods(descriptor_)) {
+    GenerateIsInitialized(printer, DONT_MEMOIZE);
     GenerateBuilderParsingMethods(printer);
   }
 
+  // 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");
     PrintFieldComment(printer, descriptor_->field(i));
@@ -657,36 +735,92 @@
   printer->Print("}\n");
 }
 
+void MessageGenerator::GenerateDescriptorMethods(io::Printer* printer) {
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "public static final com.google.protobuf.Descriptors.Descriptor\n"
+      "    getDescriptor() {\n"
+      "  return $fileclass$.internal_$identifier$_descriptor;\n"
+      "}\n"
+      "\n"
+      "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
+      "    internalGetFieldAccessorTable() {\n"
+      "  return $fileclass$.internal_$identifier$_fieldAccessorTable;\n"
+      "}\n"
+      "\n",
+      "fileclass", ClassName(descriptor_->file()),
+      "identifier", UniqueFileScopeIdentifier(descriptor_));
+  }
+}
+
 // ===================================================================
 
 void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
   printer->Print(
-    "private $classname$ result;\n"
-    "\n"
     "// Construct using $classname$.newBuilder()\n"
-    "private Builder() {}\n"
-    "\n"
-    "private static Builder create() {\n"
-    "  Builder builder = new Builder();\n"
-    "  builder.result = new $classname$();\n"
-    "  return builder;\n"
+    "private Builder() {\n"
+    "  maybeForceBuilderInitialization();\n"
     "}\n"
-    "\n"
-    "protected $classname$ internalGetResult() {\n"
-    "  return result;\n"
+    "\n",
+    "classname", ClassName(descriptor_));
+
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "private Builder(BuilderParent parent) {\n"
+      "  super(parent);\n"
+      "  maybeForceBuilderInitialization();\n"
+      "}\n",
+      "classname", ClassName(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++) {
+      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(
+    "private static Builder create() {\n"
+    "  return new Builder();\n"
     "}\n"
     "\n"
     "public Builder clear() {\n"
-    "  if (result == null) {\n"
-    "    throw new IllegalStateException(\n"
-    "      \"Cannot call clear() after build().\");\n"
-    "  }\n"
-    "  result = new $classname$();\n"
+    "  super.clear();\n",
+    "classname", ClassName(descriptor_));
+
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(descriptor_->field(i))
+        .GenerateBuilderClearCode(printer);
+  }
+
+  printer->Outdent();
+
+  printer->Print(
     "  return this;\n"
     "}\n"
     "\n"
     "public Builder clone() {\n"
-    "  return create().mergeFrom(result);\n"
+    "  return create().mergeFrom(buildPartial());\n"
     "}\n"
     "\n",
     "classname", ClassName(descriptor_));
@@ -703,49 +837,78 @@
     "public $classname$ getDefaultInstanceForType() {\n"
     "  return $classname$.getDefaultInstance();\n"
     "}\n"
-    "\n"
-    "public boolean isInitialized() {\n"
-    "  return result.isInitialized();\n"
-    "}\n",
+    "\n",
     "classname", ClassName(descriptor_));
 
   // -----------------------------------------------------------------
 
   printer->Print(
     "public $classname$ build() {\n"
-    // If result == null, we'll throw an appropriate exception later.
-    "  if (result != null && !isInitialized()) {\n"
+    "  $classname$ result = buildPartial();\n"
+    "  if (!result.isInitialized()) {\n"
     "    throw newUninitializedMessageException(result);\n"
     "  }\n"
-    "  return buildPartial();\n"
+    "  return result;\n"
     "}\n"
     "\n"
     "private $classname$ buildParsed()\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
-    "  if (!isInitialized()) {\n"
+    "  $classname$ result = buildPartial();\n"
+    "  if (!result.isInitialized()) {\n"
     "    throw newUninitializedMessageException(\n"
     "      result).asInvalidProtocolBufferException();\n"
     "  }\n"
-    "  return buildPartial();\n"
+    "  return result;\n"
     "}\n"
     "\n"
     "public $classname$ buildPartial() {\n"
-    "  if (result == null) {\n"
-    "    throw new IllegalStateException(\n"
-    "      \"build() has already been called on this Builder.\");\n"
-    "  }\n",
+    "  $classname$ result = new $classname$(this);\n",
     "classname", ClassName(descriptor_));
+
   printer->Indent();
 
+  // 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.
+  int totalBuilderBits = 0;
+  int totalMessageBits = 0;
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldGenerator& field = field_generators_.get(descriptor_->field(i));
+    totalBuilderBits += field.GetNumBitsForBuilder();
+    totalMessageBits += field.GetNumBitsForMessage();
+  }
+  int totalBuilderInts = (totalBuilderBits + 31) / 32;
+  int totalMessageInts = (totalMessageBits + 31) / 32;
+  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);
   }
 
+  // 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));
+  }
+
   printer->Outdent();
+
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+    "  onBuilt();\n");
+  }
+
   printer->Print(
-    "  $classname$ returnMe = result;\n"
-    "  result = null;\n"
-    "  return returnMe;\n"
+    "  return result;\n"
     "}\n"
     "\n",
     "classname", ClassName(descriptor_));
@@ -834,25 +997,31 @@
     printer->Print(
       "case 0:\n"          // zero signals EOF / limit reached
       "  this.setUnknownFields(unknownFields.build());\n"
+      "  $on_changed$\n"
       "  return this;\n"
       "default: {\n"
       "  if (!parseUnknownField(input, unknownFields,\n"
       "                         extensionRegistry, tag)) {\n"
       "    this.setUnknownFields(unknownFields.build());\n"
+      "    $on_changed$\n"
       "    return this;\n"   // it's an endgroup tag
       "  }\n"
       "  break;\n"
-      "}\n");
+      "}\n",
+      "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
   } else {
     printer->Print(
       "case 0:\n"          // zero signals EOF / limit reached
+      "  $on_changed$\n"
       "  return this;\n"
       "default: {\n"
       "  if (!parseUnknownField(input, extensionRegistry, tag)) {\n"
+      "    $on_changed$\n"
       "    return this;\n"   // it's an endgroup tag
       "  }\n"
       "  break;\n"
-      "}\n");
+      "}\n",
+      "on_changed", HasDescriptorMethods(descriptor_) ? "onChanged();" : "");
   }
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -898,16 +1067,33 @@
     "    }\n"     // switch (tag)
     "  }\n"       // while (true)
     "}\n"
+
     "\n");
 }
 
 // ===================================================================
 
-void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+void MessageGenerator::GenerateIsInitialized(
+    io::Printer* printer, UseMemoization useMemoization) {
+  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");
+  }
   printer->Print(
     "public final boolean isInitialized() {\n");
   printer->Indent();
 
+  if (memoization) {
+    printer->Print(
+      "byte isInitialized = memoizedIsInitialized;\n"
+      "if (isInitialized != -1) return isInitialized == 1;\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
   //   "has" fields into a single bitfield.
@@ -916,8 +1102,12 @@
 
     if (field->is_required()) {
       printer->Print(
-        "if (!has$name$) return false;\n",
-        "name", UnderscoresToCapitalizedCamelCase(field));
+        "if (!has$name$()) {\n"
+        "  $memoize$\n"
+        "  return false;\n"
+        "}\n",
+        "name", UnderscoresToCapitalizedCamelCase(field),
+        "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
     }
   }
 
@@ -929,25 +1119,37 @@
       switch (field->label()) {
         case FieldDescriptor::LABEL_REQUIRED:
           printer->Print(
-            "if (!get$name$().isInitialized()) return false;\n",
+            "if (!get$name$().isInitialized()) {\n"
+             "  $memoize$\n"
+             "  return false;\n"
+             "}\n",
             "type", ClassName(field->message_type()),
-            "name", UnderscoresToCapitalizedCamelCase(field));
+            "name", UnderscoresToCapitalizedCamelCase(field),
+            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
           break;
         case FieldDescriptor::LABEL_OPTIONAL:
           printer->Print(
             "if (has$name$()) {\n"
-            "  if (!get$name$().isInitialized()) return false;\n"
+            "  if (!get$name$().isInitialized()) {\n"
+            "    $memoize$\n"
+            "    return false;\n"
+            "  }\n"
             "}\n",
             "type", ClassName(field->message_type()),
-            "name", UnderscoresToCapitalizedCamelCase(field));
+            "name", UnderscoresToCapitalizedCamelCase(field),
+            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
           break;
         case FieldDescriptor::LABEL_REPEATED:
           printer->Print(
-            "for ($type$ element : get$name$List()) {\n"
-            "  if (!element.isInitialized()) return false;\n"
+            "for (int i = 0; i < get$name$Count(); i++) {\n"
+            "  if (!get$name$(i).isInitialized()) {\n"
+            "    $memoize$\n"
+            "    return false;\n"
+            "  }\n"
             "}\n",
             "type", ClassName(field->message_type()),
-            "name", UnderscoresToCapitalizedCamelCase(field));
+            "name", UnderscoresToCapitalizedCamelCase(field),
+            "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
           break;
       }
     }
@@ -955,10 +1157,20 @@
 
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
-      "if (!extensionsAreInitialized()) return false;\n");
+      "if (!extensionsAreInitialized()) {\n"
+      "  $memoize$\n"
+      "  return false;\n"
+      "}\n",
+      "memoize", memoization ? "memoizedIsInitialized = 0;" : "");
   }
 
   printer->Outdent();
+
+  if (memoization) {
+    printer->Print(
+      "  memoizedIsInitialized = 1;\n");
+  }
+
   printer->Print(
     "  return true;\n"
     "}\n"
@@ -967,6 +1179,94 @@
 
 // ===================================================================
 
+void MessageGenerator::GenerateEqualsAndHashCode(io::Printer* printer) {
+  printer->Print(
+    "@java.lang.Override\n"
+    "public boolean equals(final 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", ClassName(descriptor_));
+
+  printer->Print("boolean result = true;\n");
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!field->is_repeated()) {
+      printer->Print(
+        "result = result && (has$name$() == other.has$name$());\n"
+        "if (has$name$()) {\n",
+        "name", UnderscoresToCapitalizedCamelCase(field));
+      printer->Indent();
+    }
+    field_generators_.get(field).GenerateEqualsCode(printer);
+    if (!field->is_repeated()) {
+      printer->Outdent();
+      printer->Print(
+        "}\n");
+    }
+  }
+  if (HasDescriptorMethods(descriptor_)) {
+    printer->Print(
+      "result = result &&\n"
+      "    getUnknownFields().equals(other.getUnknownFields());\n");
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print(
+        "result = result &&\n"
+        "    getExtensionFields().equals(other.getExtensionFields());\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(
+    "int hash = 41;\n"
+    "hash = (19 * hash) + getDescriptorForType().hashCode();\n");
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (!field->is_repeated()) {
+      printer->Print(
+        "if (has$name$()) {\n",
+        "name", UnderscoresToCapitalizedCamelCase(field));
+      printer->Indent();
+    }
+    field_generators_.get(field).GenerateHashCode(printer);
+    if (!field->is_repeated()) {
+      printer->Outdent();
+      printer->Print("}\n");
+    }
+  }
+  if (HasDescriptorMethods(descriptor_)) {
+    if (descriptor_->extension_range_count() > 0) {
+      printer->Print(
+        "hash = hashFields(hash, getExtensionFields());\n");
+    }
+  }
+  printer->Print(
+    "hash = (29 * hash) + getUnknownFields().hashCode();\n"
+    "return hash;\n");
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
 void MessageGenerator::GenerateExtensionRegistrationCode(io::Printer* printer) {
   for (int i = 0; i < descriptor_->extension_count(); i++) {
     ExtensionGenerator(descriptor_->extension(i))
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 50ffae0..4c6fbbe 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -67,11 +67,19 @@
   // Generate the class itself.
   void Generate(io::Printer* printer);
 
+  // Generates the base interface that both the class and its builder implement
+  void GenerateInterface(io::Printer* printer);
+
   // Generate code to register all contained extensions with an
   // ExtensionRegistry.
   void GenerateExtensionRegistrationCode(io::Printer* printer);
 
  private:
+  enum UseMemoization {
+    MEMOIZE,
+    DONT_MEMOIZE
+  };
+
   void GenerateMessageSerializationMethods(io::Printer* printer);
   void GenerateParseFromMethods(io::Printer* printer);
   void GenerateSerializeOneField(io::Printer* printer,
@@ -81,8 +89,11 @@
 
   void GenerateBuilder(io::Printer* printer);
   void GenerateCommonBuilderMethods(io::Printer* printer);
+  void GenerateDescriptorMethods(io::Printer* printer);
   void GenerateBuilderParsingMethods(io::Printer* printer);
-  void GenerateIsInitialized(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer,
+      UseMemoization useMemoization);
+  void GenerateEqualsAndHashCode(io::Printer* printer);
 
   const Descriptor* descriptor_;
   FieldGeneratorMap field_generators_;
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 71edc02..251945a 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -51,16 +51,43 @@
 // TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
 //   repeat code between this and the other field types.
 void SetMessageVariables(const FieldDescriptor* descriptor,
+                         int messageBitIndex,
+                         int builderBitIndex,
                          map<string, string>* variables) {
   (*variables)["name"] =
     UnderscoresToCamelCase(descriptor);
   (*variables)["capitalized_name"] =
     UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["constant_name"] = FieldConstantName(descriptor);
   (*variables)["number"] = SimpleItoa(descriptor->number());
   (*variables)["type"] = ClassName(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();" : "";
+
+  // For singular messages and builders, one bit is used for the hasField bit.
+  (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+  (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_has_field_bit_builder"] =
+      GenerateClearBit(builderBitIndex);
+
+  // For repated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
 }
 
 }  // namespace
@@ -68,68 +95,244 @@
 // ===================================================================
 
 MessageFieldGenerator::
-MessageFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetMessageVariables(descriptor, &variables_);
+MessageFieldGenerator(const FieldDescriptor* descriptor,
+                      int messageBitIndex,
+                      int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      &variables_);
 }
 
 MessageFieldGenerator::~MessageFieldGenerator() {}
 
+int MessageFieldGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int MessageFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void MessageFieldGenerator::
+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.
+  printer->Print(variables_,
+    "$deprecation$boolean has$capitalized_name$();\n"
+    "$deprecation$$type$ get$capitalized_name$();\n");
+
+  if (HasNestedBuilders(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n");
+  }
+}
+
 void MessageFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private boolean has$capitalized_name$;\n"
     "private $type$ $name$_;\n"
-    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
-    "public $type$ get$capitalized_name$() { return $name$_; }\n");
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n"
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
+
+  if (HasNestedBuilders(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n"
+      "  return $name$_;\n"
+      "}\n");
+  }
+}
+
+void MessageFieldGenerator::PrintNestedBuilderCondition(
+    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);
+   }
+}
+
+void MessageFieldGenerator::PrintNestedBuilderFunction(
+    io::Printer* printer,
+    const char* method_prototype,
+    const char* regular_case,
+    const char* nested_builder_case,
+    const char* trailing_code) const {
+  printer->Print(variables_, method_prototype);
+  printer->Print(" {\n");
+  printer->Indent();
+  PrintNestedBuilderCondition(printer, regular_case, nested_builder_case);
+  if (trailing_code != NULL) {
+    printer->Print(variables_, trailing_code);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void MessageFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
+  // 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.
+
   printer->Print(variables_,
-    "public boolean has$capitalized_name$() {\n"
-    "  return result.has$capitalized_name$();\n"
-    "}\n"
-    "public $type$ get$capitalized_name$() {\n"
-    "  return result.get$capitalized_name$();\n"
-    "}\n"
-    "public Builder set$capitalized_name$($type$ value) {\n"
-    "  if (value == null) {\n"
-    "    throw new NullPointerException();\n"
-    "  }\n"
-    "  result.has$capitalized_name$ = true;\n"
-    "  result.$name$_ = value;\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder set$capitalized_name$($type$.Builder builderForValue) {\n"
-    "  result.has$capitalized_name$ = true;\n"
-    "  result.$name$_ = builderForValue.build();\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder merge$capitalized_name$($type$ value) {\n"
-    "  if (result.has$capitalized_name$() &&\n"
-    "      result.$name$_ != $type$.getDefaultInstance()) {\n"
-    "    result.$name$_ =\n"
-    "      $type$.newBuilder(result.$name$_).mergeFrom(value).buildPartial();\n"
-    "  } else {\n"
-    "    result.$name$_ = value;\n"
-    "  }\n"
-    "  result.has$capitalized_name$ = true;\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.has$capitalized_name$ = false;\n"
-    "  result.$name$_ = $type$.getDefaultInstance();\n"
-    "  return this;\n"
+    // Used when the builder is null.
+    "private $type$ $name$_ = $type$.getDefaultInstance();\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");
+  }
+
+  // The comments above the methods below are based on a hypothetical
+  // field of type "Field" called "Field".
+
+  // boolean hasField()
+  printer->Print(variables_,
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_builder$;\n"
     "}\n");
+
+  // Field getField()
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public $type$ get$capitalized_name$()",
+
+    "return $name$_;\n",
+
+    "return $name$Builder_.getMessage();\n",
+
+    NULL);
+
+  // Field.Builder setField(Field value)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder set$capitalized_name$($type$ value)",
+
+    "if (value == null) {\n"
+    "  throw new NullPointerException();\n"
+    "}\n"
+    "$name$_ = value;\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.setMessage(value);\n",
+
+    "$set_has_field_bit_builder$;\n"
+    "return this;\n");
+
+  // Field.Builder setField(Field.Builder builderForValue)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    $type$.Builder builderForValue)",
+
+    "$name$_ = builderForValue.build();\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.setMessage(builderForValue.build());\n",
+
+    "$set_has_field_bit_builder$;\n"
+    "return this;\n");
+
+  // Field.Builder mergeField(Field value)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder merge$capitalized_name$($type$ value)",
+
+    "if ($get_has_field_bit_builder$ &&\n"
+    "    $name$_ != $type$.getDefaultInstance()) {\n"
+    "  $name$_ =\n"
+    "    $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n"
+    "} else {\n"
+    "  $name$_ = value;\n"
+    "}\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.mergeFrom(value);\n",
+
+    "$set_has_field_bit_builder$;\n"
+    "return this;\n");
+
+  // Field.Builder clearField()
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder clear$capitalized_name$()",
+
+    "$name$_ = $type$.getDefaultInstance();\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.clear();\n",
+
+    "$clear_has_field_bit_builder$;\n"
+    "return this;\n");
+
+  if (HasNestedBuilders(descriptor_->containing_type())) {
+    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"
+      "$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"
+      "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");
+  }
 }
 
 void MessageFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  printer->Print(variables_,
+    "get$capitalized_name$FieldBuilder();\n");
+}
+
+
+void MessageFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
   printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n");
 }
 
 void MessageFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  PrintNestedBuilderCondition(printer,
+    "$name$_ = $type$.getDefaultInstance();\n",
+
+    "$name$Builder_.clear();\n");
+  printer->Print(variables_, "$clear_has_field_bit_builder$;\n");
+}
+
+void MessageFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
   printer->Print(variables_,
     "if (other.has$capitalized_name$()) {\n"
@@ -139,7 +342,16 @@
 
 void MessageFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
-  // Nothing to do for singular fields.
+
+  printer->Print(variables_,
+      "if ($get_has_field_bit_from_local$) {\n"
+      "  $set_has_field_bit_to_local$;\n"
+      "}\n");
+
+  PrintNestedBuilderCondition(printer,
+    "result.$name$_ = $name$_;\n",
+
+    "result.$name$_ = $name$Builder_.build();\n");
 }
 
 void MessageFieldGenerator::
@@ -165,20 +377,34 @@
 void MessageFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
-    "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.write$group_or_message$($number$, $name$_);\n"
     "}\n");
 }
 
 void MessageFieldGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
+    "if ($get_has_field_bit_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+    "    .compute$group_or_message$Size($number$, $name$_);\n"
     "}\n");
 }
 
+void MessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void MessageFieldGenerator::
+GenerateHashCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "hash = (37 * hash) + $constant_name$;\n"
+    "hash = (53 * hash) + get$capitalized_name$().hashCode();\n");
+}
+
 string MessageFieldGenerator::GetBoxedType() const {
   return ClassName(descriptor_->message_type());
 }
@@ -186,109 +412,416 @@
 // ===================================================================
 
 RepeatedMessageFieldGenerator::
-RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetMessageVariables(descriptor, &variables_);
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+                              int messageBitIndex,
+                              int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
+                      &variables_);
 }
 
 RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
 
+int RepeatedMessageFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedMessageFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedMessageFieldGenerator::
+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.
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$type$> \n"
+    "    get$capitalized_name$List();\n"
+    "$deprecation$$type$ get$capitalized_name$(int index);\n"
+    "$deprecation$int get$capitalized_name$Count();\n");
+  if (HasNestedBuilders(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "$deprecation$java.util.List<? extends $type$OrBuilder> \n"
+      "    get$capitalized_name$OrBuilderList();\n"
+      "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n"
+      "    int index);\n");
+  }
+}
+
 void RepeatedMessageFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.util.List<$type$> $name$_ =\n"
-    "  java.util.Collections.emptyList();\n"
-    "public java.util.List<$type$> get$capitalized_name$List() {\n"
+    "private java.util.List<$type$> $name$_;\n"
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n"
     "  return $name$_;\n"   // note:  unmodifiable list
     "}\n"
-    "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
+    "$deprecation$public java.util.List<? extends $type$OrBuilder> \n"
+    "    get$capitalized_name$OrBuilderList() {\n"
+    "  return $name$_;\n"
+    "}\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n"
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n"
+    "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n"
+    "    int index) {\n"
     "  return $name$_.get(index);\n"
     "}\n");
+
+}
+
+void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition(
+    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);
+   }
+}
+
+void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction(
+    io::Printer* printer,
+    const char* method_prototype,
+    const char* regular_case,
+    const char* nested_builder_case,
+    const char* trailing_code) const {
+  printer->Print(variables_, method_prototype);
+  printer->Print(" {\n");
+  printer->Indent();
+  PrintNestedBuilderCondition(printer, regular_case, nested_builder_case);
+  if (trailing_code != NULL) {
+    printer->Print(variables_, trailing_code);
+  }
+  printer->Outdent();
+  printer->Print("}\n");
 }
 
 void RepeatedMessageFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
+  // 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.
+
   printer->Print(variables_,
-    // Note:  We return an unmodifiable list because otherwise the caller
-    //   could hold on to the returned list and modify it after the message
-    //   has been built, thus mutating the message which is supposed to be
-    //   immutable.
-    "public java.util.List<$type$> get$capitalized_name$List() {\n"
-    "  return java.util.Collections.unmodifiableList(result.$name$_);\n"
+    // Used when the builder is null.
+    // One field is the list and the other field keeps track of whether the
+    // list is immutable. If it's immutable, the invariant is that it must
+    // either an instance of Collections.emptyList() or it's an ArrayList
+    // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+    // a refererence to the underlying ArrayList. This invariant allows us to
+    // share instances of lists between protocol buffers avoiding expensive
+    // memory allocations. Note, immutable is a strong guarantee here -- not
+    // just that the list cannot be modified via the reference but that the
+    // list can never be modified.
+    "private java.util.List<$type$> $name$_ =\n"
+    "  java.util.Collections.emptyList();\n"
+
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$get_mutable_bit_builder$) {\n"
+    "    $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
+    "    $set_mutable_bit_builder$;\n"
+    "   }\n"
     "}\n"
-    "public int get$capitalized_name$Count() {\n"
-    "  return result.get$capitalized_name$Count();\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");
+  }
+
+  // The comments above the methods below are based on a hypothetical
+  // repeated field of type "Field" called "RepeatedField".
+
+  // List<Field> getRepeatedFieldList()
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public java.util.List<$type$> get$capitalized_name$List()",
+
+    "return java.util.Collections.unmodifiableList($name$_);\n",
+    "return $name$Builder_.getMessageList();\n",
+
+    NULL);
+
+  // int getRepeatedFieldCount()
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public int get$capitalized_name$Count()",
+
+    "return $name$_.size();\n",
+    "return $name$Builder_.getCount();\n",
+
+    NULL);
+
+  // Field getRepeatedField(int index)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public $type$ get$capitalized_name$(int index)",
+
+    "return $name$_.get(index);\n",
+
+    "return $name$Builder_.getMessage(index);\n",
+
+    NULL);
+
+  // Builder setRepeatedField(int index, Field value)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value)",
+    "if (value == null) {\n"
+    "  throw new NullPointerException();\n"
     "}\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
-    "  return result.get$capitalized_name$(index);\n"
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.set(index, value);\n"
+    "$on_changed$\n",
+    "$name$Builder_.setMessage(index, value);\n",
+    "return this;\n");
+
+  // Builder setRepeatedField(int index, Field.Builder builderForValue)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue)",
+
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.set(index, builderForValue.build());\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.setMessage(index, builderForValue.build());\n",
+
+    "return this;\n");
+
+  // Builder addRepeatedField(Field value)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder add$capitalized_name$($type$ value)",
+
+    "if (value == null) {\n"
+    "  throw new NullPointerException();\n"
     "}\n"
-    "public Builder set$capitalized_name$(int index, $type$ value) {\n"
-    "  if (value == null) {\n"
-    "    throw new NullPointerException();\n"
-    "  }\n"
-    "  result.$name$_.set(index, value);\n"
-    "  return this;\n"
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(value);\n"
+
+    "$on_changed$\n",
+
+    "$name$Builder_.addMessage(value);\n",
+
+    "return this;\n");
+
+  // Builder addRepeatedField(int index, Field value)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$ value)",
+
+    "if (value == null) {\n"
+    "  throw new NullPointerException();\n"
     "}\n"
-    "public Builder set$capitalized_name$(int index, "
-      "$type$.Builder builderForValue) {\n"
-    "  result.$name$_.set(index, builderForValue.build());\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder add$capitalized_name$($type$ value) {\n"
-    "  if (value == null) {\n"
-    "    throw new NullPointerException();\n"
-    "  }\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
-    "  }\n"
-    "  result.$name$_.add(value);\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder add$capitalized_name$($type$.Builder builderForValue) {\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
-    "  }\n"
-    "  result.$name$_.add(builderForValue.build());\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder addAll$capitalized_name$(\n"
-    "    java.lang.Iterable<? extends $type$> values) {\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
-    "  }\n"
-    "  super.addAll(values, result.$name$_);\n"
-    "  return this;\n"
-    "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.$name$_ = java.util.Collections.emptyList();\n"
-    "  return this;\n"
-    "}\n");
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(index, value);\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.addMessage(index, value);\n",
+
+    "return this;\n");
+
+  // Builder addRepeatedField(Field.Builder builderForValue)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    $type$.Builder builderForValue)",
+
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(builderForValue.build());\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.addMessage(builderForValue.build());\n",
+
+    "return this;\n");
+
+  // Builder addRepeatedField(int index, Field.Builder builderForValue)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder add$capitalized_name$(\n"
+    "    int index, $type$.Builder builderForValue)",
+
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(index, builderForValue.build());\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.addMessage(index, builderForValue.build());\n",
+
+    "return this;\n");
+
+  // Builder addAllRepeatedField(Iterable<Field> values)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<? extends $type$> values)",
+
+    "ensure$capitalized_name$IsMutable();\n"
+    "super.addAll(values, $name$_);\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.addAllMessages(values);\n",
+
+    "return this;\n");
+
+  // Builder clearAllRepeatedField()
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder clear$capitalized_name$()",
+
+    "$name$_ = java.util.Collections.emptyList();\n"
+    "$clear_mutable_bit_builder$;\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.clear();\n",
+
+    "return this;\n");
+
+  // Builder removeRepeatedField(int index)
+  PrintNestedBuilderFunction(printer,
+    "$deprecation$public Builder remove$capitalized_name$(int index)",
+
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.remove(index);\n"
+    "$on_changed$\n",
+
+    "$name$Builder_.remove(index);\n",
+
+    "return this;\n");
+
+  if (HasNestedBuilders(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n"
+      "    int index) {\n"
+      "  return get$capitalized_name$FieldBuilder().getBuilder(index);\n"
+      "}\n"
+
+      "$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"
+
+      "$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"
+
+      "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n"
+      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+      "      $type$.getDefaultInstance());\n"
+      "}\n"
+      "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n"
+      "    int index) {\n"
+      "  return get$capitalized_name$FieldBuilder().addBuilder(\n"
+      "      index, $type$.getDefaultInstance());\n"
+      "}\n"
+      "$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 RepeatedMessageFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  printer->Print(variables_,
+    "get$capitalized_name$FieldBuilder();\n");
 }
 
 void RepeatedMessageFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  // Initialized inline.
+  printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  PrintNestedBuilderCondition(printer,
+    "$name$_ = java.util.Collections.emptyList();\n"
+    "$clear_mutable_bit_builder$;\n",
+
+    "$name$Builder_.clear();\n");
 }
 
 void RepeatedMessageFieldGenerator::
 GenerateMergingCode(io::Printer* printer) const {
-  printer->Print(variables_,
+  // 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.
+  PrintNestedBuilderCondition(printer,
     "if (!other.$name$_.isEmpty()) {\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "    $clear_mutable_bit_builder$;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  result.$name$_.addAll(other.$name$_);\n"
+    "  $on_changed$\n"
+    "}\n",
+
+    "if (!other.$name$_.isEmpty()) {\n"
+    "  if ($name$Builder_.isEmpty()) {\n"
+    "    $name$Builder_.dispose();\n"
+    "    $name$Builder_ = null;\n"
+    "    $name$_ = other.$name$_;\n"
+    "    $clear_mutable_bit_builder$;\n"
+    "    $name$Builder_ = \n"
+    "      com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n"
+    "         get$capitalized_name$FieldBuilder() : null;\n"
+    "  } else {\n"
+    "    $name$Builder_.addAllMessages(other.$name$_);\n"
+    "  }\n"
     "}\n");
 }
 
 void RepeatedMessageFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
-  printer->Print(variables_,
-    "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
-    "  result.$name$_ =\n"
-    "    java.util.Collections.unmodifiableList(result.$name$_);\n"
-    "}\n");
+  // The code below (non-nested builder case) ensures that the result has an
+  // immutable list. If our list is immutable, we can just reuse it. If not,
+  // we make it immutable.
+  PrintNestedBuilderCondition(printer,
+    "if ($get_mutable_bit_builder$) {\n"
+    "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n",
+
+    "result.$name$_ = $name$Builder_.build();\n");
 }
 
 void RepeatedMessageFieldGenerator::
@@ -311,17 +844,33 @@
 void RepeatedMessageFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "for ($type$ element : get$capitalized_name$List()) {\n"
-    "  output.write$group_or_message$($number$, element);\n"
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
+    "  output.write$group_or_message$($number$, $name$_.get(i));\n"
     "}\n");
 }
 
 void RepeatedMessageFieldGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "for ($type$ element : get$capitalized_name$List()) {\n"
+    "for (int i = 0; i < $name$_.size(); i++) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .compute$group_or_message$Size($number$, element);\n"
+    "    .compute$group_or_message$Size($number$, $name$_.get(i));\n"
+    "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedMessageFieldGenerator::
+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");
 }
 
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 66bdd88..2efbcd9 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -46,50 +46,84 @@
 
 class MessageFieldGenerator : public FieldGenerator {
  public:
-  explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
+  explicit MessageFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~MessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+
+  void PrintNestedBuilderCondition(io::Printer* printer,
+      const char* regular_case, const char* nested_builder_case) const;
+  void PrintNestedBuilderFunction(io::Printer* printer,
+      const char* method_prototype, const char* regular_case,
+      const char* nested_builder_case,
+      const char* trailing_code) const;
 };
 
 class RepeatedMessageFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~RepeatedMessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+
+  void PrintNestedBuilderCondition(io::Printer* printer,
+      const char* regular_case, const char* nested_builder_case) const;
+  void PrintNestedBuilderFunction(io::Printer* printer,
+      const char* method_prototype, const char* regular_case,
+      const char* nested_builder_case,
+      const char* trailing_code) const;
 };
 
 }  // namespace java
diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
index cfe0188..ccc94c9 100644
--- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc
@@ -56,21 +56,22 @@
 
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* context,
                         string* error) const {
-    TryInsert("Test.java", "outer_class_scope", output_directory);
-    TryInsert("Test.java", "class_scope:foo.Bar", output_directory);
-    TryInsert("Test.java", "class_scope:foo.Bar.Baz", output_directory);
-    TryInsert("Test.java", "builder_scope:foo.Bar", output_directory);
-    TryInsert("Test.java", "builder_scope:foo.Bar.Baz", output_directory);
-    TryInsert("Test.java", "enum_scope:foo.Qux", output_directory);
+    string filename = "Test.java";
+    TryInsert(filename, "outer_class_scope", context);
+    TryInsert(filename, "class_scope:foo.Bar", context);
+    TryInsert(filename, "class_scope:foo.Bar.Baz", context);
+    TryInsert(filename, "builder_scope:foo.Bar", context);
+    TryInsert(filename, "builder_scope:foo.Bar.Baz", context);
+    TryInsert(filename, "enum_scope:foo.Qux", context);
     return true;
   }
 
   void TryInsert(const string& filename, const string& insertion_point,
-                 OutputDirectory* output_directory) const {
+                 GeneratorContext* context) const {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      output_directory->OpenForInsert(filename, insertion_point));
+      context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
   }
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index f6179bf..addb881 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -154,15 +154,24 @@
 }
 
 void SetPrimitiveVariables(const FieldDescriptor* descriptor,
+                           int messageBitIndex,
+                           int builderBitIndex,
                            map<string, string>* variables) {
   (*variables)["name"] =
     UnderscoresToCamelCase(descriptor);
   (*variables)["capitalized_name"] =
     UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["constant_name"] = FieldConstantName(descriptor);
   (*variables)["number"] = SimpleItoa(descriptor->number());
   (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
   (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["field_type"] = (*variables)["type"];
+  (*variables)["field_list_type"] = "java.util.List<" +
+      (*variables)["boxed_type"] + ">";
+  (*variables)["empty_list"] = "java.util.Collections.emptyList();";
   (*variables)["default"] = DefaultValue(descriptor);
+  (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
+      "" : ("= " + DefaultValue(descriptor));
   (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
   (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
@@ -175,67 +184,135 @@
   } 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();" : "";
+
+  // For singular messages and builders, one bit is used for the hasField bit.
+  (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+  (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_has_field_bit_builder"] =
+      GenerateClearBit(builderBitIndex);
+
+  // For repated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
 }
+
 }  // namespace
 
 // ===================================================================
 
 PrimitiveFieldGenerator::
-PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetPrimitiveVariables(descriptor, &variables_);
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                        int messageBitIndex,
+                        int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        &variables_);
 }
 
 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
 
+int PrimitiveFieldGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int PrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void PrimitiveFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$boolean has$capitalized_name$();\n"
+    "$deprecation$$type$ get$capitalized_name$();\n");
+}
+
 void PrimitiveFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private boolean has$capitalized_name$;\n"
-    "private $type$ $name$_ = $default$;\n"
-    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
-    "public $type$ get$capitalized_name$() { return $name$_; }\n");
+    "private $field_type$ $name$_;\n"
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
 }
 
 void PrimitiveFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "public boolean has$capitalized_name$() {\n"
-    "  return result.has$capitalized_name$();\n"
-    "}\n"
-    "public $type$ get$capitalized_name$() {\n"
-    "  return result.get$capitalized_name$();\n"
-    "}\n"
-    "public Builder set$capitalized_name$($type$ value) {\n"
+    "private $field_type$ $name$_ $default_init$;\n"
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_builder$;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  return $name$_;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$($type$ value) {\n"
     "$null_check$"
-    "  result.has$capitalized_name$ = true;\n"
-    "  result.$name$_ = value;\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $name$_ = value;\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.has$capitalized_name$ = false;\n");
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_builder$;\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_,
-      "  result.$name$_ = getDefaultInstance().get$capitalized_name$();\n");
+      "  $name$_ = getDefaultInstance().get$capitalized_name$();\n");
   } else {
     printer->Print(variables_,
-      "  result.$name$_ = $default$;\n");
+      "  $name$_ = $default$;\n");
   }
   printer->Print(variables_,
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n");
 }
 
 void PrimitiveFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void PrimitiveFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  // Initialized inline.
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $default$;\n"
+    "$clear_has_field_bit_builder$;\n");
 }
 
 void PrimitiveFieldGenerator::
@@ -248,32 +325,121 @@
 
 void PrimitiveFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
-  // Nothing to do here for primitive types.
+  printer->Print(variables_,
+    "if ($get_has_field_bit_from_local$) {\n"
+    "  $set_has_field_bit_to_local$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
 }
 
 void PrimitiveFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "set$capitalized_name$(input.read$capitalized_type$());\n");
+    "$set_has_field_bit_builder$;\n"
+    "$name$_ = input.read$capitalized_type$();\n");
 }
 
 void PrimitiveFieldGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
-    "  output.write$capitalized_type$($number$, get$capitalized_name$());\n"
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.write$capitalized_type$($number$, $name$_);\n"
     "}\n");
 }
 
 void PrimitiveFieldGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if (has$capitalized_name$()) {\n"
+    "if ($get_has_field_bit_message$) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
-    "    .compute$capitalized_type$Size($number$, get$capitalized_name$());\n"
+    "    .compute$capitalized_type$Size($number$, $name$_);\n"
     "}\n");
 }
 
+void PrimitiveFieldGenerator::
+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 && (Float.floatToIntBits(get$capitalized_name$())"
+        "    == Float.floatToIntBits(other.get$capitalized_name$()));\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "result = result && (Double.doubleToLongBits(get$capitalized_name$())"
+        "    == Double.doubleToLongBits(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 PrimitiveFieldGenerator::
+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) + hashLong(get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_BOOLEAN:
+      printer->Print(variables_,
+        "hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_FLOAT:
+      printer->Print(variables_,
+        "hash = (53 * hash) + Float.floatToIntBits(\n"
+        "    get$capitalized_name$());\n");
+      break;
+
+    case JAVATYPE_DOUBLE:
+      printer->Print(variables_,
+        "hash = (53 * hash) + hashLong(\n"
+        "    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 PrimitiveFieldGenerator::GetBoxedType() const {
   return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
 }
@@ -281,23 +447,46 @@
 // ===================================================================
 
 RepeatedPrimitiveFieldGenerator::
-RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
-  : descriptor_(descriptor) {
-  SetPrimitiveVariables(descriptor, &variables_);
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+                                int messageBitIndex,
+                                int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        &variables_);
 }
 
 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
 
+int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"
+    "$deprecation$int get$capitalized_name$Count();\n"
+    "$deprecation$$type$ get$capitalized_name$(int index);\n");
+}
+
+
 void RepeatedPrimitiveFieldGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private java.util.List<$boxed_type$> $name$_ =\n"
-    "  java.util.Collections.emptyList();\n"
-    "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
+    "private $field_list_type$ $name$_;\n"
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
     "  return $name$_;\n"   // note:  unmodifiable list
     "}\n"
-    "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n"
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
     "  return $name$_.get(index);\n"
     "}\n");
 
@@ -310,76 +499,125 @@
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
+  // One field is the list and the bit field keeps track of whether the
+  // list is immutable. If it's immutable, the invariant is that it must
+  // either an instance of Collections.emptyList() or it's an ArrayList
+  // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+  // a refererence to the underlying ArrayList. This invariant allows us to
+  // share instances of lists between protocol buffers avoiding expensive
+  // memory allocations. Note, immutable is a strong guarantee here -- not
+  // just that the list cannot be modified via the reference but that the
+  // list can never be modified.
   printer->Print(variables_,
+    "private $field_list_type$ $name$_ = $empty_list$;\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$get_mutable_bit_builder$) {\n"
+    "    $name$_ = new java.util.ArrayList<$boxed_type$>($name$_);\n"
+    "    $set_mutable_bit_builder$;\n"
+    "   }\n"
+    "}\n");
+
     // Note:  We return an unmodifiable list because otherwise the caller
     //   could hold on to the returned list and modify it after the message
     //   has been built, thus mutating the message which is supposed to be
     //   immutable.
-    "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
-    "  return java.util.Collections.unmodifiableList(result.$name$_);\n"
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<$boxed_type$>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList($name$_);\n"
     "}\n"
-    "public int get$capitalized_name$Count() {\n"
-    "  return result.get$capitalized_name$Count();\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
     "}\n"
-    "public $type$ get$capitalized_name$(int index) {\n"
-    "  return result.get$capitalized_name$(index);\n"
+    "$deprecation$public $type$ get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
     "}\n"
-    "public Builder set$capitalized_name$(int index, $type$ value) {\n"
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, $type$ value) {\n"
     "$null_check$"
-    "  result.$name$_.set(index, value);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder add$capitalized_name$($type$ value) {\n"
+    "$deprecation$public Builder add$capitalized_name$($type$ value) {\n"
     "$null_check$"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
-    "  }\n"
-    "  result.$name$_.add(value);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder addAll$capitalized_name$(\n"
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
     "    java.lang.Iterable<? extends $boxed_type$> values) {\n"
-    "  if (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
-    "  }\n"
-    "  super.addAll(values, result.$name$_);\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  super.addAll(values, $name$_);\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n"
-    "public Builder clear$capitalized_name$() {\n"
-    "  result.$name$_ = java.util.Collections.emptyList();\n"
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "  $on_changed$\n"
     "  return this;\n"
     "}\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void RepeatedPrimitiveFieldGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  // Initialized inline.
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $empty_list$;\n"
+    "$clear_mutable_bit_builder$;\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
 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 (result.$name$_.isEmpty()) {\n"
-    "    result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+    "  if ($name$_.isEmpty()) {\n"
+    "    $name$_ = other.$name$_;\n"
+    "    $clear_mutable_bit_builder$;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  result.$name$_.addAll(other.$name$_);\n"
+    "  $on_changed$\n"
     "}\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateBuildingCode(io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
   printer->Print(variables_,
-    "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
-    "  result.$name$_ =\n"
-    "    java.util.Collections.unmodifiableList(result.$name$_);\n"
-    "}\n");
+    "if ($get_mutable_bit_builder$) {\n"
+    "  $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "add$capitalized_name$(input.read$capitalized_type$());\n");
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(input.read$capitalized_type$());\n");
 }
 
 void RepeatedPrimitiveFieldGenerator::
@@ -401,13 +639,13 @@
       "  output.writeRawVarint32($tag$);\n"
       "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
       "}\n"
-      "for ($type$ element : get$capitalized_name$List()) {\n"
-      "  output.write$capitalized_type$NoTag(element);\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 ($type$ element : get$capitalized_name$List()) {\n"
-      "  output.write$capitalized_type$($number$, element);\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
+      "  output.write$capitalized_type$($number$, $name$_.get(i));\n"
       "}\n");
   }
 }
@@ -421,9 +659,9 @@
 
   if (FixedSize(GetType(descriptor_)) == -1) {
     printer->Print(variables_,
-      "for ($type$ element : get$capitalized_name$List()) {\n"
+      "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  dataSize += com.google.protobuf.CodedOutputStream\n"
-      "    .compute$capitalized_type$SizeNoTag(element);\n"
+      "    .compute$capitalized_type$SizeNoTag($name$_.get(i));\n"
       "}\n");
   } else {
     printer->Print(variables_,
@@ -455,6 +693,22 @@
   printer->Print("}\n");
 }
 
+void RepeatedPrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+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 RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
   return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
 }
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index 4e482a0..7900fac 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -46,49 +46,69 @@
 
 class PrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~PrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
 };
 
 class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
   ~RepeatedPrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(io::Printer* printer) const;
   void GenerateParsingCodeFromPacked(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_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
 };
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 5545bf7..1ae4f46 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -118,7 +118,7 @@
 
   for (int i = 0; i < descriptor_->method_count(); i++) {
     const MethodDescriptor* method = descriptor_->method(i);
-    printer->Print("@Override\n");
+    printer->Print("@java.lang.Override\n");
     GenerateMethodSignature(printer, method, IS_CONCRETE);
     printer->Print(
       " {\n"
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
new file mode 100644
index 0000000..a93ff43
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -0,0 +1,605 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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/compiler/java/java_string_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_helpers.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,
+                           map<string, string>* variables) {
+  (*variables)["name"] =
+    UnderscoresToCamelCase(descriptor);
+  (*variables)["capitalized_name"] =
+    UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["constant_name"] = FieldConstantName(descriptor);
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY";
+
+  (*variables)["default"] = DefaultValue(descriptor);
+  (*variables)["default_init"] = ("= " + DefaultValue(descriptor));
+  (*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();" : "";
+
+  // For singular messages and builders, one bit is used for the hasField bit.
+  (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
+
+  (*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_has_field_bit_builder"] =
+      GenerateClearBit(builderBitIndex);
+
+  // For repated builders, one bit is used for whether the array is immutable.
+  (*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
+  (*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
+  (*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
+
+  (*variables)["get_has_field_bit_from_local"] =
+      GenerateGetBitFromLocal(builderBitIndex);
+  (*variables)["set_has_field_bit_to_local"] =
+      GenerateSetBitToLocal(messageBitIndex);
+}
+
+}  // namespace
+
+// ===================================================================
+
+StringFieldGenerator::
+StringFieldGenerator(const FieldDescriptor* descriptor,
+                     int messageBitIndex,
+                     int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        &variables_);
+}
+
+StringFieldGenerator::~StringFieldGenerator() {}
+
+int StringFieldGenerator::GetNumBitsForMessage() const {
+  return 1;
+}
+
+int StringFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+// 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 StringFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$boolean has$capitalized_name$();\n"
+    "$deprecation$String get$capitalized_name$();\n");
+}
+
+void StringFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private Object $name$_;\n"
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_message$;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public String get$capitalized_name$() {\n"
+    "  Object ref = $name$_;\n"
+    "  if (ref instanceof String) {\n"
+    "    return (String) ref;\n"
+    "  } else {\n"
+    "    com.google.protobuf.ByteString bs = \n"
+    "        (com.google.protobuf.ByteString) ref;\n"
+    "    String s = bs.toStringUtf8();\n"
+    "    if (com.google.protobuf.Internal.isValidUtf8(bs)) {\n"
+    "      $name$_ = s;\n"
+    "    }\n"
+    "    return s;\n"
+    "  }\n"
+    "}\n"
+    "private com.google.protobuf.ByteString get$capitalized_name$Bytes() {\n"
+    "  Object ref = $name$_;\n"
+    "  if (ref instanceof String) {\n"
+    "    com.google.protobuf.ByteString b = \n"
+    "        com.google.protobuf.ByteString.copyFromUtf8((String) ref);\n"
+    "    $name$_ = b;\n"
+    "    return b;\n"
+    "  } else {\n"
+    "    return (com.google.protobuf.ByteString) ref;\n"
+    "  }\n"
+    "}\n");
+}
+
+void StringFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private Object $name$_ $default_init$;\n"
+    "$deprecation$public boolean has$capitalized_name$() {\n"
+    "  return $get_has_field_bit_builder$;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public String get$capitalized_name$() {\n"
+    "  Object ref = $name$_;\n"
+    "  if (!(ref instanceof String)) {\n"
+    "    String s = ((com.google.protobuf.ByteString) ref).toStringUtf8();\n"
+    "    $name$_ = s;\n"
+    "    return s;\n"
+    "  } else {\n"
+    "    return (String) ref;\n"
+    "  }\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "$deprecation$public Builder set$capitalized_name$(String value) {\n"
+    "$null_check$"
+    "  $set_has_field_bit_builder$;\n"
+    "  $name$_ = value;\n"
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n"
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $clear_has_field_bit_builder$;\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.
+  printer->Print(variables_,
+    "  $name$_ = getDefaultInstance().get$capitalized_name$();\n");
+  printer->Print(variables_,
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "void set$capitalized_name$(com.google.protobuf.ByteString value) {\n"
+    "  $set_has_field_bit_builder$;\n"
+    "  $name$_ = value;\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void StringFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void StringFieldGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $default$;\n");
+}
+
+void StringFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $default$;\n"
+    "$clear_has_field_bit_builder$;\n");
+}
+
+void StringFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  set$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void StringFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($get_has_field_bit_from_local$) {\n"
+    "  $set_has_field_bit_to_local$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
+}
+
+void StringFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$set_has_field_bit_builder$;\n"
+    "$name$_ = input.readBytes();\n");
+}
+
+void StringFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  output.writeBytes($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+void StringFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if ($get_has_field_bit_message$) {\n"
+    "  size += com.google.protobuf.CodedOutputStream\n"
+    "    .computeBytesSize($number$, get$capitalized_name$Bytes());\n"
+    "}\n");
+}
+
+void StringFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$()\n"
+    "    .equals(other.get$capitalized_name$());\n");
+}
+
+void StringFieldGenerator::
+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 StringFieldGenerator::GetBoxedType() const {
+  return "String";
+}
+
+
+// ===================================================================
+
+RepeatedStringFieldGenerator::
+RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+                             int messageBitIndex,
+                             int builderBitIndex)
+  : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
+    builderBitIndex_(builderBitIndex) {
+  SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex,
+                        &variables_);
+}
+
+RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
+
+int RepeatedStringFieldGenerator::GetNumBitsForMessage() const {
+  return 0;
+}
+
+int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const {
+  return 1;
+}
+
+void RepeatedStringFieldGenerator::
+GenerateInterfaceMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$deprecation$java.util.List<String> get$capitalized_name$List();\n"
+    "$deprecation$int get$capitalized_name$Count();\n"
+    "$deprecation$String get$capitalized_name$(int index);\n");
+}
+
+
+void RepeatedStringFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private com.google.protobuf.LazyStringList $name$_;\n"
+    "$deprecation$public java.util.List<String>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return $name$_;\n"   // note:  unmodifiable list
+    "}\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n"
+    "$deprecation$public String get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n");
+
+  if (descriptor_->options().packed() &&
+      HasGeneratedMethods(descriptor_->containing_type())) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize = -1;\n");
+  }
+}
+
+void RepeatedStringFieldGenerator::
+GenerateBuilderMembers(io::Printer* printer) const {
+  // One field is the list and the bit field keeps track of whether the
+  // list is immutable. If it's immutable, the invariant is that it must
+  // either an instance of Collections.emptyList() or it's an ArrayList
+  // wrapped in a Collections.unmodifiableList() wrapper and nobody else has
+  // a refererence to the underlying ArrayList. This invariant allows us to
+  // share instances of lists between protocol buffers avoiding expensive
+  // memory allocations. Note, immutable is a strong guarantee here -- not
+  // just that the list cannot be modified via the reference but that the
+  // list can never be modified.
+  printer->Print(variables_,
+    "private com.google.protobuf.LazyStringList $name$_ = $empty_list$;\n");
+
+  printer->Print(variables_,
+    "private void ensure$capitalized_name$IsMutable() {\n"
+    "  if (!$get_mutable_bit_builder$) {\n"
+    "    $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n"
+    "    $set_mutable_bit_builder$;\n"
+    "   }\n"
+    "}\n");
+
+    // Note:  We return an unmodifiable list because otherwise the caller
+    //   could hold on to the returned list and modify it after the message
+    //   has been built, thus mutating the message which is supposed to be
+    //   immutable.
+  printer->Print(variables_,
+    "$deprecation$public java.util.List<String>\n"
+    "    get$capitalized_name$List() {\n"
+    "  return java.util.Collections.unmodifiableList($name$_);\n"
+    "}\n"
+    "$deprecation$public int get$capitalized_name$Count() {\n"
+    "  return $name$_.size();\n"
+    "}\n"
+    "$deprecation$public String get$capitalized_name$(int index) {\n"
+    "  return $name$_.get(index);\n"
+    "}\n"
+    "$deprecation$public Builder set$capitalized_name$(\n"
+    "    int index, String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.set(index, value);\n"
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n"
+    "$deprecation$public Builder add$capitalized_name$(String value) {\n"
+    "$null_check$"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n"
+    "$deprecation$public Builder addAll$capitalized_name$(\n"
+    "    java.lang.Iterable<String> values) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  super.addAll(values, $name$_);\n"
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n"
+    "$deprecation$public Builder clear$capitalized_name$() {\n"
+    "  $name$_ = $empty_list$;\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "  $on_changed$\n"
+    "  return this;\n"
+    "}\n");
+
+  printer->Print(variables_,
+    "void add$capitalized_name$(com.google.protobuf.ByteString value) {\n"
+    "  ensure$capitalized_name$IsMutable();\n"
+    "  $name$_.add(value);\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
+  // noop for primitives
+}
+
+void RepeatedStringFieldGenerator::
+GenerateInitializationCode(io::Printer* printer) const {
+  printer->Print(variables_, "$name$_ = $empty_list$;\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateBuilderClearCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$name$_ = $empty_list$;\n"
+    "$clear_mutable_bit_builder$;\n");
+}
+
+void RepeatedStringFieldGenerator::
+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"
+    "    $clear_mutable_bit_builder$;\n"
+    "  } else {\n"
+    "    ensure$capitalized_name$IsMutable();\n"
+    "    $name$_.addAll(other.$name$_);\n"
+    "  }\n"
+    "  $on_changed$\n"
+    "}\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateBuildingCode(io::Printer* printer) const {
+  // The code below ensures that the result has an immutable list. If our
+  // list is immutable, we can just reuse it. If not, we make it immutable.
+
+  printer->Print(variables_,
+    "if ($get_mutable_bit_builder$) {\n"
+    "  $name$_ = new com.google.protobuf.UnmodifiableLazyStringList(\n"
+    "      $name$_);\n"
+    "  $clear_mutable_bit_builder$;\n"
+    "}\n"
+    "result.$name$_ = $name$_;\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "ensure$capitalized_name$IsMutable();\n"
+    "$name$_.add(input.readBytes());\n");
+}
+
+void RepeatedStringFieldGenerator::
+GenerateParsingCodeFromPacked(io::Printer* printer) const {
+  printer->Print(variables_,
+    "int length = input.readRawVarint32();\n"
+    "int limit = input.pushLimit(length);\n"
+    "while (input.getBytesUntilLimit() > 0) {\n"
+    "  add$capitalized_name$(input.read$capitalized_type$());\n"
+    "}\n"
+    "input.popLimit(limit);\n");
+}
+
+void RepeatedStringFieldGenerator::
+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 RepeatedStringFieldGenerator::
+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 RepeatedStringFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "result = result && get$capitalized_name$List()\n"
+    "    .equals(other.get$capitalized_name$List());\n");
+}
+
+void RepeatedStringFieldGenerator::
+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 RepeatedStringFieldGenerator::GetBoxedType() const {
+  return "String";
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
new file mode 100644
index 0000000..8cb4146
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -0,0 +1,120 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/java/java_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+class StringFieldGenerator : public FieldGenerator {
+ public:
+  explicit StringFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
+  ~StringFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(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_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
+};
+
+class RepeatedStringFieldGenerator : public FieldGenerator {
+ public:
+  explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
+      int messageBitIndex, int builderBitIndex);
+  ~RepeatedStringFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  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 GenerateParsingCode(io::Printer* printer) const;
+  void GenerateParsingCodeFromPacked(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_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 83d5a4e..5b76af2 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -45,6 +45,16 @@
 namespace protobuf {
 namespace compiler {
 
+// Returns the list of the names of files in all_files in the form of a
+// comma-separated string.
+string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
+  vector<string> names;
+  for (int i = 0; i < all_files.size(); i++) {
+    names.push_back(all_files[i]->name());
+  }
+  return JoinStrings(names, ",");
+}
+
 static const char* kFirstInsertionPointName = "first_mock_insertion_point";
 static const char* kSecondInsertionPointName = "second_mock_insertion_point";
 static const char* kFirstInsertionPoint =
@@ -63,6 +73,7 @@
     const string& insertions,
     const string& file,
     const string& first_message_name,
+    const string& first_parsed_file_name,
     const string& output_directory) {
   string content;
   ASSERT_TRUE(File::ReadFileToString(
@@ -84,7 +95,8 @@
   }
 
   ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
-  EXPECT_EQ(GetOutputFileContent(name, parameter, file, first_message_name),
+  EXPECT_EQ(GetOutputFileContent(name, parameter, file,
+                                 first_parsed_file_name, first_message_name),
             lines[0]);
 
   EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
@@ -92,12 +104,12 @@
 
   for (int i = 0; i < insertion_list.size(); i++) {
     EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
-                                   file, first_message_name),
+                                   file, file, first_message_name),
               lines[1 + i]);
     // Second insertion point is indented, so the inserted text should
     // automatically be indented too.
     EXPECT_EQ("  " + GetOutputFileContent(insertion_list[i], "second_insert",
-                                          file, first_message_name),
+                                          file, file, first_message_name),
               lines[2 + insertion_list.size() + i]);
   }
 }
@@ -105,7 +117,7 @@
 bool MockCodeGenerator::Generate(
     const FileDescriptor* file,
     const string& parameter,
-    OutputDirectory* output_directory,
+    GeneratorContext* context,
     string* error) const {
   for (int i = 0; i < file->message_type_count(); i++) {
     if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
@@ -134,11 +146,12 @@
     for (int i = 0; i < insert_into.size(); i++) {
       {
         scoped_ptr<io::ZeroCopyOutputStream> output(
-            output_directory->OpenForInsert(
+            context->OpenForInsert(
               GetOutputFileName(insert_into[i], file),
               kFirstInsertionPointName));
         io::Printer printer(output.get(), '$');
-        printer.PrintRaw(GetOutputFileContent(name_, "first_insert", file));
+        printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
+                                              file, context));
         if (printer.failed()) {
           *error = "MockCodeGenerator detected write error.";
           return false;
@@ -147,11 +160,12 @@
 
       {
         scoped_ptr<io::ZeroCopyOutputStream> output(
-            output_directory->OpenForInsert(
+            context->OpenForInsert(
               GetOutputFileName(insert_into[i], file),
               kSecondInsertionPointName));
         io::Printer printer(output.get(), '$');
-        printer.PrintRaw(GetOutputFileContent(name_, "second_insert", file));
+        printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
+                                              file, context));
         if (printer.failed()) {
           *error = "MockCodeGenerator detected write error.";
           return false;
@@ -160,10 +174,11 @@
     }
   } else {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-        output_directory->Open(GetOutputFileName(name_, file)));
+        context->Open(GetOutputFileName(name_, file)));
 
     io::Printer printer(output.get(), '$');
-    printer.PrintRaw(GetOutputFileContent(name_, parameter, file));
+    printer.PrintRaw(GetOutputFileContent(name_, parameter,
+                                          file, context));
     printer.PrintRaw(kFirstInsertionPoint);
     printer.PrintRaw(kSecondInsertionPoint);
 
@@ -186,11 +201,16 @@
   return file + ".MockCodeGenerator." + generator_name;
 }
 
-string MockCodeGenerator::GetOutputFileContent(const string& generator_name,
-                                               const string& parameter,
-                                               const FileDescriptor* file) {
+string MockCodeGenerator::GetOutputFileContent(
+    const string& generator_name,
+    const string& parameter,
+    const FileDescriptor* file,
+    GeneratorContext *context) {
+  vector<const FileDescriptor*> all_files;
+  context->ListParsedFiles(&all_files);
   return GetOutputFileContent(
       generator_name, parameter, file->name(),
+      CommaSeparatedList(all_files),
       file->message_type_count() > 0 ?
           file->message_type(0)->name() : "(none)");
 }
@@ -199,9 +219,11 @@
     const string& generator_name,
     const string& parameter,
     const string& file,
+    const string& parsed_file_list,
     const string& first_message_name) {
-  return strings::Substitute("$0: $1, $2, $3\n",
-      generator_name, parameter, file, first_message_name);
+  return strings::Substitute("$0: $1, $2, $3, $4\n",
+      generator_name, parameter, file,
+      first_message_name, parsed_file_list);
 }
 
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 01d69dd..5c7942b 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -69,11 +69,14 @@
   //
   // |insertions| is a comma-separated list of names of MockCodeGenerators which
   // should have inserted lines into this file.
+  // |parsed_file_list| is a comma-separated list of names of the files
+  // that are being compiled together in this run.
   static void ExpectGenerated(const string& name,
                               const string& parameter,
                               const string& insertions,
                               const string& file,
                               const string& first_message_name,
+                              const string& parsed_file_list,
                               const string& output_directory);
 
   // Get the name of the file which would be written by the given generator.
@@ -86,7 +89,7 @@
 
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* context,
                         string* error) const;
 
  private:
@@ -94,10 +97,12 @@
 
   static string GetOutputFileContent(const string& generator_name,
                                      const string& parameter,
-                                     const FileDescriptor* file);
+                                     const FileDescriptor* file,
+                                     GeneratorContext *context);
   static string GetOutputFileContent(const string& generator_name,
                                      const string& parameter,
                                      const string& file,
+                                     const string& parsed_file_list,
                                      const string& first_message_name);
 };
 
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 9fcb131..34317b1 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -250,20 +250,69 @@
   AddError(input_->current().line, input_->current().column, error);
 }
 
-void Parser::RecordLocation(
-    const Message* descriptor,
-    DescriptorPool::ErrorCollector::ErrorLocation location,
-    int line, int column) {
-  if (source_location_table_ != NULL) {
-    source_location_table_->Add(descriptor, location, line, column);
+// -------------------------------------------------------------------
+
+Parser::LocationRecorder::LocationRecorder(Parser* parser)
+  : parser_(parser),
+    location_(parser_->source_code_info_->add_location()) {
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) {
+  Init(parent);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1) {
+  Init(parent);
+  AddPath(path1);
+}
+
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
+                                           int path1, int path2) {
+  Init(parent);
+  AddPath(path1);
+  AddPath(path2);
+}
+
+void Parser::LocationRecorder::Init(const LocationRecorder& parent) {
+  parser_ = parent.parser_;
+  location_ = parser_->source_code_info_->add_location();
+  location_->mutable_path()->CopyFrom(parent.location_->path());
+
+  location_->add_span(parser_->input_->current().line);
+  location_->add_span(parser_->input_->current().column);
+}
+
+Parser::LocationRecorder::~LocationRecorder() {
+  if (location_->span_size() <= 2) {
+    EndAt(parser_->input_->previous());
   }
 }
 
-void Parser::RecordLocation(
-    const Message* descriptor,
+void Parser::LocationRecorder::AddPath(int path_component) {
+  location_->add_path(path_component);
+}
+
+void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) {
+  location_->set_span(0, token.line);
+  location_->set_span(1, token.column);
+}
+
+void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) {
+  if (token.line != location_->span(0)) {
+    location_->add_span(token.line);
+  }
+  location_->add_span(token.end_column);
+}
+
+void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
     DescriptorPool::ErrorCollector::ErrorLocation location) {
-  RecordLocation(descriptor, location,
-                 input_->current().line, input_->current().column);
+  if (parser_->source_location_table_ != NULL) {
+    parser_->source_location_table_->Add(
+        descriptor, location, location_->span(0), location_->span(1));
+  }
 }
 
 // -------------------------------------------------------------------
@@ -308,38 +357,51 @@
   had_errors_ = false;
   syntax_identifier_.clear();
 
+  // Note that |file| could be NULL at this point if
+  // stop_after_syntax_identifier_ is true.  So, we conservatively allocate
+  // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto
+  // later on.
+  SourceCodeInfo source_code_info;
+  source_code_info_ = &source_code_info;
+
   if (LookingAtType(io::Tokenizer::TYPE_START)) {
     // Advance to first token.
     input_->Next();
   }
 
-  if (require_syntax_identifier_ || LookingAt("syntax")) {
-    if (!ParseSyntaxIdentifier()) {
-      // Don't attempt to parse the file if we didn't recognize the syntax
-      // identifier.
-      return false;
+  {
+    LocationRecorder root_location(this);
+
+    if (require_syntax_identifier_ || LookingAt("syntax")) {
+      if (!ParseSyntaxIdentifier()) {
+        // Don't attempt to parse the file if we didn't recognize the syntax
+        // identifier.
+        return false;
+      }
+    } else if (!stop_after_syntax_identifier_) {
+      syntax_identifier_ = "proto2";
     }
-  } else if (!stop_after_syntax_identifier_) {
-    syntax_identifier_ = "proto2";
-  }
 
-  if (stop_after_syntax_identifier_) return !had_errors_;
+    if (stop_after_syntax_identifier_) return !had_errors_;
 
-  // Repeatedly parse statements until we reach the end of the file.
-  while (!AtEnd()) {
-    if (!ParseTopLevelStatement(file)) {
-      // This statement failed to parse.  Skip it, but keep looping to parse
-      // other statements.
-      SkipStatement();
+    // Repeatedly parse statements until we reach the end of the file.
+    while (!AtEnd()) {
+      if (!ParseTopLevelStatement(file, root_location)) {
+        // This statement failed to parse.  Skip it, but keep looping to parse
+        // other statements.
+        SkipStatement();
 
-      if (LookingAt("}")) {
-        AddError("Unmatched \"}\".");
-        input_->Next();
+        if (LookingAt("}")) {
+          AddError("Unmatched \"}\".");
+          input_->Next();
+        }
       }
     }
   }
 
   input_ = NULL;
+  source_code_info_ = NULL;
+  source_code_info.Swap(file->mutable_source_code_info());
   return !had_errors_;
 }
 
@@ -363,25 +425,40 @@
   return true;
 }
 
-bool Parser::ParseTopLevelStatement(FileDescriptorProto* file) {
+bool Parser::ParseTopLevelStatement(FileDescriptorProto* file,
+                                    const LocationRecorder& root_location) {
   if (TryConsume(";")) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("message")) {
-    return ParseMessageDefinition(file->add_message_type());
+    LocationRecorder location(root_location,
+      FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size());
+    return ParseMessageDefinition(file->add_message_type(), location);
   } else if (LookingAt("enum")) {
-    return ParseEnumDefinition(file->add_enum_type());
+    LocationRecorder location(root_location,
+      FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size());
+    return ParseEnumDefinition(file->add_enum_type(), location);
   } else if (LookingAt("service")) {
-    return ParseServiceDefinition(file->add_service());
+    LocationRecorder location(root_location,
+      FileDescriptorProto::kServiceFieldNumber, file->service_size());
+    return ParseServiceDefinition(file->add_service(), location);
   } else if (LookingAt("extend")) {
+    LocationRecorder location(root_location,
+        FileDescriptorProto::kExtensionFieldNumber);
     return ParseExtend(file->mutable_extension(),
-                       file->mutable_message_type());
+                       file->mutable_message_type(),
+                       root_location,
+                       FileDescriptorProto::kMessageTypeFieldNumber,
+                       location);
   } else if (LookingAt("import")) {
-    return ParseImport(file->add_dependency());
+    int index = file->dependency_size();
+    return ParseImport(file->add_dependency(), root_location, index);
   } else if (LookingAt("package")) {
-    return ParsePackage(file);
+    return ParsePackage(file, root_location);
   } else if (LookingAt("option")) {
-    return ParseOption(file->mutable_options());
+    LocationRecorder location(root_location,
+        FileDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(file->mutable_options(), location);
   } else {
     AddError("Expected top-level statement (e.g. \"message\").");
     return false;
@@ -391,15 +468,22 @@
 // -------------------------------------------------------------------
 // Messages
 
-bool Parser::ParseMessageDefinition(DescriptorProto* message) {
+bool Parser::ParseMessageDefinition(DescriptorProto* message,
+                                    const LocationRecorder& message_location) {
   DO(Consume("message"));
-  RecordLocation(message, DescriptorPool::ErrorCollector::NAME);
-  DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
-  DO(ParseMessageBlock(message));
+  {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(
+        message, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(message->mutable_name(), "Expected message name."));
+  }
+  DO(ParseMessageBlock(message, message_location));
   return true;
 }
 
-bool Parser::ParseMessageBlock(DescriptorProto* message) {
+bool Parser::ParseMessageBlock(DescriptorProto* message,
+                               const LocationRecorder& message_location) {
   DO(Consume("{"));
 
   while (!TryConsume("}")) {
@@ -408,7 +492,7 @@
       return false;
     }
 
-    if (!ParseMessageStatement(message)) {
+    if (!ParseMessageStatement(message, message_location)) {
       // This statement failed to parse.  Skip it, but keep looping to parse
       // other statements.
       SkipStatement();
@@ -418,66 +502,133 @@
   return true;
 }
 
-bool Parser::ParseMessageStatement(DescriptorProto* message) {
+bool Parser::ParseMessageStatement(DescriptorProto* message,
+                                   const LocationRecorder& message_location) {
   if (TryConsume(";")) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("message")) {
-    return ParseMessageDefinition(message->add_nested_type());
+    LocationRecorder location(message_location,
+                              DescriptorProto::kNestedTypeFieldNumber,
+                              message->nested_type_size());
+    return ParseMessageDefinition(message->add_nested_type(), location);
   } else if (LookingAt("enum")) {
-    return ParseEnumDefinition(message->add_enum_type());
+    LocationRecorder location(message_location,
+                              DescriptorProto::kEnumTypeFieldNumber,
+                              message->enum_type_size());
+    return ParseEnumDefinition(message->add_enum_type(), location);
   } else if (LookingAt("extensions")) {
-    return ParseExtensions(message);
+    LocationRecorder location(message_location,
+                              DescriptorProto::kExtensionRangeFieldNumber);
+    return ParseExtensions(message, location);
   } else if (LookingAt("extend")) {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kExtensionFieldNumber);
     return ParseExtend(message->mutable_extension(),
-                       message->mutable_nested_type());
+                       message->mutable_nested_type(),
+                       message_location,
+                       DescriptorProto::kNestedTypeFieldNumber,
+                       location);
   } else if (LookingAt("option")) {
-    return ParseOption(message->mutable_options());
+    LocationRecorder location(message_location,
+                              DescriptorProto::kOptionsFieldNumber);
+    return ParseOption(message->mutable_options(), location);
   } else {
+    LocationRecorder location(message_location,
+                              DescriptorProto::kFieldFieldNumber,
+                              message->field_size());
     return ParseMessageField(message->add_field(),
-                             message->mutable_nested_type());
+                             message->mutable_nested_type(),
+                             message_location,
+                             DescriptorProto::kNestedTypeFieldNumber,
+                             location);
   }
 }
 
 bool Parser::ParseMessageField(FieldDescriptorProto* field,
-                               RepeatedPtrField<DescriptorProto>* messages) {
+                               RepeatedPtrField<DescriptorProto>* messages,
+                               const LocationRecorder& parent_location,
+                               int location_field_number_for_nested_type,
+                               const LocationRecorder& field_location) {
   // Parse label and type.
-  FieldDescriptorProto::Label label;
-  DO(ParseLabel(&label));
-  field->set_label(label);
+  io::Tokenizer::Token label_token = input_->current();
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kLabelFieldNumber);
+    FieldDescriptorProto::Label label;
+    DO(ParseLabel(&label));
+    field->set_label(label);
+  }
 
-  RecordLocation(field, DescriptorPool::ErrorCollector::TYPE);
-  FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
-  string type_name;
-  DO(ParseType(&type, &type_name));
-  if (type_name.empty()) {
-    field->set_type(type);
-  } else {
-    field->set_type_name(type_name);
+  {
+    LocationRecorder location(field_location);  // add path later
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE);
+
+    FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32;
+    string type_name;
+    DO(ParseType(&type, &type_name));
+    if (type_name.empty()) {
+      location.AddPath(FieldDescriptorProto::kTypeFieldNumber);
+      field->set_type(type);
+    } else {
+      location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber);
+      field->set_type_name(type_name);
+    }
   }
 
   // Parse name and '='.
-  RecordLocation(field, DescriptorPool::ErrorCollector::NAME);
   io::Tokenizer::Token name_token = input_->current();
-  DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(field->mutable_name(), "Expected field name."));
+  }
   DO(Consume("=", "Missing field number."));
 
   // Parse field number.
-  RecordLocation(field, DescriptorPool::ErrorCollector::NUMBER);
-  int number;
-  DO(ConsumeInteger(&number, "Expected field number."));
-  field->set_number(number);
+  {
+    LocationRecorder location(field_location,
+                              FieldDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(
+        field, DescriptorPool::ErrorCollector::NUMBER);
+    int number;
+    DO(ConsumeInteger(&number, "Expected field number."));
+    field->set_number(number);
+  }
 
   // Parse options.
-  DO(ParseFieldOptions(field));
+  DO(ParseFieldOptions(field, field_location));
 
   // Deal with groups.
-  if (type_name.empty() && type == FieldDescriptorProto::TYPE_GROUP) {
+  if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) {
+    // Awkward:  Since a group declares both a message type and a field, we
+    //   have to create overlapping locations.
+    LocationRecorder group_location(parent_location);
+    group_location.StartAt(label_token);
+    group_location.AddPath(location_field_number_for_nested_type);
+    group_location.AddPath(messages->size());
+
     DescriptorProto* group = messages->Add();
     group->set_name(field->name());
+
     // Record name location to match the field name's location.
-    RecordLocation(group, DescriptorPool::ErrorCollector::NAME,
-                   name_token.line, name_token.column);
+    {
+      LocationRecorder location(group_location,
+                                DescriptorProto::kNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+      location.RecordLegacyLocation(
+          group, DescriptorPool::ErrorCollector::NAME);
+    }
+
+    // The field's type_name also comes from the name.  Confusing!
+    {
+      LocationRecorder location(field_location,
+                                FieldDescriptorProto::kTypeNameFieldNumber);
+      location.StartAt(name_token);
+      location.EndAt(name_token);
+    }
 
     // As a hack for backwards-compatibility, we force the group name to start
     // with a capital letter and lower-case the field name.  New code should
@@ -490,7 +641,7 @@
 
     field->set_type_name(group->name());
     if (LookingAt("{")) {
-      DO(ParseMessageBlock(group));
+      DO(ParseMessageBlock(group, group_location));
     } else {
       AddError("Missing group body.");
       return false;
@@ -502,15 +653,23 @@
   return true;
 }
 
-bool Parser::ParseFieldOptions(FieldDescriptorProto* field) {
-  if (!TryConsume("[")) return true;
+bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
+                               const LocationRecorder& field_location) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
 
   // Parse field options.
   do {
     if (LookingAt("default")) {
-      DO(ParseDefaultAssignment(field));
+      // We intentionally pass field_location rather than location here, since
+      // the default value is not actually an option.
+      DO(ParseDefaultAssignment(field, field_location));
     } else {
-      DO(ParseOptionAssignment(field->mutable_options()));
+      DO(ParseOptionAssignment(field->mutable_options(), location));
     }
   } while (TryConsume(","));
 
@@ -518,7 +677,8 @@
   return true;
 }
 
-bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field) {
+bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field,
+                                    const LocationRecorder& field_location) {
   if (field->has_default_value()) {
     AddError("Already set option \"default\".");
     field->clear_default_value();
@@ -527,7 +687,10 @@
   DO(Consume("default"));
   DO(Consume("="));
 
-  RecordLocation(field, DescriptorPool::ErrorCollector::DEFAULT_VALUE);
+  LocationRecorder location(field_location,
+                            FieldDescriptorProto::kDefaultValueFieldNumber);
+  location.RecordLegacyLocation(
+      field, DescriptorPool::ErrorCollector::DEFAULT_VALUE);
   string* default_value = field->mutable_default_value();
 
   if (!field->has_type()) {
@@ -634,26 +797,35 @@
   return true;
 }
 
-bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option) {
+bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
+                                 const LocationRecorder& part_location) {
   UninterpretedOption::NamePart* name = uninterpreted_option->add_name();
   string identifier;  // We parse identifiers into this string.
   if (LookingAt("(")) {  // This is an extension.
     DO(Consume("("));
-    // An extension name consists of dot-separated identifiers, and may begin
-    // with a dot.
-    if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
-      DO(ConsumeIdentifier(&identifier, "Expected identifier."));
-      name->mutable_name_part()->append(identifier);
+
+    {
+      LocationRecorder location(
+          part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
+      // An extension name consists of dot-separated identifiers, and may begin
+      // with a dot.
+      if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
+      while (LookingAt(".")) {
+        DO(Consume("."));
+        name->mutable_name_part()->append(".");
+        DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+        name->mutable_name_part()->append(identifier);
+      }
     }
-    while (LookingAt(".")) {
-      DO(Consume("."));
-      name->mutable_name_part()->append(".");
-      DO(ConsumeIdentifier(&identifier, "Expected identifier."));
-      name->mutable_name_part()->append(identifier);
-    }
+
     DO(Consume(")"));
     name->set_is_extension(true);
   } else {  // This is a regular field.
+    LocationRecorder location(
+        part_location, UninterpretedOption::NamePart::kNamePartFieldNumber);
     DO(ConsumeIdentifier(&identifier, "Expected identifier."));
     name->mutable_name_part()->append(identifier);
     name->set_is_extension(false);
@@ -661,34 +833,75 @@
   return true;
 }
 
+bool Parser::ParseUninterpretedBlock(string* value) {
+  // Note that enclosing braces are not added to *value.
+  DO(Consume("{"));
+  int brace_depth = 1;
+  while (!AtEnd()) {
+    if (LookingAt("{")) {
+      brace_depth++;
+    } else if (LookingAt("}")) {
+      brace_depth--;
+      if (brace_depth == 0) {
+        input_->Next();
+        return true;
+      }
+    }
+    // TODO(sanjay): Interpret line/column numbers to preserve formatting
+    if (!value->empty()) value->push_back(' ');
+    value->append(input_->current().text);
+    input_->Next();
+  }
+  AddError("Unexpected end of stream while parsing aggregate value.");
+  return false;
+}
+
 // We don't interpret the option here. Instead we store it in an
 // UninterpretedOption, to be interpreted later.
-bool Parser::ParseOptionAssignment(Message* options) {
+bool Parser::ParseOptionAssignment(Message* options,
+                                   const LocationRecorder& options_location) {
   // Create an entry in the uninterpreted_option field.
   const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()->
       FindFieldByName("uninterpreted_option");
   GOOGLE_CHECK(uninterpreted_option_field != NULL)
       << "No field named \"uninterpreted_option\" in the Options proto.";
 
+  const Reflection* reflection = options->GetReflection();
+
+  LocationRecorder location(
+      options_location, uninterpreted_option_field->number(),
+      reflection->FieldSize(*options, uninterpreted_option_field));
+
   UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>(
       options->GetReflection()->AddMessage(options,
                                            uninterpreted_option_field));
 
   // Parse dot-separated name.
-  RecordLocation(uninterpreted_option,
-                 DescriptorPool::ErrorCollector::OPTION_NAME);
+  {
+    LocationRecorder name_location(location,
+                                   UninterpretedOption::kNameFieldNumber);
+    name_location.RecordLegacyLocation(
+        uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME);
 
-  DO(ParseOptionNamePart(uninterpreted_option));
+    {
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location));
+    }
 
-  while (LookingAt(".")) {
-    DO(Consume("."));
-    DO(ParseOptionNamePart(uninterpreted_option));
+    while (LookingAt(".")) {
+      DO(Consume("."));
+      LocationRecorder part_location(name_location,
+                                     uninterpreted_option->name_size());
+      DO(ParseOptionNamePart(uninterpreted_option, part_location));
+    }
   }
 
   DO(Consume("="));
 
-  RecordLocation(uninterpreted_option,
-                 DescriptorPool::ErrorCollector::OPTION_VALUE);
+  LocationRecorder value_location(location);
+  value_location.RecordLegacyLocation(
+      uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE);
 
   // All values are a single token, except for negative numbers, which consist
   // of a single '-' symbol, followed by a positive number.
@@ -704,6 +917,7 @@
       return false;
 
     case io::Tokenizer::TYPE_IDENTIFIER: {
+      value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber);
       if (is_negative) {
         AddError("Invalid '-' symbol before identifier.");
         return false;
@@ -720,15 +934,19 @@
           is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max;
       DO(ConsumeInteger64(max_value, &value, "Expected integer."));
       if (is_negative) {
-        uninterpreted_option->set_negative_int_value(
-            -static_cast<int64>(value));
+        value_location.AddPath(
+            UninterpretedOption::kNegativeIntValueFieldNumber);
+        uninterpreted_option->set_negative_int_value(-static_cast<int64>(value));
       } else {
+        value_location.AddPath(
+            UninterpretedOption::kPositiveIntValueFieldNumber);
         uninterpreted_option->set_positive_int_value(value);
       }
       break;
     }
 
     case io::Tokenizer::TYPE_FLOAT: {
+      value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
       double value;
       DO(ConsumeNumber(&value, "Expected number."));
       uninterpreted_option->set_double_value(is_negative ? -value : value);
@@ -736,6 +954,7 @@
     }
 
     case io::Tokenizer::TYPE_STRING: {
+      value_location.AddPath(UninterpretedOption::kStringValueFieldNumber);
       if (is_negative) {
         AddError("Invalid '-' symbol before string.");
         return false;
@@ -747,31 +966,57 @@
     }
 
     case io::Tokenizer::TYPE_SYMBOL:
-      AddError("Expected option value.");
-      return false;
+      if (LookingAt("{")) {
+        value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber);
+        DO(ParseUninterpretedBlock(
+            uninterpreted_option->mutable_aggregate_value()));
+      } else {
+        AddError("Expected option value.");
+        return false;
+      }
+      break;
   }
 
   return true;
 }
 
-bool Parser::ParseExtensions(DescriptorProto* message) {
+bool Parser::ParseExtensions(DescriptorProto* message,
+                             const LocationRecorder& extensions_location) {
   // Parse the declaration.
   DO(Consume("extensions"));
 
   do {
+    // Note that kExtensionRangeFieldNumber was already pushed by the parent.
+    LocationRecorder location(extensions_location,
+                              message->extension_range_size());
+
     DescriptorProto::ExtensionRange* range = message->add_extension_range();
-    RecordLocation(range, DescriptorPool::ErrorCollector::NUMBER);
+    location.RecordLegacyLocation(
+        range, DescriptorPool::ErrorCollector::NUMBER);
 
     int start, end;
-    DO(ConsumeInteger(&start, "Expected field number range."));
+    io::Tokenizer::Token start_token;
+
+    {
+      LocationRecorder start_location(
+          location, DescriptorProto::ExtensionRange::kStartFieldNumber);
+      start_token = input_->current();
+      DO(ConsumeInteger(&start, "Expected field number range."));
+    }
 
     if (TryConsume("to")) {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::kEndFieldNumber);
       if (TryConsume("max")) {
         end = FieldDescriptor::kMaxNumber;
       } else {
         DO(ConsumeInteger(&end, "Expected integer."));
       }
     } else {
+      LocationRecorder end_location(
+          location, DescriptorProto::ExtensionRange::kEndFieldNumber);
+      end_location.StartAt(start_token);
+      end_location.EndAt(start_token);
       end = start;
     }
 
@@ -788,16 +1033,17 @@
 }
 
 bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
-                         RepeatedPtrField<DescriptorProto>* messages) {
+                         RepeatedPtrField<DescriptorProto>* messages,
+                         const LocationRecorder& parent_location,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& extend_location) {
   DO(Consume("extend"));
 
-  // We expect to see at least one extension field defined in the extend block.
-  // We need to create it now so we can record the extendee's location.
-  FieldDescriptorProto* first_field = extensions->Add();
-
   // Parse the extendee type.
-  RecordLocation(first_field, DescriptorPool::ErrorCollector::EXTENDEE);
-  DO(ParseUserDefinedType(first_field->mutable_extendee()));
+  io::Tokenizer::Token extendee_start = input_->current();
+  string extendee;
+  DO(ParseUserDefinedType(&extendee));
+  io::Tokenizer::Token extendee_end = input_->previous();
 
   // Parse the block.
   DO(Consume("{"));
@@ -810,16 +1056,29 @@
       return false;
     }
 
-    FieldDescriptorProto* field;
-    if (is_first) {
-      field = first_field;
-      is_first = false;
-    } else {
-      field = extensions->Add();
-      field->set_extendee(first_field->extendee());
+    // Note that kExtensionFieldNumber was already pushed by the parent.
+    LocationRecorder location(extend_location, extensions->size());
+
+    FieldDescriptorProto* field = extensions->Add();
+
+    {
+      LocationRecorder extendee_location(
+          location, FieldDescriptorProto::kExtendeeFieldNumber);
+      extendee_location.StartAt(extendee_start);
+      extendee_location.EndAt(extendee_end);
+
+      if (is_first) {
+        extendee_location.RecordLegacyLocation(
+            field, DescriptorPool::ErrorCollector::EXTENDEE);
+        is_first = false;
+      }
     }
 
-    if (!ParseMessageField(field, messages)) {
+    field->set_extendee(extendee);
+
+    if (!ParseMessageField(field, messages, parent_location,
+                           location_field_number_for_nested_type,
+                           location)) {
       // This statement failed to parse.  Skip it, but keep looping to parse
       // other statements.
       SkipStatement();
@@ -832,15 +1091,24 @@
 // -------------------------------------------------------------------
 // Enums
 
-bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type) {
+bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                                 const LocationRecorder& enum_location) {
   DO(Consume("enum"));
-  RecordLocation(enum_type, DescriptorPool::ErrorCollector::NAME);
-  DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
-  DO(ParseEnumBlock(enum_type));
+
+  {
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(
+        enum_type, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name."));
+  }
+
+  DO(ParseEnumBlock(enum_type, enum_location));
   return true;
 }
 
-bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type) {
+bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type,
+                            const LocationRecorder& enum_location) {
   DO(Consume("{"));
 
   while (!TryConsume("}")) {
@@ -849,7 +1117,7 @@
       return false;
     }
 
-    if (!ParseEnumStatement(enum_type)) {
+    if (!ParseEnumStatement(enum_type, enum_location)) {
       // This statement failed to parse.  Skip it, but keep looping to parse
       // other statements.
       SkipStatement();
@@ -859,41 +1127,69 @@
   return true;
 }
 
-bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type) {
+bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type,
+                                const LocationRecorder& enum_location) {
   if (TryConsume(";")) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("option")) {
-    return ParseOption(enum_type->mutable_options());
+    LocationRecorder location(enum_location,
+                              EnumDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(enum_type->mutable_options(), location);
   } else {
-    return ParseEnumConstant(enum_type->add_value());
+    LocationRecorder location(enum_location,
+        EnumDescriptorProto::kValueFieldNumber, enum_type->value_size());
+    return ParseEnumConstant(enum_type->add_value(), location);
   }
 }
 
-bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value) {
-  RecordLocation(enum_value, DescriptorPool::ErrorCollector::NAME);
-  DO(ConsumeIdentifier(enum_value->mutable_name(),
-                       "Expected enum constant name."));
+bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                               const LocationRecorder& enum_value_location) {
+  // Parse name.
+  {
+    LocationRecorder location(enum_value_location,
+                              EnumValueDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(
+        enum_value, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(enum_value->mutable_name(),
+                         "Expected enum constant name."));
+  }
+
   DO(Consume("=", "Missing numeric value for enum constant."));
 
-  bool is_negative = TryConsume("-");
-  int number;
-  DO(ConsumeInteger(&number, "Expected integer."));
-  if (is_negative) number *= -1;
-  enum_value->set_number(number);
+  // Parse value.
+  {
+    LocationRecorder location(
+        enum_value_location, EnumValueDescriptorProto::kNumberFieldNumber);
+    location.RecordLegacyLocation(
+        enum_value, DescriptorPool::ErrorCollector::NUMBER);
 
-  DO(ParseEnumConstantOptions(enum_value));
+    bool is_negative = TryConsume("-");
+    int number;
+    DO(ConsumeInteger(&number, "Expected integer."));
+    if (is_negative) number *= -1;
+    enum_value->set_number(number);
+  }
+
+  DO(ParseEnumConstantOptions(enum_value, enum_value_location));
 
   DO(Consume(";"));
 
   return true;
 }
 
-bool Parser::ParseEnumConstantOptions(EnumValueDescriptorProto* value) {
-  if (!TryConsume("[")) return true;
+bool Parser::ParseEnumConstantOptions(
+    EnumValueDescriptorProto* value,
+    const LocationRecorder& enum_value_location) {
+  if (!LookingAt("[")) return true;
+
+  LocationRecorder location(
+      enum_value_location, EnumValueDescriptorProto::kOptionsFieldNumber);
+
+  DO(Consume("["));
 
   do {
-    DO(ParseOptionAssignment(value->mutable_options()));
+    DO(ParseOptionAssignment(value->mutable_options(), location));
   } while (TryConsume(","));
 
   DO(Consume("]"));
@@ -903,15 +1199,24 @@
 // -------------------------------------------------------------------
 // Services
 
-bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service) {
+bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service,
+                                    const LocationRecorder& service_location) {
   DO(Consume("service"));
-  RecordLocation(service, DescriptorPool::ErrorCollector::NAME);
-  DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
-  DO(ParseServiceBlock(service));
+
+  {
+    LocationRecorder location(service_location,
+                              ServiceDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(
+        service, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(service->mutable_name(), "Expected service name."));
+  }
+
+  DO(ParseServiceBlock(service, service_location));
   return true;
 }
 
-bool Parser::ParseServiceBlock(ServiceDescriptorProto* service) {
+bool Parser::ParseServiceBlock(ServiceDescriptorProto* service,
+                               const LocationRecorder& service_location) {
   DO(Consume("{"));
 
   while (!TryConsume("}")) {
@@ -920,7 +1225,7 @@
       return false;
     }
 
-    if (!ParseServiceStatement(service)) {
+    if (!ParseServiceStatement(service, service_location)) {
       // This statement failed to parse.  Skip it, but keep looping to parse
       // other statements.
       SkipStatement();
@@ -930,33 +1235,55 @@
   return true;
 }
 
-bool Parser::ParseServiceStatement(ServiceDescriptorProto* service) {
+bool Parser::ParseServiceStatement(ServiceDescriptorProto* service,
+                                   const LocationRecorder& service_location) {
   if (TryConsume(";")) {
     // empty statement; ignore
     return true;
   } else if (LookingAt("option")) {
-    return ParseOption(service->mutable_options());
+    LocationRecorder location(
+        service_location, ServiceDescriptorProto::kOptionsFieldNumber);
+    return ParseOption(service->mutable_options(), location);
   } else {
-    return ParseServiceMethod(service->add_method());
+    LocationRecorder location(service_location,
+        ServiceDescriptorProto::kMethodFieldNumber, service->method_size());
+    return ParseServiceMethod(service->add_method(), location);
   }
 }
 
-bool Parser::ParseServiceMethod(MethodDescriptorProto* method) {
+bool Parser::ParseServiceMethod(MethodDescriptorProto* method,
+                                const LocationRecorder& method_location) {
   DO(Consume("rpc"));
-  RecordLocation(method, DescriptorPool::ErrorCollector::NAME);
-  DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
+
+  {
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kNameFieldNumber);
+    location.RecordLegacyLocation(
+        method, DescriptorPool::ErrorCollector::NAME);
+    DO(ConsumeIdentifier(method->mutable_name(), "Expected method name."));
+  }
 
   // Parse input type.
   DO(Consume("("));
-  RecordLocation(method, DescriptorPool::ErrorCollector::INPUT_TYPE);
-  DO(ParseUserDefinedType(method->mutable_input_type()));
+  {
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kInputTypeFieldNumber);
+    location.RecordLegacyLocation(
+        method, DescriptorPool::ErrorCollector::INPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_input_type()));
+  }
   DO(Consume(")"));
 
   // Parse output type.
   DO(Consume("returns"));
   DO(Consume("("));
-  RecordLocation(method, DescriptorPool::ErrorCollector::OUTPUT_TYPE);
-  DO(ParseUserDefinedType(method->mutable_output_type()));
+  {
+    LocationRecorder location(method_location,
+                              MethodDescriptorProto::kOutputTypeFieldNumber);
+    location.RecordLegacyLocation(
+        method, DescriptorPool::ErrorCollector::OUTPUT_TYPE);
+    DO(ParseUserDefinedType(method->mutable_output_type()));
+  }
   DO(Consume(")"));
 
   if (TryConsume("{")) {
@@ -970,7 +1297,9 @@
       if (TryConsume(";")) {
         // empty statement; ignore
       } else {
-        if (!ParseOption(method->mutable_options())) {
+        LocationRecorder location(method_location,
+                                  MethodDescriptorProto::kOptionsFieldNumber);
+        if (!ParseOption(method->mutable_options(), location)) {
           // This statement failed to parse.  Skip it, but keep looping to
           // parse other statements.
           SkipStatement();
@@ -1054,7 +1383,8 @@
 
 // ===================================================================
 
-bool Parser::ParsePackage(FileDescriptorProto* file) {
+bool Parser::ParsePackage(FileDescriptorProto* file,
+                          const LocationRecorder& root_location) {
   if (file->has_package()) {
     AddError("Multiple package definitions.");
     // Don't append the new package to the old one.  Just replace it.  Not
@@ -1064,31 +1394,43 @@
 
   DO(Consume("package"));
 
-  RecordLocation(file, DescriptorPool::ErrorCollector::NAME);
+  {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kPackageFieldNumber);
+    location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME);
 
-  while (true) {
-    string identifier;
-    DO(ConsumeIdentifier(&identifier, "Expected identifier."));
-    file->mutable_package()->append(identifier);
-    if (!TryConsume(".")) break;
-    file->mutable_package()->append(".");
+    while (true) {
+      string identifier;
+      DO(ConsumeIdentifier(&identifier, "Expected identifier."));
+      file->mutable_package()->append(identifier);
+      if (!TryConsume(".")) break;
+      file->mutable_package()->append(".");
+    }
   }
 
   DO(Consume(";"));
   return true;
 }
 
-bool Parser::ParseImport(string* import_filename) {
+bool Parser::ParseImport(string* import_filename,
+                         const LocationRecorder& root_location,
+                         int index) {
   DO(Consume("import"));
-  DO(ConsumeString(import_filename,
-    "Expected a string naming the file to import."));
+  {
+    LocationRecorder location(root_location,
+                              FileDescriptorProto::kDependencyFieldNumber,
+                              index);
+    DO(ConsumeString(import_filename,
+      "Expected a string naming the file to import."));
+  }
   DO(Consume(";"));
   return true;
 }
 
-bool Parser::ParseOption(Message* options) {
+bool Parser::ParseOption(Message* options,
+                         const LocationRecorder& options_location) {
   DO(Consume("option"));
-  DO(ParseOptionAssignment(options));
+  DO(ParseOptionAssignment(options, options_location));
   DO(Consume(";"));
   return true;
 }
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 72c96d0..4cc90a2 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -74,6 +74,9 @@
 
   // Optional fetaures:
 
+  // DEPRECATED:  New code should use the SourceCodeInfo embedded in the
+  //   FileDescriptorProto.
+  //
   // Requests that locations of certain definitions be recorded to the given
   // SourceLocationTable while parsing.  This can be used to look up exact line
   // and column numbers for errors reported by DescriptorPool during validation.
@@ -82,7 +85,7 @@
     source_location_table_ = location_table;
   }
 
-  // Requsets that errors be recorded to the given ErrorCollector while
+  // Requests that errors be recorded to the given ErrorCollector while
   // parsing.  Set to NULL (the default) to discard error messages.
   void RecordErrorsTo(io::ErrorCollector* error_collector) {
     error_collector_ = error_collector;
@@ -180,16 +183,56 @@
   // of the current token.
   void AddError(const string& error);
 
-  // Record the given line and column and associate it with this descriptor
-  // in the SourceLocationTable.
-  void RecordLocation(const Message* descriptor,
-                      DescriptorPool::ErrorCollector::ErrorLocation location,
-                      int line, int column);
+  // Records a location in the SourceCodeInfo.location table (see
+  // descriptor.proto).  We use RAII to ensure that the start and end locations
+  // are recorded -- the constructor records the start location and the
+  // destructor records the end location.  Since the parser is
+  // recursive-descent, this works out beautifully.
+  class LIBPROTOBUF_EXPORT LocationRecorder {
+   public:
+    // Construct the file's "root" location.
+    LocationRecorder(Parser* parser);
 
-  // Record the current line and column and associate it with this descriptor
-  // in the SourceLocationTable.
-  void RecordLocation(const Message* descriptor,
-                      DescriptorPool::ErrorCollector::ErrorLocation location);
+    // Construct a location that represents a declaration nested within the
+    // given parent.  E.g. a field's location is nested within the location
+    // for a message type.  The parent's path will be copied, so you should
+    // call AddPath() only to add the path components leading from the parent
+    // to the child (as opposed to leading from the root to the child).
+    LocationRecorder(const LocationRecorder& parent);
+
+    // Convenience constructors that call AddPath() one or two times.
+    LocationRecorder(const LocationRecorder& parent, int path1);
+    LocationRecorder(const LocationRecorder& parent, int path1, int path2);
+
+    ~LocationRecorder();
+
+    // Add a path component.  See SourceCodeInfo.Location.path in
+    // descriptor.proto.
+    void AddPath(int path_component);
+
+    // By default the location is considered to start at the current token at
+    // the time the LocationRecorder is created.  StartAt() sets the start
+    // location to the given token instead.
+    void StartAt(const io::Tokenizer::Token& token);
+
+    // By default the location is considered to end at the previous token at
+    // the time the LocationRecorder is destroyed.  EndAt() sets the end
+    // location to the given token instead.
+    void EndAt(const io::Tokenizer::Token& token);
+
+    // Records the start point of this location to the SourceLocationTable that
+    // was passed to RecordSourceLocationsTo(), if any.  SourceLocationTable
+    // is an older way of keeping track of source locations which is still
+    // used in some places.
+    void RecordLegacyLocation(const Message* descriptor,
+        DescriptorPool::ErrorCollector::ErrorLocation location);
+
+   private:
+    Parser* parser_;
+    SourceCodeInfo::Location* location_;
+
+    void Init(const LocationRecorder& parent);
+  };
 
   // =================================================================
   // Parsers for various language constructs
@@ -210,50 +253,81 @@
   // makes logic much simpler for the caller.
 
   // Parse a top-level message, enum, service, etc.
-  bool ParseTopLevelStatement(FileDescriptorProto* file);
+  bool ParseTopLevelStatement(FileDescriptorProto* file,
+                              const LocationRecorder& root_location);
 
   // Parse various language high-level language construrcts.
-  bool ParseMessageDefinition(DescriptorProto* message);
-  bool ParseEnumDefinition(EnumDescriptorProto* enum_type);
-  bool ParseServiceDefinition(ServiceDescriptorProto* service);
-  bool ParsePackage(FileDescriptorProto* file);
-  bool ParseImport(string* import_filename);
-  bool ParseOption(Message* options);
+  bool ParseMessageDefinition(DescriptorProto* message,
+                              const LocationRecorder& message_location);
+  bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
+                           const LocationRecorder& enum_location);
+  bool ParseServiceDefinition(ServiceDescriptorProto* service,
+                              const LocationRecorder& service_location);
+  bool ParsePackage(FileDescriptorProto* file,
+                    const LocationRecorder& root_location);
+  bool ParseImport(string* import_filename,
+                   const LocationRecorder& root_location,
+                   int index);
+  bool ParseOption(Message* options,
+                   const LocationRecorder& options_location);
 
   // These methods parse the contents of a message, enum, or service type and
   // add them to the given object.  They consume the entire block including
   // the beginning and ending brace.
-  bool ParseMessageBlock(DescriptorProto* message);
-  bool ParseEnumBlock(EnumDescriptorProto* enum_type);
-  bool ParseServiceBlock(ServiceDescriptorProto* service);
+  bool ParseMessageBlock(DescriptorProto* message,
+                         const LocationRecorder& message_location);
+  bool ParseEnumBlock(EnumDescriptorProto* enum_type,
+                      const LocationRecorder& enum_location);
+  bool ParseServiceBlock(ServiceDescriptorProto* service,
+                         const LocationRecorder& service_location);
 
   // Parse one statement within a message, enum, or service block, inclunding
   // final semicolon.
-  bool ParseMessageStatement(DescriptorProto* message);
-  bool ParseEnumStatement(EnumDescriptorProto* message);
-  bool ParseServiceStatement(ServiceDescriptorProto* message);
+  bool ParseMessageStatement(DescriptorProto* message,
+                             const LocationRecorder& message_location);
+  bool ParseEnumStatement(EnumDescriptorProto* message,
+                          const LocationRecorder& enum_location);
+  bool ParseServiceStatement(ServiceDescriptorProto* message,
+                             const LocationRecorder& service_location);
 
   // Parse a field of a message.  If the field is a group, its type will be
   // added to "messages".
+  //
+  // parent_location and location_field_number_for_nested_type are needed when
+  // parsing groups -- we need to generate a nested message type within the
+  // parent and record its location accordingly.  Since the parent could be
+  // either a FileDescriptorProto or a DescriptorProto, we must pass in the
+  // correct field number to use.
   bool ParseMessageField(FieldDescriptorProto* field,
-                         RepeatedPtrField<DescriptorProto>* messages);
+                         RepeatedPtrField<DescriptorProto>* messages,
+                         const LocationRecorder& parent_location,
+                         int location_field_number_for_nested_type,
+                         const LocationRecorder& field_location);
 
   // Parse an "extensions" declaration.
-  bool ParseExtensions(DescriptorProto* message);
+  bool ParseExtensions(DescriptorProto* message,
+                       const LocationRecorder& extensions_location);
 
-  // Parse an "extend" declaration.
+  // Parse an "extend" declaration.  (See also comments for
+  // ParseMessageField().)
   bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
-                   RepeatedPtrField<DescriptorProto>* messages);
+                   RepeatedPtrField<DescriptorProto>* messages,
+                   const LocationRecorder& parent_location,
+                   int location_field_number_for_nested_type,
+                   const LocationRecorder& extend_location);
 
   // Parse a single enum value within an enum block.
-  bool ParseEnumConstant(EnumValueDescriptorProto* enum_value);
+  bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
+                         const LocationRecorder& enum_value_location);
 
   // Parse enum constant options, i.e. the list in square brackets at the end
   // of the enum constant value definition.
-  bool ParseEnumConstantOptions(EnumValueDescriptorProto* value);
+  bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
+                                const LocationRecorder& enum_value_location);
 
   // Parse a single method within a service definition.
-  bool ParseServiceMethod(MethodDescriptorProto* method);
+  bool ParseServiceMethod(MethodDescriptorProto* method,
+                          const LocationRecorder& method_location);
 
   // Parse "required", "optional", or "repeated" and fill in "label"
   // with the value.
@@ -269,28 +343,45 @@
 
   // Parses field options, i.e. the stuff in square brackets at the end
   // of a field definition.  Also parses default value.
-  bool ParseFieldOptions(FieldDescriptorProto* field);
+  bool ParseFieldOptions(FieldDescriptorProto* field,
+                         const LocationRecorder& field_location);
 
   // Parse the "default" option.  This needs special handling because its
   // type is the field's type.
-  bool ParseDefaultAssignment(FieldDescriptorProto* field);
+  bool ParseDefaultAssignment(FieldDescriptorProto* field,
+                              const LocationRecorder& field_location);
 
   // Parse a single option name/value pair, e.g. "ctype = CORD".  The name
   // identifies a field of the given Message, and the value of that field
   // is set to the parsed value.
-  bool ParseOptionAssignment(Message* options);
+  bool ParseOptionAssignment(Message* options,
+                             const LocationRecorder& options_location);
 
   // Parses a single part of a multipart option name. A multipart name consists
   // of names separated by dots. Each name is either an identifier or a series
   // of identifiers separated by dots and enclosed in parentheses. E.g.,
   // "foo.(bar.baz).qux".
-  bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option);
+  bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
+                           const LocationRecorder& part_location);
+
+  // Parses a string surrounded by balanced braces.  Strips off the outer
+  // braces and stores the enclosed string in *value.
+  // E.g.,
+  //     { foo }                     *value gets 'foo'
+  //     { foo { bar: box } }        *value gets 'foo { bar: box }'
+  //     {}                          *value gets ''
+  //
+  // REQUIRES: LookingAt("{")
+  // When finished successfully, we are looking at the first token past
+  // the ending brace.
+  bool ParseUninterpretedBlock(string* value);
 
   // =================================================================
 
   io::Tokenizer* input_;
   io::ErrorCollector* error_collector_;
-  SourceLocationTable* source_location_table_;
+  SourceCodeInfo* source_code_info_;
+  SourceLocationTable* source_location_table_;  // legacy
   bool had_errors_;
   bool require_syntax_identifier_;
   bool stop_after_syntax_identifier_;
@@ -302,6 +393,11 @@
 // A table mapping (descriptor, ErrorLocation) pairs -- as reported by
 // DescriptorPool when validating descriptors -- to line and column numbers
 // within the original source code.
+//
+// This is semi-obsolete:  FileDescriptorProto.source_code_info now contains
+// far more complete information about source locations.  However, as of this
+// writing you still need to use SourceLocationTable when integrating with
+// DescriptorPool.
 class LIBPROTOBUF_EXPORT SourceLocationTable {
  public:
   SourceLocationTable();
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index e2262b8..156c0dc 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -34,6 +34,7 @@
 
 #include <vector>
 #include <algorithm>
+#include <map>
 
 #include <google/protobuf/compiler/parser.h>
 
@@ -45,6 +46,7 @@
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map-util.h>
 
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
@@ -118,6 +120,9 @@
     EXPECT_EQ(io::Tokenizer::TYPE_END, input_->current().type);
     ASSERT_EQ("", error_collector_.text_);
 
+    // We don't cover SourceCodeInfo in these tests.
+    actual.clear_source_code_info();
+
     // Parse the ASCII representation in order to canonicalize it.  We could
     // just compare directly to actual.DebugString(), but that would require
     // that the caller precisely match the formatting that DebugString()
@@ -930,6 +935,12 @@
     "3:25: Expected \";\".\n");
 }
 
+TEST_F(ParseErrorTest, EofInAggregateValue) {
+  ExpectHasErrors(
+      "option (fileopt) = { i:100\n",
+      "1:0: Unexpected end of stream while parsing aggregate value.\n");
+}
+
 // -------------------------------------------------------------------
 // Enum errors
 
@@ -1248,6 +1259,861 @@
 }
 
 // ===================================================================
+// SourceCodeInfo tests.
+
+// Follows a path -- as defined by SourceCodeInfo.Location.path -- from a
+// message to a particular sub-field.
+// * If the target is itself a message, sets *output_message to point at it,
+//   *output_field to NULL, and *output_index to -1.
+// * Otherwise, if the target is an element of a repeated field, sets
+//   *output_message to the containing message, *output_field to the descriptor
+//   of the field, and *output_index to the index of the element.
+// * Otherwise, the target is a field (possibly a repeated field, but not any
+//   one element).  Sets *output_message to the containing message,
+//   *output_field to the descriptor of the field, and *output_index to -1.
+// Returns true if the path was valid, false otherwise.  A gTest failure is
+// recorded before returning false.
+bool FollowPath(const Message& root,
+                const int* path_begin, const int* path_end,
+                const Message** output_message,
+                const FieldDescriptor** output_field,
+                int* output_index) {
+  if (path_begin == path_end) {
+    // Path refers to this whole message.
+    *output_message = &root;
+    *output_field = NULL;
+    *output_index = -1;
+    return true;
+  }
+
+  const Descriptor* descriptor = root.GetDescriptor();
+  const Reflection* reflection = root.GetReflection();
+
+  const FieldDescriptor* field = descriptor->FindFieldByNumber(*path_begin);
+
+  if (field == NULL) {
+    ADD_FAILURE() << descriptor->name() << " has no field number: "
+                  << *path_begin;
+    return false;
+  }
+
+  ++path_begin;
+
+  if (field->is_repeated()) {
+    if (path_begin == path_end) {
+      // Path refers to the whole repeated field.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = -1;
+      return true;
+    }
+
+    int index = *path_begin++;
+    int size = reflection->FieldSize(root, field);
+
+    if (index >= size) {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " has size " << size << ", but path contained index: "
+                    << index;
+      return false;
+    }
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      // Descend into child message.
+      const Message& child = reflection->GetRepeatedMessage(root, field, index);
+      return FollowPath(child, path_begin, path_end,
+                        output_message, output_field, output_index);
+    } else if (path_begin == path_end) {
+      // Path refers to this element.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = index;
+      return true;
+    } else {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " is not a message; cannot descend into it.";
+      return false;
+    }
+  } else {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      const Message& child = reflection->GetMessage(root, field);
+      return FollowPath(child, path_begin, path_end,
+                        output_message, output_field, output_index);
+    } else if (path_begin == path_end) {
+      // Path refers to this field.
+      *output_message = &root;
+      *output_field = field;
+      *output_index = -1;
+      return true;
+    } else {
+      ADD_FAILURE() << descriptor->name() << "." << field->name()
+                    << " is not a message; cannot descend into it.";
+      return false;
+    }
+  }
+}
+
+// Split some text on line breaks.  The line breaks are retained in the output,
+// so each line (except the last) ends with a '\n', and the lines can be
+// concatenated to produce the original text.
+//
+// I couldn't find the proper string utility function for this.  Our
+// split-on-delimiter functions don't include the delimiter in the output.
+void SplitLines(const string& text, vector<string>* lines) {
+  string::size_type pos = 0;
+
+  while (pos != string::npos) {
+    string::size_type last_pos = pos;
+    pos = text.find_first_of('\n', pos);
+    if (pos != string::npos) ++pos;
+    lines->push_back(text.substr(last_pos, pos - last_pos));
+  }
+}
+
+// Look for the given tags in the given text and construct a span (as defined
+// by SourceCodeInfo.Location.span) from them.  E.g. for text like:
+//   /*a*/message /*b*/Foo/*c*/ {}/*d*/
+// There are four tags:  "a", "b", "c", and "d".  The constructed span starts
+// immediately after the start tag's trailing '/' and ends immediately before
+// the end tags leading '/'.
+void MakeExpectedSpan(const vector<string>& lines,
+                      const string& start_tag, const string& end_tag,
+                      RepeatedField<int>* output) {
+  string start_comment = "/*" + start_tag + "*/";
+  string end_comment = "/*" + end_tag + "*/";
+
+  int start_line = -1;
+  int start_column = -1;
+  for (int i = 0; i < lines.size(); i++) {
+    string::size_type pos = lines[i].find(start_comment);
+    if (pos != string::npos) {
+      start_line = i;
+      start_column = pos + start_comment.size();
+      break;
+    }
+  }
+  ASSERT_NE(start_line, -1)
+      << "Tag \"" << start_comment << "\" not found in text.";
+
+  int end_line = -1;
+  int end_column = -1;
+  for (int i = start_line; i < lines.size(); i++) {
+    string::size_type pos = lines[i].find(end_comment);
+    if (pos != string::npos) {
+      end_line = i;
+      end_column = pos;
+      break;
+    }
+  }
+  ASSERT_NE(end_line, -1)
+      << "Tag \"" << end_comment << "\" not found in text.";
+
+  output->Add(start_line);
+  output->Add(start_column);
+  if (end_line != start_line) output->Add(end_line);
+  output->Add(end_column);
+}
+
+// Check if two spans are equal.
+bool CompareSpans(const RepeatedField<int>& span1,
+                  const RepeatedField<int>& span2) {
+  if (span1.size() != span2.size()) return false;
+  for (int i = 0; i < span1.size(); i++) {
+    if (span1.Get(i) != span2.Get(i)) return false;
+  }
+  return true;
+}
+
+// Test fixture for source info tests, which check that source locations are
+// recorded correctly in FileDescriptorProto.source_code_info.location.
+class SourceInfoTest : public ParserTest {
+ protected:
+  // The parsed file (initialized by Parse()).
+  FileDescriptorProto file_;
+
+  // Parse the given text as a .proto file and populate the spans_ map with
+  // all the source location spans in its SourceCodeInfo table.
+  bool Parse(const char* text) {
+    SetupParser(text);
+    SplitLines(text, &lines_);
+    if (!parser_->Parse(input_.get(), &file_)) {
+      return false;
+    }
+
+    const SourceCodeInfo& source_info = file_.source_code_info();
+    for (int i = 0; i < source_info.location_size(); i++) {
+      const SourceCodeInfo::Location& location = source_info.location(i);
+      const Message* descriptor_proto = NULL;
+      const FieldDescriptor* field = NULL;
+      int index = 0;
+      if (!FollowPath(file_, location.path().begin(), location.path().end(),
+                      &descriptor_proto, &field, &index)) {
+        return false;
+      }
+
+      spans_.insert(make_pair(SpanKey(*descriptor_proto, field, index),
+                              &location));
+    }
+
+    return true;
+  }
+
+  virtual void TearDown() {
+    EXPECT_TRUE(spans_.empty())
+        << "Forgot to call HasSpan() for:\n"
+        << spans_.begin()->second->DebugString();
+  }
+
+  // -----------------------------------------------------------------
+  // HasSpan() checks that the span of source code delimited by the given
+  // tags (comments) correspond via the SourceCodeInfo table to the given
+  // part of the FileDescriptorProto.  (If unclear, look at the actual tests;
+  // it should quickly become obvious.)
+
+  bool HasSpan(const char* start_tag, const char* end_tag,
+               const Message& descriptor_proto) {
+    return HasSpan(start_tag, end_tag, descriptor_proto, NULL, -1);
+  }
+
+  bool HasSpan(const char* start_tag, const char* end_tag,
+               const Message& descriptor_proto, const string& field_name) {
+    return HasSpan(start_tag, end_tag, descriptor_proto, field_name, -1);
+  }
+
+  bool HasSpan(const char* start_tag, const char* end_tag,
+               const Message& descriptor_proto, const string& field_name,
+               int index) {
+    const FieldDescriptor* field =
+        descriptor_proto.GetDescriptor()->FindFieldByName(field_name);
+    if (field == NULL) {
+      ADD_FAILURE() << descriptor_proto.GetDescriptor()->name()
+                    << " has no such field: " << field_name;
+      return false;
+    }
+
+    return HasSpan(start_tag, end_tag, descriptor_proto, field, index);
+  }
+
+  bool HasSpan(const Message& descriptor_proto) {
+    return HasSpan(NULL, NULL, descriptor_proto, NULL, -1);
+  }
+
+  bool HasSpan(const Message& descriptor_proto, const string& field_name) {
+    return HasSpan(NULL, NULL, descriptor_proto, field_name, -1);
+  }
+
+  bool HasSpan(const Message& descriptor_proto, const string& field_name,
+               int index) {
+    return HasSpan(NULL, NULL, descriptor_proto, field_name, index);
+  }
+
+  bool HasSpan(const char* start_tag, const char* end_tag,
+               const Message& descriptor_proto, const FieldDescriptor* field,
+               int index) {
+    pair<SpanMap::iterator, SpanMap::iterator> range =
+        spans_.equal_range(SpanKey(descriptor_proto, field, index));
+
+    if (start_tag == NULL) {
+      if (range.first == range.second) {
+        return false;
+      } else {
+        spans_.erase(range.first);
+        return true;
+      }
+    } else {
+      RepeatedField<int> expected_span;
+      MakeExpectedSpan(lines_, start_tag, end_tag, &expected_span);
+
+      for (SpanMap::iterator iter = range.first; iter != range.second; ++iter) {
+        if (CompareSpans(expected_span, iter->second->span())) {
+          spans_.erase(iter);
+          return true;
+        }
+      }
+
+      return false;
+    }
+  }
+
+ private:
+  struct SpanKey {
+    const Message* descriptor_proto;
+    const FieldDescriptor* field;
+    int index;
+
+    inline SpanKey() {}
+    inline SpanKey(const Message& descriptor_proto,
+                   const FieldDescriptor* field,
+                   int index)
+        : descriptor_proto(&descriptor_proto), field(field), index(index) {}
+
+    inline bool operator<(const SpanKey& other) const {
+      if (descriptor_proto < other.descriptor_proto) return true;
+      if (descriptor_proto > other.descriptor_proto) return false;
+      if (field < other.field) return true;
+      if (field > other.field) return false;
+      return index < other.index;
+    }
+  };
+
+  typedef multimap<SpanKey, const SourceCodeInfo::Location*> SpanMap;
+  SpanMap spans_;
+  vector<string> lines_;
+};
+
+TEST_F(SourceInfoTest, BasicFileDecls) {
+  EXPECT_TRUE(Parse(
+      "/*a*/syntax = \"proto2\";\n"
+      "package /*b*/foo.bar/*c*/;\n"
+      "import /*d*/\"baz.proto\"/*e*/;\n"
+      "import /*f*/\"qux.proto\"/*g*/;/*h*/\n"
+      "// comment ignored\n"));
+
+  EXPECT_TRUE(HasSpan("a", "h", file_));
+  EXPECT_TRUE(HasSpan("b", "c", file_, "package"));
+  EXPECT_TRUE(HasSpan("d", "e", file_, "dependency", 0));
+  EXPECT_TRUE(HasSpan("f", "g", file_, "dependency", 1));
+}
+
+TEST_F(SourceInfoTest, Messages) {
+  EXPECT_TRUE(Parse(
+      "/*a*/message /*b*/Foo/*c*/ {}/*d*/\n"
+      "/*e*/message /*f*/Bar/*g*/ {}/*h*/\n"));
+
+  EXPECT_TRUE(HasSpan("a", "d", file_.message_type(0)));
+  EXPECT_TRUE(HasSpan("b", "c", file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan("e", "h", file_.message_type(1)));
+  EXPECT_TRUE(HasSpan("f", "g", file_.message_type(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, Fields) {
+  EXPECT_TRUE(Parse(
+      "message Foo {\n"
+      "  /*a*/optional/*b*/ /*c*/int32/*d*/ /*e*/bar/*f*/ = /*g*/1/*h*/;/*i*/\n"
+      "  /*j*/repeated/*k*/ /*l*/X.Y/*m*/ /*n*/baz/*o*/ = /*p*/2/*q*/;/*r*/\n"
+      "}\n"));
+
+  const FieldDescriptorProto& field1 = file_.message_type(0).field(0);
+  const FieldDescriptorProto& field2 = file_.message_type(0).field(1);
+
+  EXPECT_TRUE(HasSpan("a", "i", field1));
+  EXPECT_TRUE(HasSpan("a", "b", field1, "label"));
+  EXPECT_TRUE(HasSpan("c", "d", field1, "type"));
+  EXPECT_TRUE(HasSpan("e", "f", field1, "name"));
+  EXPECT_TRUE(HasSpan("g", "h", field1, "number"));
+
+  EXPECT_TRUE(HasSpan("j", "r", field2));
+  EXPECT_TRUE(HasSpan("j", "k", field2, "label"));
+  EXPECT_TRUE(HasSpan("l", "m", field2, "type_name"));
+  EXPECT_TRUE(HasSpan("n", "o", field2, "name"));
+  EXPECT_TRUE(HasSpan("p", "q", field2, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Extensions) {
+  EXPECT_TRUE(Parse(
+      "/*a*/extend /*b*/Foo/*c*/ {\n"
+      "  /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
+      "  /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
+      "}/*j*/\n"
+      "/*k*/extend /*l*/Bar/*m*/ {\n"
+      "  /*n*/optional int32 qux = 1;/*o*/\n"
+      "}/*p*/\n"));
+
+  const FieldDescriptorProto& field1 = file_.extension(0);
+  const FieldDescriptorProto& field2 = file_.extension(1);
+  const FieldDescriptorProto& field3 = file_.extension(2);
+
+  EXPECT_TRUE(HasSpan("a", "j", file_, "extension"));
+  EXPECT_TRUE(HasSpan("k", "p", file_, "extension"));
+
+  EXPECT_TRUE(HasSpan("d", "f", field1));
+  EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
+  EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+
+  EXPECT_TRUE(HasSpan("g", "i", field2));
+  EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
+  EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+
+  EXPECT_TRUE(HasSpan("n", "o", field3));
+  EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(field1, "type"));
+  EXPECT_TRUE(HasSpan(field1, "name"));
+  EXPECT_TRUE(HasSpan(field1, "number"));
+  EXPECT_TRUE(HasSpan(field2, "type_name"));
+  EXPECT_TRUE(HasSpan(field2, "name"));
+  EXPECT_TRUE(HasSpan(field2, "number"));
+  EXPECT_TRUE(HasSpan(field3, "label"));
+  EXPECT_TRUE(HasSpan(field3, "type"));
+  EXPECT_TRUE(HasSpan(field3, "name"));
+  EXPECT_TRUE(HasSpan(field3, "number"));
+}
+
+TEST_F(SourceInfoTest, NestedExtensions) {
+  EXPECT_TRUE(Parse(
+      "message Message {\n"
+      "  /*a*/extend /*b*/Foo/*c*/ {\n"
+      "    /*d*/optional/*e*/ int32 bar = 1;/*f*/\n"
+      "    /*g*/repeated/*h*/ X.Y baz = 2;/*i*/\n"
+      "  }/*j*/\n"
+      "  /*k*/extend /*l*/Bar/*m*/ {\n"
+      "    /*n*/optional int32 qux = 1;/*o*/\n"
+      "  }/*p*/\n"
+      "}\n"));
+
+  const FieldDescriptorProto& field1 = file_.message_type(0).extension(0);
+  const FieldDescriptorProto& field2 = file_.message_type(0).extension(1);
+  const FieldDescriptorProto& field3 = file_.message_type(0).extension(2);
+
+  EXPECT_TRUE(HasSpan("a", "j", file_.message_type(0), "extension"));
+  EXPECT_TRUE(HasSpan("k", "p", file_.message_type(0), "extension"));
+
+  EXPECT_TRUE(HasSpan("d", "f", field1));
+  EXPECT_TRUE(HasSpan("d", "e", field1, "label"));
+  EXPECT_TRUE(HasSpan("b", "c", field1, "extendee"));
+
+  EXPECT_TRUE(HasSpan("g", "i", field2));
+  EXPECT_TRUE(HasSpan("g", "h", field2, "label"));
+  EXPECT_TRUE(HasSpan("b", "c", field2, "extendee"));
+
+  EXPECT_TRUE(HasSpan("n", "o", field3));
+  EXPECT_TRUE(HasSpan("l", "m", field3, "extendee"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(field1, "type"));
+  EXPECT_TRUE(HasSpan(field1, "name"));
+  EXPECT_TRUE(HasSpan(field1, "number"));
+  EXPECT_TRUE(HasSpan(field2, "type_name"));
+  EXPECT_TRUE(HasSpan(field2, "name"));
+  EXPECT_TRUE(HasSpan(field2, "number"));
+  EXPECT_TRUE(HasSpan(field3, "label"));
+  EXPECT_TRUE(HasSpan(field3, "type"));
+  EXPECT_TRUE(HasSpan(field3, "name"));
+  EXPECT_TRUE(HasSpan(field3, "number"));
+}
+
+TEST_F(SourceInfoTest, ExtensionRanges) {
+  EXPECT_TRUE(Parse(
+      "message Message {\n"
+      "  /*a*/extensions /*b*/1/*c*/ to /*d*/4/*e*/, /*f*/6/*g*/;/*h*/\n"
+      "  /*i*/extensions /*j*/8/*k*/ to /*l*/max/*m*/;/*n*/\n"
+      "}\n"));
+
+  const DescriptorProto::ExtensionRange& range1 =
+      file_.message_type(0).extension_range(0);
+  const DescriptorProto::ExtensionRange& range2 =
+      file_.message_type(0).extension_range(1);
+  const DescriptorProto::ExtensionRange& range3 =
+      file_.message_type(0).extension_range(2);
+
+  EXPECT_TRUE(HasSpan("a", "h", file_.message_type(0), "extension_range"));
+  EXPECT_TRUE(HasSpan("i", "n", file_.message_type(0), "extension_range"));
+
+  EXPECT_TRUE(HasSpan("b", "e", range1));
+  EXPECT_TRUE(HasSpan("b", "c", range1, "start"));
+  EXPECT_TRUE(HasSpan("d", "e", range1, "end"));
+
+  EXPECT_TRUE(HasSpan("f", "g", range2));
+  EXPECT_TRUE(HasSpan("f", "g", range2, "start"));
+  EXPECT_TRUE(HasSpan("f", "g", range2, "end"));
+
+  EXPECT_TRUE(HasSpan("j", "m", range3));
+  EXPECT_TRUE(HasSpan("j", "k", range3, "start"));
+  EXPECT_TRUE(HasSpan("l", "m", range3, "end"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, NestedMessages) {
+  EXPECT_TRUE(Parse(
+      "message Foo {\n"
+      "  /*a*/message /*b*/Bar/*c*/ {\n"
+      "    /*d*/message /*e*/Baz/*f*/ {}/*g*/\n"
+      "  }/*h*/\n"
+      "  /*i*/message /*j*/Qux/*k*/ {}/*l*/\n"
+      "}\n"));
+
+  const DescriptorProto& bar = file_.message_type(0).nested_type(0);
+  const DescriptorProto& baz = bar.nested_type(0);
+  const DescriptorProto& qux = file_.message_type(0).nested_type(1);
+
+  EXPECT_TRUE(HasSpan("a", "h", bar));
+  EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
+  EXPECT_TRUE(HasSpan("d", "g", baz));
+  EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
+  EXPECT_TRUE(HasSpan("i", "l", qux));
+  EXPECT_TRUE(HasSpan("j", "k", qux, "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Groups) {
+  EXPECT_TRUE(Parse(
+      "message Foo {\n"
+      "  message Bar {}\n"
+      "  /*a*/optional/*b*/ /*c*/group/*d*/ /*e*/Baz/*f*/ = /*g*/1/*h*/ {\n"
+      "    /*i*/message Qux {}/*j*/\n"
+      "  }/*k*/\n"
+      "}\n"));
+
+  const DescriptorProto& bar = file_.message_type(0).nested_type(0);
+  const DescriptorProto& baz = file_.message_type(0).nested_type(1);
+  const DescriptorProto& qux = baz.nested_type(0);
+  const FieldDescriptorProto& field = file_.message_type(0).field(0);
+
+  EXPECT_TRUE(HasSpan("a", "k", field));
+  EXPECT_TRUE(HasSpan("a", "b", field, "label"));
+  EXPECT_TRUE(HasSpan("c", "d", field, "type"));
+  EXPECT_TRUE(HasSpan("e", "f", field, "name"));
+  EXPECT_TRUE(HasSpan("e", "f", field, "type_name"));
+  EXPECT_TRUE(HasSpan("g", "h", field, "number"));
+
+  EXPECT_TRUE(HasSpan("a", "k", baz));
+  EXPECT_TRUE(HasSpan("e", "f", baz, "name"));
+  EXPECT_TRUE(HasSpan("i", "j", qux));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(bar));
+  EXPECT_TRUE(HasSpan(bar, "name"));
+  EXPECT_TRUE(HasSpan(qux, "name"));
+}
+
+TEST_F(SourceInfoTest, Enums) {
+  EXPECT_TRUE(Parse(
+      "/*a*/enum /*b*/Foo/*c*/ {}/*d*/\n"
+      "/*e*/enum /*f*/Bar/*g*/ {}/*h*/\n"));
+
+  EXPECT_TRUE(HasSpan("a", "d", file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan("b", "c", file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan("e", "h", file_.enum_type(1)));
+  EXPECT_TRUE(HasSpan("f", "g", file_.enum_type(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, EnumValues) {
+  EXPECT_TRUE(Parse(
+      "enum Foo {\n"
+      "  /*a*/BAR/*b*/ = /*c*/1/*d*/;/*e*/\n"
+      "  /*f*/BAZ/*g*/ = /*h*/2/*i*/;/*j*/\n"
+      "}"));
+
+  const EnumValueDescriptorProto& bar = file_.enum_type(0).value(0);
+  const EnumValueDescriptorProto& baz = file_.enum_type(0).value(1);
+
+  EXPECT_TRUE(HasSpan("a", "e", bar));
+  EXPECT_TRUE(HasSpan("a", "b", bar, "name"));
+  EXPECT_TRUE(HasSpan("c", "d", bar, "number"));
+  EXPECT_TRUE(HasSpan("f", "j", baz));
+  EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
+  EXPECT_TRUE(HasSpan("h", "i", baz, "number"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, NestedEnums) {
+  EXPECT_TRUE(Parse(
+      "message Foo {\n"
+      "  /*a*/enum /*b*/Bar/*c*/ {}/*d*/\n"
+      "  /*e*/enum /*f*/Baz/*g*/ {}/*h*/\n"
+      "}\n"));
+
+  const EnumDescriptorProto& bar = file_.message_type(0).enum_type(0);
+  const EnumDescriptorProto& baz = file_.message_type(0).enum_type(1);
+
+  EXPECT_TRUE(HasSpan("a", "d", bar));
+  EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
+  EXPECT_TRUE(HasSpan("e", "h", baz));
+  EXPECT_TRUE(HasSpan("f", "g", baz, "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Services) {
+  EXPECT_TRUE(Parse(
+      "/*a*/service /*b*/Foo/*c*/ {}/*d*/\n"
+      "/*e*/service /*f*/Bar/*g*/ {}/*h*/\n"));
+
+  EXPECT_TRUE(HasSpan("a", "d", file_.service(0)));
+  EXPECT_TRUE(HasSpan("b", "c", file_.service(0), "name"));
+  EXPECT_TRUE(HasSpan("e", "h", file_.service(1)));
+  EXPECT_TRUE(HasSpan("f", "g", file_.service(1), "name"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+}
+
+TEST_F(SourceInfoTest, Methods) {
+  EXPECT_TRUE(Parse(
+      "service Foo {\n"
+      "  /*a*/rpc /*b*/Bar/*c*/(/*d*/X/*e*/) returns(/*f*/Y/*g*/);/*h*/"
+      "  /*i*/rpc /*j*/Baz/*k*/(/*l*/Z/*m*/) returns(/*n*/W/*o*/);/*p*/"
+      "}"));
+
+  const MethodDescriptorProto& bar = file_.service(0).method(0);
+  const MethodDescriptorProto& baz = file_.service(0).method(1);
+
+  EXPECT_TRUE(HasSpan("a", "h", bar));
+  EXPECT_TRUE(HasSpan("b", "c", bar, "name"));
+  EXPECT_TRUE(HasSpan("d", "e", bar, "input_type"));
+  EXPECT_TRUE(HasSpan("f", "g", bar, "output_type"));
+
+  EXPECT_TRUE(HasSpan("i", "p", baz));
+  EXPECT_TRUE(HasSpan("j", "k", baz, "name"));
+  EXPECT_TRUE(HasSpan("l", "m", baz, "input_type"));
+  EXPECT_TRUE(HasSpan("n", "o", baz, "output_type"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.service(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0), "name"));
+}
+
+TEST_F(SourceInfoTest, Options) {
+  EXPECT_TRUE(Parse(
+      "/*a*/option /*b*/foo/*c*/./*d*/(/*e*/bar.baz/*f*/)/*g*/ = "
+          "/*h*/123/*i*/;/*j*/\n"
+      "/*k*/option qux = /*l*/-123/*m*/;/*n*/\n"
+      "/*o*/option corge = /*p*/abc/*q*/;/*r*/\n"
+      "/*s*/option grault = /*t*/'blah'/*u*/;/*v*/\n"
+      "/*w*/option garply = /*x*/{ yadda yadda }/*y*/;/*z*/\n"
+      "/*0*/option waldo = /*1*/123.0/*2*/;/*3*/\n"
+  ));
+
+  const UninterpretedOption& option1 = file_.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = file_.options().uninterpreted_option(1);
+  const UninterpretedOption& option3 = file_.options().uninterpreted_option(2);
+  const UninterpretedOption& option4 = file_.options().uninterpreted_option(3);
+  const UninterpretedOption& option5 = file_.options().uninterpreted_option(4);
+  const UninterpretedOption& option6 = file_.options().uninterpreted_option(5);
+
+  EXPECT_TRUE(HasSpan("a", "j", file_.options()));
+  EXPECT_TRUE(HasSpan("b", "i", option1));
+  EXPECT_TRUE(HasSpan("b", "g", option1, "name"));
+  EXPECT_TRUE(HasSpan("b", "c", option1.name(0)));
+  EXPECT_TRUE(HasSpan("b", "c", option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan("d", "g", option1.name(1)));
+  EXPECT_TRUE(HasSpan("e", "f", option1.name(1), "name_part"));
+  EXPECT_TRUE(HasSpan("h", "i", option1, "positive_int_value"));
+
+  EXPECT_TRUE(HasSpan("k", "n", file_.options()));
+  EXPECT_TRUE(HasSpan("l", "m", option2, "negative_int_value"));
+
+  EXPECT_TRUE(HasSpan("o", "r", file_.options()));
+  EXPECT_TRUE(HasSpan("p", "q", option3, "identifier_value"));
+
+  EXPECT_TRUE(HasSpan("s", "v", file_.options()));
+  EXPECT_TRUE(HasSpan("t", "u", option4, "string_value"));
+
+  EXPECT_TRUE(HasSpan("w", "z", file_.options()));
+  EXPECT_TRUE(HasSpan("x", "y", option5, "aggregate_value"));
+
+  EXPECT_TRUE(HasSpan("0", "3", file_.options()));
+  EXPECT_TRUE(HasSpan("1", "2", option6, "double_value"));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(option2));
+  EXPECT_TRUE(HasSpan(option3));
+  EXPECT_TRUE(HasSpan(option4));
+  EXPECT_TRUE(HasSpan(option5));
+  EXPECT_TRUE(HasSpan(option6));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option3, "name"));
+  EXPECT_TRUE(HasSpan(option4, "name"));
+  EXPECT_TRUE(HasSpan(option5, "name"));
+  EXPECT_TRUE(HasSpan(option6, "name"));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option3.name(0)));
+  EXPECT_TRUE(HasSpan(option4.name(0)));
+  EXPECT_TRUE(HasSpan(option5.name(0)));
+  EXPECT_TRUE(HasSpan(option6.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option3.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option4.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option5.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option6.name(0), "name_part"));
+}
+
+TEST_F(SourceInfoTest, ScopedOptions) {
+  EXPECT_TRUE(Parse(
+    "message Foo {\n"
+    "  /*a*/option mopt = 1;/*b*/\n"
+    "}\n"
+    "enum Bar {\n"
+    "  /*c*/option eopt = 1;/*d*/\n"
+    "}\n"
+    "service Baz {\n"
+    "  /*e*/option sopt = 1;/*f*/\n"
+    "  rpc M(X) returns(Y) {\n"
+    "    /*g*/option mopt = 1;/*h*/\n"
+    "  }\n"
+    "}\n"));
+
+  EXPECT_TRUE(HasSpan("a", "b", file_.message_type(0).options()));
+  EXPECT_TRUE(HasSpan("c", "d", file_.enum_type(0).options()));
+  EXPECT_TRUE(HasSpan("e", "f", file_.service(0).options()));
+  EXPECT_TRUE(HasSpan("g", "h", file_.service(0).method(0).options()));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.message_type(0).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.service(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.service(0).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "input_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0), "output_type"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
+                      .uninterpreted_option(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
+                      .uninterpreted_option(0), "name"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
+                      .uninterpreted_option(0).name(0)));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
+                      .uninterpreted_option(0).name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(file_.service(0).method(0).options()
+                      .uninterpreted_option(0), "positive_int_value"));
+}
+
+TEST_F(SourceInfoTest, FieldOptions) {
+  // The actual "name = value" pairs are parsed by the same code as for
+  // top-level options so we won't re-test that -- just make sure that the
+  // syntax used for field options is understood.
+  EXPECT_TRUE(Parse(
+      "message Foo {"
+      "  optional int32 bar = 1 "
+          "/*a*/[default=/*b*/123/*c*/,/*d*/opt1=123/*e*/,"
+          "/*f*/opt2='hi'/*g*/]/*h*/;"
+      "}\n"
+  ));
+
+  const FieldDescriptorProto& field = file_.message_type(0).field(0);
+  const UninterpretedOption& option1 = field.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = field.options().uninterpreted_option(1);
+
+  EXPECT_TRUE(HasSpan("a", "h", field.options()));
+  EXPECT_TRUE(HasSpan("b", "c", field, "default_value"));
+  EXPECT_TRUE(HasSpan("d", "e", option1));
+  EXPECT_TRUE(HasSpan("f", "g", option2));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.message_type(0)));
+  EXPECT_TRUE(HasSpan(file_.message_type(0), "name"));
+  EXPECT_TRUE(HasSpan(field));
+  EXPECT_TRUE(HasSpan(field, "label"));
+  EXPECT_TRUE(HasSpan(field, "type"));
+  EXPECT_TRUE(HasSpan(field, "name"));
+  EXPECT_TRUE(HasSpan(field, "number"));
+  EXPECT_TRUE(HasSpan(option1, "name"));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option1.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
+  EXPECT_TRUE(HasSpan(option2, "string_value"));
+}
+
+TEST_F(SourceInfoTest, EnumValueOptions) {
+  // The actual "name = value" pairs are parsed by the same code as for
+  // top-level options so we won't re-test that -- just make sure that the
+  // syntax used for enum options is understood.
+  EXPECT_TRUE(Parse(
+      "enum Foo {"
+      "  BAR = 1 /*a*/[/*b*/opt1=123/*c*/,/*d*/opt2='hi'/*e*/]/*f*/;"
+      "}\n"
+  ));
+
+  const EnumValueDescriptorProto& value = file_.enum_type(0).value(0);
+  const UninterpretedOption& option1 = value.options().uninterpreted_option(0);
+  const UninterpretedOption& option2 = value.options().uninterpreted_option(1);
+
+  EXPECT_TRUE(HasSpan("a", "f", value.options()));
+  EXPECT_TRUE(HasSpan("b", "c", option1));
+  EXPECT_TRUE(HasSpan("d", "e", option2));
+
+  // Ignore these.
+  EXPECT_TRUE(HasSpan(file_));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0)));
+  EXPECT_TRUE(HasSpan(file_.enum_type(0), "name"));
+  EXPECT_TRUE(HasSpan(value));
+  EXPECT_TRUE(HasSpan(value, "name"));
+  EXPECT_TRUE(HasSpan(value, "number"));
+  EXPECT_TRUE(HasSpan(option1, "name"));
+  EXPECT_TRUE(HasSpan(option2, "name"));
+  EXPECT_TRUE(HasSpan(option1.name(0)));
+  EXPECT_TRUE(HasSpan(option2.name(0)));
+  EXPECT_TRUE(HasSpan(option1.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option2.name(0), "name_part"));
+  EXPECT_TRUE(HasSpan(option1, "positive_int_value"));
+  EXPECT_TRUE(HasSpan(option2, "string_value"));
+}
+
+// ===================================================================
 
 }  // anonymous namespace
 
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index a4aedaf..727f942 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -59,13 +59,15 @@
 namespace protobuf {
 namespace compiler {
 
-class GeneratorResponseOutputDirectory : public OutputDirectory {
+class GeneratorResponseContext : public GeneratorContext {
  public:
-  GeneratorResponseOutputDirectory(CodeGeneratorResponse* response)
-      : response_(response) {}
-  virtual ~GeneratorResponseOutputDirectory() {}
+  GeneratorResponseContext(CodeGeneratorResponse* response,
+                           const vector<const FileDescriptor*>& parsed_files)
+      : response_(response),
+        parsed_files_(parsed_files) {}
+  virtual ~GeneratorResponseContext() {}
 
-  // implements OutputDirectory --------------------------------------
+  // implements GeneratorContext --------------------------------------
 
   virtual io::ZeroCopyOutputStream* Open(const string& filename) {
     CodeGeneratorResponse::File* file = response_->add_file();
@@ -81,8 +83,13 @@
     return new io::StringOutputStream(file->mutable_content());
   }
 
+  void ListParsedFiles(vector<const FileDescriptor*>* output) {
+    *output = parsed_files_;
+  }
+
  private:
   CodeGeneratorResponse* response_;
+  const vector<const FileDescriptor*>& parsed_files_;
 };
 
 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
@@ -112,22 +119,26 @@
     }
   }
 
-  CodeGeneratorResponse response;
-  GeneratorResponseOutputDirectory output_directory(&response);
-
+  vector<const FileDescriptor*> parsed_files;
   for (int i = 0; i < request.file_to_generate_size(); i++) {
-    const FileDescriptor* file =
-        pool.FindFileByName(request.file_to_generate(i));
-    if (file == NULL) {
+    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
+    if (parsed_files.back() == NULL) {
       cerr << argv[0] << ": protoc asked plugin to generate a file but "
               "did not provide a descriptor for the file: "
            << request.file_to_generate(i) << endl;
       return 1;
     }
+  }
+
+  CodeGeneratorResponse response;
+  GeneratorResponseContext context(&response, parsed_files);
+
+  for (int i = 0; i < parsed_files.size(); i++) {
+    const FileDescriptor* file = parsed_files[i];
 
     string error;
     bool succeeded = generator->Generate(
-        file, request.parameter(), &output_directory, &error);
+        file, request.parameter(), &context, &error);
 
     if (!succeeded && error.empty()) {
       error = "Code generator returned false but provided no error "
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 7c40333..64dfb1d 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -64,7 +64,7 @@
 class CodeGenerator;    // code_generator.h
 
 // Implements main() for a protoc plugin exposing the given code generator.
-LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
+int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
 
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 13d35c6..ad4b4de 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -158,7 +158,6 @@
 
 // ===================================================================
 
-const ::std::string CodeGeneratorRequest::_default_parameter_;
 #ifndef _MSC_VER
 const int CodeGeneratorRequest::kFileToGenerateFieldNumber;
 const int CodeGeneratorRequest::kParameterFieldNumber;
@@ -181,7 +180,7 @@
 
 void CodeGeneratorRequest::SharedCtor() {
   _cached_size_ = 0;
-  parameter_ = const_cast< ::std::string*>(&_default_parameter_);
+  parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -190,7 +189,7 @@
 }
 
 void CodeGeneratorRequest::SharedDtor() {
-  if (parameter_ != &_default_parameter_) {
+  if (parameter_ != &::google::protobuf::internal::kEmptyString) {
     delete parameter_;
   }
   if (this != default_instance_) {
@@ -219,8 +218,8 @@
 
 void CodeGeneratorRequest::Clear() {
   if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) {
-    if (_has_bit(1)) {
-      if (parameter_ != &_default_parameter_) {
+    if (has_parameter()) {
+      if (parameter_ != &::google::protobuf::internal::kEmptyString) {
         parameter_->clear();
       }
     }
@@ -315,7 +314,7 @@
   }
   
   // optional string parameter = 2;
-  if (_has_bit(1)) {
+  if (has_parameter()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->parameter().data(), this->parameter().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -347,7 +346,7 @@
   }
   
   // optional string parameter = 2;
-  if (_has_bit(1)) {
+  if (has_parameter()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->parameter().data(), this->parameter().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -425,7 +424,7 @@
   file_to_generate_.MergeFrom(from.file_to_generate_);
   proto_file_.MergeFrom(from.proto_file_);
   if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) {
-    if (from._has_bit(1)) {
+    if (from.has_parameter()) {
       set_parameter(from.parameter());
     }
   }
@@ -474,9 +473,6 @@
 
 // ===================================================================
 
-const ::std::string CodeGeneratorResponse_File::_default_name_;
-const ::std::string CodeGeneratorResponse_File::_default_insertion_point_;
-const ::std::string CodeGeneratorResponse_File::_default_content_;
 #ifndef _MSC_VER
 const int CodeGeneratorResponse_File::kNameFieldNumber;
 const int CodeGeneratorResponse_File::kInsertionPointFieldNumber;
@@ -499,9 +495,9 @@
 
 void CodeGeneratorResponse_File::SharedCtor() {
   _cached_size_ = 0;
-  name_ = const_cast< ::std::string*>(&_default_name_);
-  insertion_point_ = const_cast< ::std::string*>(&_default_insertion_point_);
-  content_ = const_cast< ::std::string*>(&_default_content_);
+  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+  insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+  content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -510,13 +506,13 @@
 }
 
 void CodeGeneratorResponse_File::SharedDtor() {
-  if (name_ != &_default_name_) {
+  if (name_ != &::google::protobuf::internal::kEmptyString) {
     delete name_;
   }
-  if (insertion_point_ != &_default_insertion_point_) {
+  if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
     delete insertion_point_;
   }
-  if (content_ != &_default_content_) {
+  if (content_ != &::google::protobuf::internal::kEmptyString) {
     delete content_;
   }
   if (this != default_instance_) {
@@ -545,18 +541,18 @@
 
 void CodeGeneratorResponse_File::Clear() {
   if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (_has_bit(0)) {
-      if (name_ != &_default_name_) {
+    if (has_name()) {
+      if (name_ != &::google::protobuf::internal::kEmptyString) {
         name_->clear();
       }
     }
-    if (_has_bit(1)) {
-      if (insertion_point_ != &_default_insertion_point_) {
+    if (has_insertion_point()) {
+      if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
         insertion_point_->clear();
       }
     }
-    if (_has_bit(2)) {
-      if (content_ != &_default_content_) {
+    if (has_content()) {
+      if (content_ != &::google::protobuf::internal::kEmptyString) {
         content_->clear();
       }
     }
@@ -640,7 +636,7 @@
 void CodeGeneratorResponse_File::SerializeWithCachedSizes(
     ::google::protobuf::io::CodedOutputStream* output) const {
   // optional string name = 1;
-  if (_has_bit(0)) {
+  if (has_name()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -649,7 +645,7 @@
   }
   
   // optional string insertion_point = 2;
-  if (_has_bit(1)) {
+  if (has_insertion_point()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->insertion_point().data(), this->insertion_point().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -658,7 +654,7 @@
   }
   
   // optional string content = 15;
-  if (_has_bit(2)) {
+  if (has_content()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->content().data(), this->content().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -675,7 +671,7 @@
 ::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray(
     ::google::protobuf::uint8* target) const {
   // optional string name = 1;
-  if (_has_bit(0)) {
+  if (has_name()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->name().data(), this->name().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -685,7 +681,7 @@
   }
   
   // optional string insertion_point = 2;
-  if (_has_bit(1)) {
+  if (has_insertion_point()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->insertion_point().data(), this->insertion_point().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -695,7 +691,7 @@
   }
   
   // optional string content = 15;
-  if (_has_bit(2)) {
+  if (has_content()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->content().data(), this->content().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -763,13 +759,13 @@
 void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) {
   GOOGLE_CHECK_NE(&from, this);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (from._has_bit(0)) {
+    if (from.has_name()) {
       set_name(from.name());
     }
-    if (from._has_bit(1)) {
+    if (from.has_insertion_point()) {
       set_insertion_point(from.insertion_point());
     }
-    if (from._has_bit(2)) {
+    if (from.has_content()) {
       set_content(from.content());
     }
   }
@@ -815,7 +811,6 @@
 
 // -------------------------------------------------------------------
 
-const ::std::string CodeGeneratorResponse::_default_error_;
 #ifndef _MSC_VER
 const int CodeGeneratorResponse::kErrorFieldNumber;
 const int CodeGeneratorResponse::kFileFieldNumber;
@@ -837,7 +832,7 @@
 
 void CodeGeneratorResponse::SharedCtor() {
   _cached_size_ = 0;
-  error_ = const_cast< ::std::string*>(&_default_error_);
+  error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -846,7 +841,7 @@
 }
 
 void CodeGeneratorResponse::SharedDtor() {
-  if (error_ != &_default_error_) {
+  if (error_ != &::google::protobuf::internal::kEmptyString) {
     delete error_;
   }
   if (this != default_instance_) {
@@ -875,8 +870,8 @@
 
 void CodeGeneratorResponse::Clear() {
   if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (_has_bit(0)) {
-      if (error_ != &_default_error_) {
+    if (has_error()) {
+      if (error_ != &::google::protobuf::internal::kEmptyString) {
         error_->clear();
       }
     }
@@ -942,7 +937,7 @@
 void CodeGeneratorResponse::SerializeWithCachedSizes(
     ::google::protobuf::io::CodedOutputStream* output) const {
   // optional string error = 1;
-  if (_has_bit(0)) {
+  if (has_error()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->error().data(), this->error().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -965,7 +960,7 @@
 ::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray(
     ::google::protobuf::uint8* target) const {
   // optional string error = 1;
-  if (_has_bit(0)) {
+  if (has_error()) {
     ::google::protobuf::internal::WireFormat::VerifyUTF8String(
       this->error().data(), this->error().length(),
       ::google::protobuf::internal::WireFormat::SERIALIZE);
@@ -1035,7 +1030,7 @@
   GOOGLE_CHECK_NE(&from, this);
   file_.MergeFrom(from.file_);
   if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (from._has_bit(0)) {
+    if (from.has_error()) {
       set_error(from.error());
     }
   }
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index bd6bf63..c307bfd 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -120,6 +120,7 @@
   inline void set_parameter(const char* value);
   inline void set_parameter(const char* value, size_t size);
   inline ::std::string* mutable_parameter();
+  inline ::std::string* release_parameter();
   
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   inline int proto_file_size() const;
@@ -135,30 +136,22 @@
   
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
  private:
+  inline void set_has_parameter();
+  inline void clear_has_parameter();
+  
   ::google::protobuf::UnknownFieldSet _unknown_fields_;
-  mutable int _cached_size_;
   
   ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_;
   ::std::string* parameter_;
-  static const ::std::string _default_parameter_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_;
+  
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+  
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-  
-  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
-  inline bool _has_bit(int index) const {
-    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
-  }
-  inline void _set_bit(int index) {
-    _has_bits_[index / 32] |= (1u << (index % 32));
-  }
-  inline void _clear_bit(int index) {
-    _has_bits_[index / 32] &= ~(1u << (index % 32));
-  }
-  
   void InitAsDefaultInstance();
   static CodeGeneratorRequest* default_instance_;
 };
@@ -227,6 +220,7 @@
   inline void set_name(const char* value);
   inline void set_name(const char* value, size_t size);
   inline ::std::string* mutable_name();
+  inline ::std::string* release_name();
   
   // optional string insertion_point = 2;
   inline bool has_insertion_point() const;
@@ -237,6 +231,7 @@
   inline void set_insertion_point(const char* value);
   inline void set_insertion_point(const char* value, size_t size);
   inline ::std::string* mutable_insertion_point();
+  inline ::std::string* release_insertion_point();
   
   // optional string content = 15;
   inline bool has_content() const;
@@ -247,35 +242,30 @@
   inline void set_content(const char* value);
   inline void set_content(const char* value, size_t size);
   inline ::std::string* mutable_content();
+  inline ::std::string* release_content();
   
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
  private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_insertion_point();
+  inline void clear_has_insertion_point();
+  inline void set_has_content();
+  inline void clear_has_content();
+  
   ::google::protobuf::UnknownFieldSet _unknown_fields_;
-  mutable int _cached_size_;
   
   ::std::string* name_;
-  static const ::std::string _default_name_;
   ::std::string* insertion_point_;
-  static const ::std::string _default_insertion_point_;
   ::std::string* content_;
-  static const ::std::string _default_content_;
+  
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+  
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
-  
-  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
-  inline bool _has_bit(int index) const {
-    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
-  }
-  inline void _set_bit(int index) {
-    _has_bits_[index / 32] |= (1u << (index % 32));
-  }
-  inline void _clear_bit(int index) {
-    _has_bits_[index / 32] &= ~(1u << (index % 32));
-  }
-  
   void InitAsDefaultInstance();
   static CodeGeneratorResponse_File* default_instance_;
 };
@@ -346,6 +336,7 @@
   inline void set_error(const char* value);
   inline void set_error(const char* value, size_t size);
   inline ::std::string* mutable_error();
+  inline ::std::string* release_error();
   
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
   inline int file_size() const;
@@ -361,29 +352,21 @@
   
   // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
  private:
+  inline void set_has_error();
+  inline void clear_has_error();
+  
   ::google::protobuf::UnknownFieldSet _unknown_fields_;
-  mutable int _cached_size_;
   
   ::std::string* error_;
-  static const ::std::string _default_error_;
   ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
+  
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+  
   friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
-  
-  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
-  inline bool _has_bit(int index) const {
-    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
-  }
-  inline void _set_bit(int index) {
-    _has_bits_[index / 32] |= (1u << (index % 32));
-  }
-  inline void _clear_bit(int index) {
-    _has_bits_[index / 32] &= ~(1u << (index % 32));
-  }
-  
   void InitAsDefaultInstance();
   static CodeGeneratorResponse* default_instance_;
 };
@@ -440,45 +423,61 @@
 
 // optional string parameter = 2;
 inline bool CodeGeneratorRequest::has_parameter() const {
-  return _has_bit(1);
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void CodeGeneratorRequest::set_has_parameter() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void CodeGeneratorRequest::clear_has_parameter() {
+  _has_bits_[0] &= ~0x00000002u;
 }
 inline void CodeGeneratorRequest::clear_parameter() {
-  if (parameter_ != &_default_parameter_) {
+  if (parameter_ != &::google::protobuf::internal::kEmptyString) {
     parameter_->clear();
   }
-  _clear_bit(1);
+  clear_has_parameter();
 }
 inline const ::std::string& CodeGeneratorRequest::parameter() const {
   return *parameter_;
 }
 inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
-  _set_bit(1);
-  if (parameter_ == &_default_parameter_) {
+  set_has_parameter();
+  if (parameter_ == &::google::protobuf::internal::kEmptyString) {
     parameter_ = new ::std::string;
   }
   parameter_->assign(value);
 }
 inline void CodeGeneratorRequest::set_parameter(const char* value) {
-  _set_bit(1);
-  if (parameter_ == &_default_parameter_) {
+  set_has_parameter();
+  if (parameter_ == &::google::protobuf::internal::kEmptyString) {
     parameter_ = new ::std::string;
   }
   parameter_->assign(value);
 }
 inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
-  _set_bit(1);
-  if (parameter_ == &_default_parameter_) {
+  set_has_parameter();
+  if (parameter_ == &::google::protobuf::internal::kEmptyString) {
     parameter_ = new ::std::string;
   }
   parameter_->assign(reinterpret_cast<const char*>(value), size);
 }
 inline ::std::string* CodeGeneratorRequest::mutable_parameter() {
-  _set_bit(1);
-  if (parameter_ == &_default_parameter_) {
+  set_has_parameter();
+  if (parameter_ == &::google::protobuf::internal::kEmptyString) {
     parameter_ = new ::std::string;
   }
   return parameter_;
 }
+inline ::std::string* CodeGeneratorRequest::release_parameter() {
+  clear_has_parameter();
+  if (parameter_ == &::google::protobuf::internal::kEmptyString) {
+    return NULL;
+  } else {
+    ::std::string* temp = parameter_;
+    parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+    return temp;
+  }
+}
 
 // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
 inline int CodeGeneratorRequest::proto_file_size() const {
@@ -511,129 +510,177 @@
 
 // optional string name = 1;
 inline bool CodeGeneratorResponse_File::has_name() const {
-  return _has_bit(0);
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void CodeGeneratorResponse_File::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void CodeGeneratorResponse_File::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
 }
 inline void CodeGeneratorResponse_File::clear_name() {
-  if (name_ != &_default_name_) {
+  if (name_ != &::google::protobuf::internal::kEmptyString) {
     name_->clear();
   }
-  _clear_bit(0);
+  clear_has_name();
 }
 inline const ::std::string& CodeGeneratorResponse_File::name() const {
   return *name_;
 }
 inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
-  _set_bit(0);
-  if (name_ == &_default_name_) {
+  set_has_name();
+  if (name_ == &::google::protobuf::internal::kEmptyString) {
     name_ = new ::std::string;
   }
   name_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_name(const char* value) {
-  _set_bit(0);
-  if (name_ == &_default_name_) {
+  set_has_name();
+  if (name_ == &::google::protobuf::internal::kEmptyString) {
     name_ = new ::std::string;
   }
   name_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
-  _set_bit(0);
-  if (name_ == &_default_name_) {
+  set_has_name();
+  if (name_ == &::google::protobuf::internal::kEmptyString) {
     name_ = new ::std::string;
   }
   name_->assign(reinterpret_cast<const char*>(value), size);
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_name() {
-  _set_bit(0);
-  if (name_ == &_default_name_) {
+  set_has_name();
+  if (name_ == &::google::protobuf::internal::kEmptyString) {
     name_ = new ::std::string;
   }
   return name_;
 }
+inline ::std::string* CodeGeneratorResponse_File::release_name() {
+  clear_has_name();
+  if (name_ == &::google::protobuf::internal::kEmptyString) {
+    return NULL;
+  } else {
+    ::std::string* temp = name_;
+    name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+    return temp;
+  }
+}
 
 // optional string insertion_point = 2;
 inline bool CodeGeneratorResponse_File::has_insertion_point() const {
-  return _has_bit(1);
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void CodeGeneratorResponse_File::set_has_insertion_point() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void CodeGeneratorResponse_File::clear_has_insertion_point() {
+  _has_bits_[0] &= ~0x00000002u;
 }
 inline void CodeGeneratorResponse_File::clear_insertion_point() {
-  if (insertion_point_ != &_default_insertion_point_) {
+  if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
     insertion_point_->clear();
   }
-  _clear_bit(1);
+  clear_has_insertion_point();
 }
 inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
   return *insertion_point_;
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
-  _set_bit(1);
-  if (insertion_point_ == &_default_insertion_point_) {
+  set_has_insertion_point();
+  if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
     insertion_point_ = new ::std::string;
   }
   insertion_point_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
-  _set_bit(1);
-  if (insertion_point_ == &_default_insertion_point_) {
+  set_has_insertion_point();
+  if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
     insertion_point_ = new ::std::string;
   }
   insertion_point_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
-  _set_bit(1);
-  if (insertion_point_ == &_default_insertion_point_) {
+  set_has_insertion_point();
+  if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
     insertion_point_ = new ::std::string;
   }
   insertion_point_->assign(reinterpret_cast<const char*>(value), size);
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
-  _set_bit(1);
-  if (insertion_point_ == &_default_insertion_point_) {
+  set_has_insertion_point();
+  if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
     insertion_point_ = new ::std::string;
   }
   return insertion_point_;
 }
+inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
+  clear_has_insertion_point();
+  if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
+    return NULL;
+  } else {
+    ::std::string* temp = insertion_point_;
+    insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+    return temp;
+  }
+}
 
 // optional string content = 15;
 inline bool CodeGeneratorResponse_File::has_content() const {
-  return _has_bit(2);
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void CodeGeneratorResponse_File::set_has_content() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void CodeGeneratorResponse_File::clear_has_content() {
+  _has_bits_[0] &= ~0x00000004u;
 }
 inline void CodeGeneratorResponse_File::clear_content() {
-  if (content_ != &_default_content_) {
+  if (content_ != &::google::protobuf::internal::kEmptyString) {
     content_->clear();
   }
-  _clear_bit(2);
+  clear_has_content();
 }
 inline const ::std::string& CodeGeneratorResponse_File::content() const {
   return *content_;
 }
 inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
-  _set_bit(2);
-  if (content_ == &_default_content_) {
+  set_has_content();
+  if (content_ == &::google::protobuf::internal::kEmptyString) {
     content_ = new ::std::string;
   }
   content_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_content(const char* value) {
-  _set_bit(2);
-  if (content_ == &_default_content_) {
+  set_has_content();
+  if (content_ == &::google::protobuf::internal::kEmptyString) {
     content_ = new ::std::string;
   }
   content_->assign(value);
 }
 inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
-  _set_bit(2);
-  if (content_ == &_default_content_) {
+  set_has_content();
+  if (content_ == &::google::protobuf::internal::kEmptyString) {
     content_ = new ::std::string;
   }
   content_->assign(reinterpret_cast<const char*>(value), size);
 }
 inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
-  _set_bit(2);
-  if (content_ == &_default_content_) {
+  set_has_content();
+  if (content_ == &::google::protobuf::internal::kEmptyString) {
     content_ = new ::std::string;
   }
   return content_;
 }
+inline ::std::string* CodeGeneratorResponse_File::release_content() {
+  clear_has_content();
+  if (content_ == &::google::protobuf::internal::kEmptyString) {
+    return NULL;
+  } else {
+    ::std::string* temp = content_;
+    content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+    return temp;
+  }
+}
 
 // -------------------------------------------------------------------
 
@@ -641,45 +688,61 @@
 
 // optional string error = 1;
 inline bool CodeGeneratorResponse::has_error() const {
-  return _has_bit(0);
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void CodeGeneratorResponse::set_has_error() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void CodeGeneratorResponse::clear_has_error() {
+  _has_bits_[0] &= ~0x00000001u;
 }
 inline void CodeGeneratorResponse::clear_error() {
-  if (error_ != &_default_error_) {
+  if (error_ != &::google::protobuf::internal::kEmptyString) {
     error_->clear();
   }
-  _clear_bit(0);
+  clear_has_error();
 }
 inline const ::std::string& CodeGeneratorResponse::error() const {
   return *error_;
 }
 inline void CodeGeneratorResponse::set_error(const ::std::string& value) {
-  _set_bit(0);
-  if (error_ == &_default_error_) {
+  set_has_error();
+  if (error_ == &::google::protobuf::internal::kEmptyString) {
     error_ = new ::std::string;
   }
   error_->assign(value);
 }
 inline void CodeGeneratorResponse::set_error(const char* value) {
-  _set_bit(0);
-  if (error_ == &_default_error_) {
+  set_has_error();
+  if (error_ == &::google::protobuf::internal::kEmptyString) {
     error_ = new ::std::string;
   }
   error_->assign(value);
 }
 inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
-  _set_bit(0);
-  if (error_ == &_default_error_) {
+  set_has_error();
+  if (error_ == &::google::protobuf::internal::kEmptyString) {
     error_ = new ::std::string;
   }
   error_->assign(reinterpret_cast<const char*>(value), size);
 }
 inline ::std::string* CodeGeneratorResponse::mutable_error() {
-  _set_bit(0);
-  if (error_ == &_default_error_) {
+  set_has_error();
+  if (error_ == &::google::protobuf::internal::kEmptyString) {
     error_ = new ::std::string;
   }
   return error_;
 }
+inline ::std::string* CodeGeneratorResponse::release_error() {
+  clear_has_error();
+  if (error_ == &::google::protobuf::internal::kEmptyString) {
+    return NULL;
+  } else {
+    ::std::string* temp = error_;
+    error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+    return temp;
+  }
+}
 
 // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
 inline int CodeGeneratorResponse::file_size() const {
diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto
index 4e928b0..651ed10 100644
--- a/src/google/protobuf/compiler/plugin.proto
+++ b/src/google/protobuf/compiler/plugin.proto
@@ -131,7 +131,7 @@
     // in order to work correctly in that context.
     //
     // The code generator that generates the initial file and the one which
-    // inserts into it must both run as part of a single invocatino of protoc.
+    // inserts into it must both run as part of a single invocation of protoc.
     // Code generators are executed in the order in which they appear on the
     // command line.
     //
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index fae83a3..9b10937 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -230,7 +230,7 @@
 
 bool Generator::Generate(const FileDescriptor* file,
                          const string& parameter,
-                         OutputDirectory* output_directory,
+                         GeneratorContext* context,
                          string* error) const {
 
   // Completely serialize all Generate() calls on this instance.  The
@@ -252,20 +252,18 @@
   fdp.SerializeToString(&file_descriptor_serialized_);
 
 
-  scoped_ptr<io::ZeroCopyOutputStream> output(output_directory->Open(filename));
+  scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
   GOOGLE_CHECK(output.get());
   io::Printer printer(output.get(), '$');
   printer_ = &printer;
 
   PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto());
+  PrintImports();
   PrintFileDescriptor();
   PrintTopLevelEnums();
   PrintTopLevelExtensions();
   PrintAllNestedEnumsInFile();
   PrintMessageDescriptors();
-  // We have to print the imports after the descriptors, so that mutually
-  // recursive protos in separate files can successfully reference each other.
-  PrintImports();
   FixForeignFieldsInDescriptors();
   PrintMessages();
   // We have to fix up the extensions after the message classes themselves,
@@ -377,7 +375,7 @@
   printer_->Print("containing_type=None,\n");
   printer_->Print("options=$options_value$,\n",
                   "options_value",
-                  OptionsValue("EnumOptions", CEscape(options_string)));
+                  OptionsValue("EnumOptions", options_string));
   EnumDescriptorProto edp;
   PrintSerializedPbInterval(enum_descriptor, edp);
   printer_->Outdent();
@@ -674,6 +672,17 @@
   }
 }
 
+void Generator::AddMessageToFileDescriptor(const Descriptor& descriptor) const {
+  map<string, string> m;
+  m["descriptor_name"] = kDescriptorKey;
+  m["message_name"] = descriptor.name();
+  m["message_descriptor_name"] = ModuleLevelDescriptorName(descriptor);
+  const char file_descriptor_template[] =
+      "$descriptor_name$.message_types_by_name['$message_name$'] = "
+      "$message_descriptor_name$\n";
+  printer_->Print(m, file_descriptor_template);
+}
+
 // Sets any necessary message_type and enum_type attributes
 // for the Python version of |field|.
 //
@@ -752,6 +761,9 @@
   for (int i = 0; i < file_->message_type_count(); ++i) {
     FixForeignFieldsInDescriptor(*file_->message_type(i), NULL);
   }
+  for (int i = 0; i < file_->message_type_count(); ++i) {
+    AddMessageToFileDescriptor(*file_->message_type(i));
+  }
   printer_->Print("\n");
 }
 
@@ -823,6 +835,8 @@
       "  type=None)");
 }
 
+// Returns a Python expression that calls descriptor._ParseOptions using
+// the given descriptor class name and serialized options protobuf string.
 string Generator::OptionsValue(
     const string& class_name, const string& serialized_options) const {
   if (serialized_options.length() == 0 || GeneratingDescriptorProto()) {
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index 43c2087..84eaf8a 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -66,7 +66,7 @@
   // CodeGenerator methods.
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* generator_context,
                         string* error) const;
 
  private:
@@ -104,6 +104,7 @@
   void FixForeignFieldsInField(const Descriptor* containing_type,
                                const FieldDescriptor& field,
                                const string& python_dict_name) const;
+  void AddMessageToFileDescriptor(const Descriptor& descriptor) const;
   string FieldReferencingExpression(const Descriptor* containing_type,
                                     const FieldDescriptor& field,
                                     const string& python_dict_name) const;
diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
index fde8876..da619ad 100644
--- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc
@@ -56,19 +56,19 @@
 
   virtual bool Generate(const FileDescriptor* file,
                         const string& parameter,
-                        OutputDirectory* output_directory,
+                        GeneratorContext* context,
                         string* error) const {
-    TryInsert("test_pb2.py", "imports", output_directory);
-    TryInsert("test_pb2.py", "module_scope", output_directory);
-    TryInsert("test_pb2.py", "class_scope:foo.Bar", output_directory);
-    TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", output_directory);
+    TryInsert("test_pb2.py", "imports", context);
+    TryInsert("test_pb2.py", "module_scope", context);
+    TryInsert("test_pb2.py", "class_scope:foo.Bar", context);
+    TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", context);
     return true;
   }
 
   void TryInsert(const string& filename, const string& insertion_point,
-                 OutputDirectory* output_directory) const {
+                 GeneratorContext* context) const {
     scoped_ptr<io::ZeroCopyOutputStream> output(
-      output_directory->OpenForInsert(filename, insertion_point));
+      context->OpenForInsert(filename, insertion_point));
     io::Printer printer(output.get(), '$');
     printer.Print("// inserted $name$\n", "name", insertion_point);
   }
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index dbd813e..5fb5d5c 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -32,6 +32,8 @@
 
 #include <google/protobuf/compiler/subprocess.h>
 
+#include <algorithm>
+
 #ifndef _WIN32
 #include <errno.h>
 #include <sys/select.h>
@@ -39,7 +41,6 @@
 #include <signal.h>
 #endif
 
-#include <algorithm>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/stubs/substitute.h>
diff --git a/src/google/protobuf/compiler/subprocess.h b/src/google/protobuf/compiler/subprocess.h
index 7a6fa70..de9fce9 100644
--- a/src/google/protobuf/compiler/subprocess.h
+++ b/src/google/protobuf/compiler/subprocess.h
@@ -40,9 +40,10 @@
 #include <sys/types.h>
 #include <unistd.h>
 #endif  // !_WIN32
+#include <google/protobuf/stubs/common.h>
 
 #include <string>
-#include <google/protobuf/stubs/common.h>
+
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/zip_output_unittest.sh b/src/google/protobuf/compiler/zip_output_unittest.sh
index 259d5d2..3a02436 100755
--- a/src/google/protobuf/compiler/zip_output_unittest.sh
+++ b/src/google/protobuf/compiler/zip_output_unittest.sh
@@ -39,45 +39,51 @@
   exit 1
 }
 
+TEST_TMPDIR=.
+PROTOC=./protoc
+
 echo '
+  syntax = "proto2";
   option java_multiple_files = true;
   option java_package = "test.jar";
   option java_outer_classname = "Outer";
   message Foo {}
   message Bar {}
-' > testzip.proto
+' > $TEST_TMPDIR/testzip.proto
 
-./protoc --cpp_out=testzip.zip --python_out=testzip.zip --java_out=testzip.jar \
-    testzip.proto || fail 'protoc failed.'
+$PROTOC \
+    --cpp_out=$TEST_TMPDIR/testzip.zip --python_out=$TEST_TMPDIR/testzip.zip \
+    --java_out=$TEST_TMPDIR/testzip.jar -I$TEST_TMPDIR testzip.proto \
+    || fail 'protoc failed.'
 
 echo "Testing output to zip..."
 if unzip -h > /dev/null; then
-  unzip -t testzip.zip > testzip.list || fail 'unzip failed.'
+  unzip -t $TEST_TMPDIR/testzip.zip > $TEST_TMPDIR/testzip.list || fail 'unzip failed.'
 
-  grep 'testing: testzip\.pb\.cc *OK$' testzip.list > /dev/null \
+  grep 'testing: testzip\.pb\.cc *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'testzip.pb.cc not found in output zip.'
-  grep 'testing: testzip\.pb\.h *OK$' testzip.list > /dev/null \
+  grep 'testing: testzip\.pb\.h *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'testzip.pb.h not found in output zip.'
-  grep 'testing: testzip_pb2\.py *OK$' testzip.list > /dev/null \
+  grep 'testing: testzip_pb2\.py *OK$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'testzip_pb2.py not found in output zip.'
-  grep -i 'manifest' testzip.list > /dev/null \
+  grep -i 'manifest' $TEST_TMPDIR/testzip.list > /dev/null \
     && fail 'Zip file contained manifest.'
 else
   echo "Warning:  'unzip' command not available.  Skipping test."
 fi
 
 echo "Testing output to jar..."
-if jar c testzip.proto > /dev/null; then
-  jar tf testzip.jar > testzip.list || fail 'jar failed.'
+if jar c $TEST_TMPDIR/testzip.proto > /dev/null; then
+  jar tf $TEST_TMPDIR/testzip.jar > $TEST_TMPDIR/testzip.list || fail 'jar failed.'
 
-  grep '^test/jar/Foo\.java$' testzip.list > /dev/null \
+  grep '^test/jar/Foo\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'Foo.java not found in output jar.'
-  grep '^test/jar/Bar\.java$' testzip.list > /dev/null \
+  grep '^test/jar/Bar\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'Bar.java not found in output jar.'
-  grep '^test/jar/Outer\.java$' testzip.list > /dev/null \
+  grep '^test/jar/Outer\.java$' $TEST_TMPDIR/testzip.list > /dev/null \
     || fail 'Outer.java not found in output jar.'
-  grep '^META-INF/MANIFEST\.MF$' testzip.list > /dev/null \
-    || fail 'Manifest not ofund in output jar.'
+  grep '^META-INF/MANIFEST\.MF$' $TEST_TMPDIR/testzip.list > /dev/null \
+    || fail 'Manifest not found in output jar.'
 else
   echo "Warning:  'jar' command not available.  Skipping test."
 fi
diff --git a/src/google/protobuf/compiler/zip_writer.cc b/src/google/protobuf/compiler/zip_writer.cc
index 53c1877..65d7352 100644
--- a/src/google/protobuf/compiler/zip_writer.cc
+++ b/src/google/protobuf/compiler/zip_writer.cc
@@ -28,6 +28,36 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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: ambrose@google.com (Ambrose Feinstein),
 //         kenton@google.com (Kenton Varda)
 //
@@ -183,6 +213,6 @@
   return output.HadError();
 }
 
-}  // namespace google
-}  // namespace protobuf
 }  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/zip_writer.h b/src/google/protobuf/compiler/zip_writer.h
index 4289553..be73972 100644
--- a/src/google/protobuf/compiler/zip_writer.h
+++ b/src/google/protobuf/compiler/zip_writer.h
@@ -28,6 +28,36 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// 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)
 
 #include <vector>
@@ -58,6 +88,6 @@
   vector<FileInfo> files_;
 };
 
-}  // namespace google
-}  // namespace protobuf
 }  // namespace compiler
+}  // namespace protobuf
+}  // namespace google