Integrate google internal changes.
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 3a816b0..87843f6 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -49,7 +49,7 @@
 #include <iostream>
 #include <ctype.h>
 
-#ifdef GOOGLE_PROTOBUF_ARCH_SPARC 
+#ifdef GOOGLE_PROTOBUF_ARCH_SPARC
 #include <limits.h> //For PATH_MAX
 #endif
 
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index dda007d..e3dd229 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -63,13 +63,13 @@
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
-namespace google {
-namespace protobuf {
-namespace compiler {
 
 // Disable the whole test when we use tcmalloc for "draconian" heap checks, in
 // which case tcmalloc will print warnings that fail the plugin tests.
 #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+namespace google {
+namespace protobuf {
+namespace compiler {
 
 #if defined(_WIN32)
 #ifndef STDIN_FILENO
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index 5ee6f00..415ae60 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -69,11 +69,12 @@
 
 EnumGenerator::~EnumGenerator() {}
 
-void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) {
+void EnumGenerator::FillForwardDeclaration(
+    map<string, const EnumDescriptor*>* enum_names) {
   if (!options_.proto_h) {
     return;
   }
-  enum_names->insert(classname_);
+  (*enum_names)[classname_] = descriptor_;
 }
 
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {
@@ -83,6 +84,7 @@
   vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : "");
 
   printer->Print(vars, "enum $enumbase$ {\n");
+  printer->Annotate("enumbase", descriptor_);
   printer->Indent();
 
   const EnumValueDescriptor* min_value = descriptor_->value(0);
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h
index f3aa72e..61e4034 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.h
@@ -64,8 +64,10 @@
   // Fills the name to use when declaring the enum. This is for use when
   // generating other .proto.h files. This code should be placed within the
   // enum's package namespace, but NOT within any class, even for nested
-  // enums.
-  void FillForwardDeclaration(set<string>* enum_names);
+  // enums. A given key in enum_names will map from an enum class name to the
+  // EnumDescriptor that was responsible for its inclusion in the map. This can
+  // be used to associate the descriptor with the code generated for it.
+  void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names);
 
   // Generate header code defining the enum.  This code should be placed
   // within the enum's package namespace, but NOT within any class, even for
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index 37e4bae..d48171b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -94,7 +94,8 @@
 
 FileGenerator::~FileGenerator() {}
 
-void FileGenerator::GenerateProtoHeader(io::Printer* printer) {
+void FileGenerator::GenerateProtoHeader(io::Printer* printer,
+                                        const string& info_path) {
   if (!options_.proto_h) {
     return;
   }
@@ -114,6 +115,8 @@
       "dependency", dependency);
   }
 
+  GenerateMetadataPragma(printer, info_path);
+
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
 
@@ -167,7 +170,8 @@
   GenerateBottomHeaderGuard(printer, filename_identifier);
 }
 
-void FileGenerator::GeneratePBHeader(io::Printer* printer) {
+void FileGenerator::GeneratePBHeader(io::Printer* printer,
+                                     const string& info_path) {
   string filename_identifier =
       FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : ""));
   GenerateTopHeaderGuard(printer, filename_identifier);
@@ -179,6 +183,7 @@
     GenerateLibraryIncludes(printer);
   }
   GenerateDependencyIncludes(printer);
+  GenerateMetadataPragma(printer, info_path);
 
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
@@ -237,7 +242,7 @@
 }
 
 void FileGenerator::GenerateSource(io::Printer* printer) {
-  bool well_known = IsWellKnownMessage(file_);
+  const bool use_system_include = IsWellKnownMessage(file_);
   string header =
       StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
   printer->Print(
@@ -258,8 +263,8 @@
     "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "filename", file_->name(),
     "header", header,
-    "left", well_known ? "<" : "\"",
-    "right", well_known ? ">" : "\"");
+    "left", use_system_include ? "<" : "\"",
+    "right", use_system_include ? ">" : "\"");
 
   // Unknown fields implementation in lite mode uses StringOutputStream
   if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -401,20 +406,24 @@
     return ns;
   }
 
-  set<string>& classes() { return classes_; }
-  set<string>& enums() { return enums_; }
+  map<string, const Descriptor*>& classes() { return classes_; }
+  map<string, const EnumDescriptor*>& enums() { return enums_; }
 
   void Print(io::Printer* printer) const {
-    for (set<string>::const_iterator it = enums_.begin(), end = enums_.end();
+    for (map<string, const EnumDescriptor *>::const_iterator
+             it = enums_.begin(),
+             end = enums_.end();
          it != end; ++it) {
-      printer->Print("enum $enumname$ : int;\n"
-                     "bool $enumname$_IsValid(int value);\n",
-                     "enumname", it->c_str());
+      printer->Print("enum $enumname$ : int;\n", "enumname", it->first);
+      printer->Annotate("enumname", it->second);
+      printer->Print("bool $enumname$_IsValid(int value);\n", "enumname",
+                     it->first);
     }
-    for (set<string>::const_iterator it = classes_.begin(),
-                                     end = classes_.end();
+    for (map<string, const Descriptor *>::const_iterator it = classes_.begin(),
+                                                         end = classes_.end();
          it != end; ++it) {
-      printer->Print("class $classname$;\n", "classname", it->c_str());
+      printer->Print("class $classname$;\n", "classname", it->first);
+      printer->Annotate("classname", it->second);
     }
     for (map<string, ForwardDeclarations *>::const_iterator
              it = namespaces_.begin(),
@@ -431,8 +440,8 @@
 
  private:
   map<string, ForwardDeclarations*> namespaces_;
-  set<string> classes_;
-  set<string> enums_;
+  map<string, const Descriptor*> classes_;
+  map<string, const EnumDescriptor*> enums_;
 };
 
 void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
@@ -854,6 +863,19 @@
   }
 }
 
+void FileGenerator::GenerateMetadataPragma(io::Printer* printer,
+                                           const string& info_path) {
+  if (!info_path.empty() && !options_.annotation_pragma_name.empty() &&
+      !options_.annotation_guard_name.empty()) {
+    printer->Print(
+        "#ifdef $guard$\n"
+        "#pragma $pragma$ \"$info_path$\"\n"
+        "#endif  // $guard$\n",
+        "guard", options_.annotation_guard_name, "pragma",
+        options_.annotation_pragma_name, "info_path", info_path);
+  }
+}
+
 void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
   set<string> public_import_names;
   for (int i = 0; i < file_->public_dependency_count(); i++) {
@@ -861,16 +883,17 @@
   }
 
   for (int i = 0; i < file_->dependency_count(); i++) {
-    bool well_known = IsWellKnownMessage(file_->dependency(i));
+    const bool use_system_include = IsWellKnownMessage(file_->dependency(i));
     const string& name = file_->dependency(i)->name();
     bool public_import = (public_import_names.count(name) != 0);
 
+
     printer->Print(
       "#include $left$$dependency$.pb.h$right$$iwyu$\n",
       "dependency", StripProto(name),
       "iwyu", (public_import) ? "  // IWYU pragma: export" : "",
-      "left", well_known ? "<" : "\"",
-      "right", well_known ? ">" : "\"");
+      "left", use_system_include ? "<" : "\"",
+      "right", use_system_include ? ">" : "\"");
   }
 }
 
@@ -897,13 +920,15 @@
 }
 
 void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
-  set<string> classes;
+  map<string, const Descriptor*> classes;
   for (int i = 0; i < file_->message_type_count(); i++) {
     message_generators_[i]->FillMessageForwardDeclarations(&classes);
   }
-  for (set<string>::const_iterator it = classes.begin(), end = classes.end();
+  for (map<string, const Descriptor *>::const_iterator it = classes.begin(),
+                                                       end = classes.end();
        it != end; ++it) {
-    printer->Print("class $classname$;\n", "classname", it->c_str());
+    printer->Print("class $classname$;\n", "classname", it->first);
+    printer->Annotate("classname", it->second);
   }
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 29cdaea..ebe990c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -69,8 +69,14 @@
                          const Options& options);
   ~FileGenerator();
 
-  void GenerateProtoHeader(io::Printer* printer);
-  void GeneratePBHeader(io::Printer* printer);
+  // info_path, if non-empty, should be the path (relative to printer's output)
+  // to the metadata file describing this proto header.
+  void GenerateProtoHeader(io::Printer* printer,
+                           const string& info_path);
+  // info_path, if non-empty, should be the path (relative to printer's output)
+  // to the metadata file describing this PB header.
+  void GeneratePBHeader(io::Printer* printer,
+                        const string& info_path);
   void GenerateSource(io::Printer* printer);
 
  private:
@@ -102,6 +108,10 @@
   void GenerateLibraryIncludes(io::Printer* printer);
   void GenerateDependencyIncludes(io::Printer* printer);
 
+  // Generate a pragma to pull in metadata using the given info_path (if
+  // non-empty). info_path should be relative to printer's output.
+  void GenerateMetadataPragma(io::Printer* printer, const string& info_path);
+
   // Generates a couple of different pieces before definitions:
   void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 781526b..c7aec93 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -90,6 +90,12 @@
       file_options.dllexport_decl = options[i].second;
     } else if (options[i].first == "safe_boundary_check") {
       file_options.safe_boundary_check = true;
+    } else if (options[i].first == "annotate_headers") {
+      file_options.annotate_headers = true;
+    } else if (options[i].first == "annotation_pragma_name") {
+      file_options.annotation_pragma_name = options[i].second;
+    } else if (options[i].first == "annotation_guard_name") {
+      file_options.annotation_guard_name = options[i].second;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
@@ -107,16 +113,40 @@
   if (file_options.proto_h) {
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".proto.h"));
-    io::Printer printer(output.get(), '$');
-    file_generator.GenerateProtoHeader(&printer);
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    string info_path = basename + ".proto.h.meta";
+    io::Printer printer(output.get(), '$', file_options.annotate_headers
+                                               ? &annotation_collector
+                                               : NULL);
+    file_generator.GenerateProtoHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
   }
 
   basename.append(".pb");
   {
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".h"));
-    io::Printer printer(output.get(), '$');
-    file_generator.GeneratePBHeader(&printer);
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    string info_path = basename + ".h.meta";
+    io::Printer printer(output.get(), '$', file_options.annotate_headers
+                                               ? &annotation_collector
+                                               : NULL);
+    file_generator.GeneratePBHeader(
+        &printer, file_options.annotate_headers ? info_path : "");
+    if (file_options.annotate_headers) {
+      scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          generator_context->Open(info_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
   }
 
   // Generate cc file.
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 8304ebb..c316661 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -423,8 +423,8 @@
 MessageGenerator::~MessageGenerator() {}
 
 void MessageGenerator::
-FillMessageForwardDeclarations(set<string>* class_names) {
-  class_names->insert(classname_);
+FillMessageForwardDeclarations(map<string, const Descriptor*>* class_names) {
+  (*class_names)[classname_] = descriptor_;
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // map entry message doesn't need forward declaration. Since map entry
@@ -436,7 +436,7 @@
 }
 
 void MessageGenerator::
-FillEnumForwardDeclarations(set<string>* enum_names) {
+FillEnumForwardDeclarations(map<string, const EnumDescriptor*>* enum_names) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     nested_generators_[i]->FillEnumForwardDeclarations(enum_names);
   }
@@ -892,6 +892,7 @@
   }
   printer->Print(vars,
     "class $dllexport$$classname$ : public $superclass$ {\n");
+  printer->Annotate("classname", descriptor_);
   if (use_dependent_base_) {
     printer->Print(vars, "  friend class $superclass$;\n");
   }
@@ -1027,6 +1028,8 @@
       "// implements Any -----------------------------------------------\n"
       "\n"
       "void PackFrom(const ::google::protobuf::Message& message);\n"
+      "void PackFrom(const ::google::protobuf::Message& message,\n"
+      "              const ::std::string& type_url_prefix);\n"
       "bool UnpackTo(::google::protobuf::Message* message) const;\n"
       "template<typename T> bool Is() const {\n"
       "  return _any_metadata_.Is<T>();\n"
@@ -1789,6 +1792,11 @@
       "  _any_metadata_.PackFrom(message);\n"
       "}\n"
       "\n"
+      "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n"
+      "                           const ::std::string& type_url_prefix) {\n"
+      "  _any_metadata_.PackFrom(message, type_url_prefix);\n"
+      "}\n"
+      "\n"
       "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n"
       "  return _any_metadata_.UnpackTo(message);\n"
       "}\n"
@@ -1899,11 +1907,10 @@
 
 void MessageGenerator::
 GenerateOffsets(io::Printer* printer) {
-  printer->Print(
-    "static const int $classname$_offsets_[$field_count$] = {\n",
-    "classname", classname_,
-    "field_count", SimpleItoa(max(
-        1, descriptor_->field_count() + descriptor_->oneof_decl_count())));
+  printer->Print("static const int $classname$_offsets_[$field_count$] = {\n",
+                 "classname", classname_, "field_count",
+                 SimpleItoa(std::max(1, descriptor_->field_count() +
+                                            descriptor_->oneof_decl_count())));
   printer->Indent();
 
   for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -2907,7 +2914,7 @@
     // on the CodedOutputStream.
     printer->Print(
       "  ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n"
-      "      ::google::protobuf::internal::NewPermanentCallback(\n"
+      "      google::protobuf::internal::NewPermanentCallback(\n"
       "          &MutableUnknownFieldsFor$classname$, this));\n"
       "  ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n"
       "      &unknown_fields_string, false);\n",
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 8e19a3f..31223e1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -67,9 +67,13 @@
   // Header stuff.
 
   // Return names for foward declarations of this class and all its nested
-  // types.
-  void FillMessageForwardDeclarations(set<string>* class_names);
-  void FillEnumForwardDeclarations(set<string>* enum_names);
+  // types. A given key in {class,enum}_names will map from a class name to the
+  // descriptor that was responsible for its inclusion in the map. This can be
+  // used to associate the descriptor with the code generated for it.
+  void FillMessageForwardDeclarations(
+      map<string, const Descriptor*>* class_names);
+  void FillEnumForwardDeclarations(
+      map<string, const EnumDescriptor*>* enum_names);
 
   // Generate definitions of all nested enums (must come before class
   // definitions because those classes use the enums definitions).
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index 4463f20..e908362 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -43,11 +43,14 @@
 
 // Generator options (see generator.cc for a description of each):
 struct Options {
-  Options() : safe_boundary_check(false), proto_h(false) {
-  }
+  Options()
+      : safe_boundary_check(false), proto_h(false), annotate_headers(false) {}
   string dllexport_decl;
   bool safe_boundary_check;
   bool proto_h;
+  bool annotate_headers;
+  string annotation_pragma_name;
+  string annotation_guard_name;
 };
 
 }  // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 9942a34..148da88 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -82,7 +82,6 @@
 
 namespace google {
 namespace protobuf {
-using internal::NewPermanentCallback;
 namespace compiler {
 namespace cpp {
 
@@ -1253,7 +1252,7 @@
       foo_(descriptor_->FindMethodByName("Foo")),
       bar_(descriptor_->FindMethodByName("Bar")),
       stub_(&mock_channel_),
-      done_(NewPermanentCallback(&DoNothing)) {}
+      done_(google::protobuf::internal::NewPermanentCallback(&DoNothing)) {}
 
   virtual void SetUp() {
     ASSERT_TRUE(foo_ != NULL);
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index 422eb73..61dc283 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -51,6 +51,189 @@
 namespace cpp {
 namespace {
 
+// A CodeGenerator that captures the FileDescriptor it's passed as a
+// FileDescriptorProto.
+class DescriptorCapturingGenerator : public CodeGenerator {
+ public:
+  // Does not own file; file must outlive the Generator.
+  explicit DescriptorCapturingGenerator(FileDescriptorProto* file)
+      : file_(file) {}
+
+  virtual bool Generate(const FileDescriptor* file, const string& parameter,
+                        GeneratorContext* context, string* error) const {
+    file->CopyTo(file_);
+    return true;
+  }
+
+ private:
+  FileDescriptorProto* file_;
+};
+
+class CppMetadataTest : public ::testing::Test {
+ public:
+  // Adds a file with name `filename` and content `data`.
+  void AddFile(const string& filename, const string& data) {
+    GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data,
+                               true));
+  }
+
+  // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output
+  // code from the previously added file with name `filename`. Returns true on
+  // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to
+  // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info.
+  bool CaptureMetadata(const string& filename, FileDescriptorProto* file,
+                       string* pb_h, GeneratedCodeInfo* pb_h_info,
+                       string* proto_h, GeneratedCodeInfo* proto_h_info,
+                       string* pb_cc) {
+    google::protobuf::compiler::CommandLineInterface cli;
+    cli.SetInputsAreProtoPathRelative(true);
+
+    CppGenerator cpp_generator;
+    DescriptorCapturingGenerator capturing_generator(file);
+    cli.RegisterGenerator("--cpp_out", &cpp_generator, "");
+    cli.RegisterGenerator("--capture_out", &capturing_generator, "");
+
+    string proto_path = "-I" + TestTempDir();
+    string cpp_out =
+        "--cpp_out=annotate_headers=true,"
+        "annotation_pragma_name=pragma_name,"
+        "annotation_guard_name=guard_name:" +
+        TestTempDir();
+    string capture_out = "--capture_out=" + TestTempDir();
+
+    const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(),
+                          capture_out.c_str(), filename.c_str()};
+
+    if (cli.Run(5, argv) != 0) {
+      return false;
+    }
+
+    string output_base = TestTempDir() + "/" + StripProto(filename);
+
+    if (pb_cc != NULL) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.cc", pb_cc, true));
+    }
+
+    if (pb_h != NULL && pb_h_info != NULL) {
+      GOOGLE_CHECK_OK(
+          File::GetContents(output_base + ".pb.h", pb_h, true));
+      if (!DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) {
+        return false;
+      }
+    }
+
+    if (proto_h != NULL && proto_h_info != NULL) {
+      GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h,
+                                 true));
+      if (!DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+ private:
+  // Decodes GeneratedCodeInfo stored in path and copies it to info.
+  // Returns true on success.
+  bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) {
+    string data;
+    GOOGLE_CHECK_OK(File::GetContents(path, &data, true));
+    io::ArrayInputStream input(data.data(), data.size());
+    return info->ParseFromZeroCopyStream(&input);
+  }
+};
+
+const char kSmallTestFile[] =
+    "syntax = \"proto2\";\n"
+    "package foo;\n"
+    "enum Enum { VALUE = 0; }\n"
+    "message Message { }\n";
+
+// Finds the Annotation for a given source file and path (or returns null if it
+// couldn't).
+const GeneratedCodeInfo::Annotation* FindAnnotationOnPath(
+    const GeneratedCodeInfo& info, const string& source_file,
+    const vector<int>& path) {
+  for (int i = 0; i < info.annotation_size(); ++i) {
+    const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i);
+    if (annotation->source_file() != source_file ||
+        annotation->path_size() != path.size()) {
+      continue;
+    }
+    int node = 0;
+    for (; node < path.size(); ++node) {
+      if (annotation->path(node) != path[node]) {
+        break;
+      }
+    }
+    if (node == path.size()) {
+      return annotation;
+    }
+  }
+  return NULL;
+}
+
+// Returns true if the provided annotation covers a given substring in
+// file_content.
+bool AnnotationMatchesSubstring(const string& file_content,
+                                const GeneratedCodeInfo::Annotation* annotation,
+                                const string& expected_text) {
+  uint32 begin = annotation->begin();
+  uint32 end = annotation->end();
+  if (end < begin || end > file_content.size()) {
+    return false;
+  }
+  return file_content.substr(begin, end - begin) == expected_text;
+}
+
+TEST_F(CppMetadataTest, CapturesEnumNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_EQ("Enum", file.enum_type(0).name());
+  vector<int> enum_path;
+  enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber);
+  enum_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* enum_annotation =
+      FindAnnotationOnPath(info, "test.proto", enum_path);
+  EXPECT_TRUE(NULL != enum_annotation);
+  EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum"));
+}
+
+TEST_F(CppMetadataTest, AddsPragma) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos);
+  EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") !=
+              string::npos);
+}
+
+TEST_F(CppMetadataTest, CapturesMessageNames) {
+  FileDescriptorProto file;
+  GeneratedCodeInfo info;
+  string pb_h;
+  AddFile("test.proto", kSmallTestFile);
+  EXPECT_TRUE(
+      CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL));
+  EXPECT_EQ("Message", file.message_type(0).name());
+  vector<int> message_path;
+  message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+  message_path.push_back(0);
+  const GeneratedCodeInfo::Annotation* message_annotation =
+      FindAnnotationOnPath(info, "test.proto", message_path);
+  EXPECT_TRUE(NULL != message_annotation);
+  EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, message_annotation, "Message"));
+}
+
 }  // namespace
 }  // namespace cpp
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index 7d21fe6..0a11288 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -43,7 +43,7 @@
 namespace java {
 
 Context::Context(const FileDescriptor* file)
-    : name_resolver_(new ClassNameResolver) {
+    : name_resolver_(new ClassNameResolver), enforce_lite_(false) {
   InitializeFieldGeneratorInfo(file);
 }
 
@@ -189,6 +189,13 @@
   return result;
 }
 
+// Does this message class have generated parsing, serialization, and other
+// standard methods for which reflection-based fallback implementations exist?
+bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
+  return enforce_lite_ || descriptor->file()->options().optimize_for() !=
+           FileOptions::CODE_SIZE;
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
index 5b595d0..a480e45 100644
--- a/src/google/protobuf/compiler/java/java_context.h
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -46,6 +46,7 @@
   class FieldDescriptor;
   class OneofDescriptor;
   class Descriptor;
+  class EnumDescriptor;
   namespace compiler {
     namespace java {
       class ClassNameResolver;  // name_resolver.h
@@ -78,6 +79,20 @@
   const OneofGeneratorInfo* GetOneofGeneratorInfo(
       const OneofDescriptor* oneof) const;
 
+  // Enforces all the files (including transitive dependencies) to use
+  // LiteRuntime.
+  void SetEnforceLite(bool enforce_lite) {
+    enforce_lite_ = enforce_lite;
+  }
+
+  bool EnforceLite() const {
+    return enforce_lite_;
+  }
+
+  // Does this message class have generated parsing, serialization, and other
+  // standard methods for which reflection-based fallback implementations exist?
+  bool HasGeneratedMethods(const Descriptor* descriptor) const;
+
  private:
   void InitializeFieldGeneratorInfo(const FileDescriptor* file);
   void InitializeFieldGeneratorInfoForMessage(const Descriptor* message);
@@ -87,6 +102,7 @@
   google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
   map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
   map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
+  bool enforce_lite_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
 };
 
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 5fc9b00..9eea873 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -64,6 +64,7 @@
                              bool immutable_api,
                              Context* context)
   : descriptor_(descriptor), immutable_api_(immutable_api),
+    context_(context),
     name_resolver_(context->GetNameResolver())  {
   for (int i = 0; i < descriptor_->value_count(); i++) {
     const EnumValueDescriptor* value = descriptor_->value(i);
@@ -150,7 +151,15 @@
     "  return value;\n"
     "}\n"
     "\n"
+    "/**\n"
+    " * @deprecated Use {@link #forNumber(int)} instead.\n"
+    " */\n"
+    "@java.lang.Deprecated\n"
     "public static $classname$ valueOf(int value) {\n"
+    "  return forNumber(value);\n"
+    "}\n"
+    "\n"
+    "public static $classname$ forNumber(int value) {\n"
     "  switch (value) {\n",
     "classname", descriptor_->name());
   printer->Indent();
@@ -178,7 +187,7 @@
     "    $classname$> internalValueMap =\n"
     "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
     "        public $classname$ findValueByNumber(int number) {\n"
-    "          return $classname$.valueOf(number);\n"
+    "          return $classname$.forNumber(number);\n"
     "        }\n"
     "      };\n"
     "\n",
@@ -187,7 +196,7 @@
   // -----------------------------------------------------------------
   // Reflection
 
-  if (HasDescriptorMethods(descriptor_)) {
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
     printer->Print(
       "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
       "    getValueDescriptor() {\n"
@@ -229,7 +238,7 @@
             "      (com.google.protobuf.Descriptors.FileDescriptor)\n"
             "          m.invoke(immutableFileClass);\n"
             "  return file.getEnumTypes().get($index$);\n"
-            "} catch (Exception e) {\n"
+            "} catch (java.lang.Exception e) {\n"
             // Immutable classes cannot be found. Proceed as if custom options
             // don't exist.
             "}\n",
@@ -313,7 +322,7 @@
     "private final int value;\n\n"
     "private $classname$(int index, int value) {\n",
     "classname", descriptor_->name());
-  if (HasDescriptorMethods(descriptor_)) {
+  if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) {
     printer->Print("  this.index = index;\n");
   }
   printer->Print(
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 558da96..3e54be3 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -68,21 +68,14 @@
   (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
   (*variables)["default_number"] = SimpleItoa(
       descriptor->default_value_enum()->number());
-  if (descriptor->is_packed()) {
-    (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag(
-        descriptor->number(),
-        internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
-  } else {
-    (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
-  }
+  (*variables)["tag"] = 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();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -198,7 +191,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  $type$ result = $type$.valueOf($name$_);\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
     "  return result == null ? $unknown$ : result;\n"
     "}\n");
 }
@@ -231,7 +224,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  $type$ result = $type$.valueOf($name$_);\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
     "  return result == null ? $unknown$ : result;\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
@@ -311,7 +304,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -405,7 +398,7 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    $type$ result =  $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
     "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
@@ -443,7 +436,7 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    $type$ result =  $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
     "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
@@ -500,7 +493,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -613,7 +606,7 @@
     "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
     "            java.lang.Integer, $type$>() {\n"
     "          public $type$ convert(java.lang.Integer from) {\n"
-    "            $type$ result = $type$.valueOf(from);\n"
+    "            $type$ result = $type$.forNumber(from);\n"
     "            return result == null ? $unknown$ : result;\n"
     "          }\n"
     "        };\n");
@@ -649,7 +642,7 @@
   }
 
   if (descriptor_->is_packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
   }
@@ -846,7 +839,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
         "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index e3e87c5..5b98637 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -75,8 +75,6 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -179,7 +177,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  $type$ result = $type$.valueOf($name$_);\n"
+    "  $type$ result = $type$.forNumber($name$_);\n"
     "  return result == null ? $unknown$ : result;\n"
     "}\n");
 
@@ -228,7 +226,7 @@
     printer->Print(variables_,
       "$deprecation$public Builder set$capitalized_name$Value(int value) {\n"
       "  copyOnWrite();\n"
-      "  instance.set$capitalized_name$Value(int value);\n"
+      "  instance.set$capitalized_name$Value(value);\n"
       "  return this;\n"
       "}\n");
   }
@@ -295,7 +293,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -389,7 +387,7 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    $type$ result =  $type$.valueOf((java.lang.Integer) $oneof_name$_);\n"
+    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
     "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
@@ -488,7 +486,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -602,7 +600,7 @@
     "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
     "            java.lang.Integer, $type$>() {\n"
     "          public $type$ convert(java.lang.Integer from) {\n"
-    "            $type$ result = $type$.valueOf(from);\n"
+    "            $type$ result = $type$.forNumber(from);\n"
     "            return result == null ? $unknown$ : result;\n"
     "          }\n"
     "        };\n");
@@ -638,7 +636,7 @@
   }
 
   if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize;\n");
   }
@@ -821,7 +819,6 @@
     "    ensure$capitalized_name$IsMutable();\n"
     "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  $on_changed$\n"
     "}\n");
 }
 
@@ -844,7 +841,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.valueOf(rawValue);\n"
+      "$type$ value = $type$.forNumber(rawValue);\n"
         "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index ed415ee..c22da8d 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -141,7 +141,15 @@
     "  return value;\n"
     "}\n"
     "\n"
+    "/**\n"
+    " * @deprecated Use {@link #forNumber(int)} instead.\n"
+    " */\n"
+    "@java.lang.Deprecated\n"
     "public static $classname$ valueOf(int value) {\n"
+    "  return forNumber(value);\n"
+    "}\n"
+    "\n"
+    "public static $classname$ forNumber(int value) {\n"
     "  switch (value) {\n",
     "classname", descriptor_->name());
   printer->Indent();
@@ -169,7 +177,7 @@
     "    $classname$> internalValueMap =\n"
     "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
     "        public $classname$ findValueByNumber(int number) {\n"
-    "          return $classname$.valueOf(number);\n"
+    "          return $classname$.forNumber(number);\n"
     "        }\n"
     "      };\n"
     "\n",
diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc
index 4db7085..46b5faa 100644
--- a/src/google/protobuf/compiler/java/java_extension.cc
+++ b/src/google/protobuf/compiler/java/java_extension.cc
@@ -118,75 +118,38 @@
       "public static final int $constant_name$ = $number$;\n");
 
   WriteFieldDocComment(printer, descriptor_);
-  if (HasDescriptorMethods(descriptor_->file())) {
-    // 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 {
-      // 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");
-    }
+  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 {
-    // 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"
-          "      $singular_type$.class);\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"
-          "      $singular_type$.class);\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");
   }
 }
 
 int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode(
     io::Printer* printer) {
   int bytecode_estimate = 0;
-  if (descriptor_->extension_scope() == NULL &&
-      HasDescriptorMethods(descriptor_->file())) {
-    // Only applies to non-nested, non-lite extensions.
+  if (descriptor_->extension_scope() == NULL) {
+    // Only applies to non-nested extensions.
     printer->Print(
         "$name$.internalInit(descriptor.getExtensions().get($index$));\n",
         "name", UnderscoresToCamelCase(descriptor_),
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc
index e69de29..23261ba 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.cc
+++ b/src/google/protobuf/compiler/java/java_extension_lite.cc
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/java/java_extension_lite.h>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator(
+    const FieldDescriptor* descriptor, Context* context)
+  : descriptor_(descriptor), context_(context),
+    name_resolver_(context->GetNameResolver()) {
+  if (descriptor_->extension_scope() != NULL) {
+    scope_ = name_resolver_->GetImmutableClassName(
+        descriptor_->extension_scope());
+  } else {
+    scope_ = name_resolver_->GetImmutableClassName(descriptor_->file());
+  }
+}
+
+ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {}
+
+void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) {
+  map<string, string> vars;
+  const bool kUseImmutableNames = true;
+  InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_,
+                   &vars);
+  printer->Print(vars,
+      "public static final int $constant_name$ = $number$;\n");
+
+  WriteFieldDocComment(printer, descriptor_);
+  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"
+        "      $singular_type$.class);\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"
+        "      $singular_type$.class);\n");
+  }
+}
+
+int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode(
+    io::Printer* printer) {
+  return 0;
+}
+
+int ImmutableExtensionLiteGenerator::GenerateRegistrationCode(
+    io::Printer* printer) {
+  printer->Print(
+    "registry.add($scope$.$name$);\n",
+    "scope", scope_,
+    "name", UnderscoresToCamelCase(descriptor_));
+  return 7;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h
index e69de29..4cd49bd 100644
--- a/src/google/protobuf/compiler/java/java_extension_lite.h
+++ b/src/google/protobuf/compiler/java/java_extension_lite.h
@@ -0,0 +1,76 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_extension.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generates code for a lite extension, which may be within the scope of some
+// message or may be at file scope.  This is much simpler than FieldGenerator
+// since extensions are just simple identifiers with interesting types.
+class ImmutableExtensionLiteGenerator : public ExtensionGenerator {
+ public:
+  explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor,
+                                           Context* context);
+  virtual ~ImmutableExtensionLiteGenerator();
+
+  virtual void Generate(io::Printer* printer);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateNonNestedInitializationCode(io::Printer* printer);
+
+  // Returns an estimate of the number of bytes the printed code will compile to
+  virtual int GenerateRegistrationCode(io::Printer* printer);
+
+ private:
+  const FieldDescriptor* descriptor_;
+  Context* context_;
+  ClassNameResolver* name_resolver_;
+  string scope_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator);
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index c543476..3c7bc5c 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -77,7 +77,7 @@
           return new ImmutableMapFieldGenerator(
               field, messageBitIndex, builderBitIndex, context);
         } else {
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new RepeatedImmutableLazyMessageFieldGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -99,7 +99,7 @@
     if (field->containing_oneof()) {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageOneofFieldGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -119,7 +119,7 @@
     } else {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageFieldGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -150,7 +150,7 @@
           return new ImmutableMapFieldLiteGenerator(
               field, messageBitIndex, builderBitIndex, context);
         } else {
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new RepeatedImmutableLazyMessageFieldLiteGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -172,7 +172,7 @@
     if (field->containing_oneof()) {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageOneofFieldLiteGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
@@ -192,7 +192,7 @@
     } else {
       switch (GetJavaType(field)) {
         case JAVATYPE_MESSAGE:
-          if (IsLazy(field)) {
+          if (IsLazy(field, context->EnforceLite())) {
             return new ImmutableLazyMessageFieldLiteGenerator(
                 field, messageBitIndex, builderBitIndex, context);
           } else {
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index c817233..c53aae6 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -177,7 +177,7 @@
   // since otherwise we hit a hardcoded limit in the jvm and javac will
   // then fail with the error "code too large". This limit lets our
   // estimates be off by a factor of two and still we're okay.
-  static const int bytesPerMethod = 1<<15;  // aka 32K
+  static const int bytesPerMethod = kMaxStaticSize;
 
   if ((*bytecode_estimate) > bytesPerMethod) {
     ++(*method_num);
@@ -193,7 +193,8 @@
 
 }  // namespace
 
-FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api)
+FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api,
+                             bool enforce_lite)
     : file_(file),
       java_package_(FileJavaPackage(file, immutable_api)),
       message_generators_(
@@ -204,6 +205,7 @@
       name_resolver_(context_->GetNameResolver()),
       immutable_api_(immutable_api) {
   classname_ = name_resolver_->GetFileClassName(file, immutable_api);
+  context_->SetEnforceLite(enforce_lite);
   generator_factory_.reset(
       new ImmutableGeneratorFactory(context_.get()));
   for (int i = 0; i < file_->message_type_count(); ++i) {
@@ -262,7 +264,8 @@
   printer->Print(
     "public static void registerAllExtensions(\n"
     "    com.google.protobuf.ExtensionRegistry$lite$ registry) {\n",
-    "lite", HasDescriptorMethods(file_) ? "" : "Lite");
+    "lite",
+    HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite");
 
   printer->Indent();
 
@@ -282,7 +285,7 @@
 
   if (!MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      if (HasDescriptorMethods(file_)) {
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
         EnumGenerator(file_->enum_type(i), immutable_api_, context_.get())
             .Generate(printer);
       } else {
@@ -294,7 +297,7 @@
       message_generators_[i]->GenerateInterface(printer);
       message_generators_[i]->Generate(printer);
     }
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, context_->EnforceLite())) {
       for (int i = 0; i < file_->service_count(); i++) {
         google::protobuf::scoped_ptr<ServiceGenerator> generator(
             generator_factory_->NewServiceGenerator(file_->service(i)));
@@ -309,14 +312,18 @@
     extension_generators_[i]->Generate(printer);
   }
 
-  // Static variables.
+  // Static variables. We'd like them to be final if possible, but due to
+  // the JVM's 64k size limit on static blocks, we have to initialize some
+  // of them in methods; thus they cannot be final.
+  int static_block_bytecode_estimate = 0;
   for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateStaticVariables(printer);
+    message_generators_[i]->GenerateStaticVariables(
+        printer, &static_block_bytecode_estimate);
   }
 
   printer->Print("\n");
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, context_->EnforceLite())) {
     if (immutable_api_) {
       GenerateDescriptorInitializationCodeForImmutable(printer);
     } else {
@@ -358,9 +365,11 @@
     "    getDescriptor() {\n"
     "  return descriptor;\n"
     "}\n"
-    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+    "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n"
     "    descriptor;\n"
-    "static {\n");
+    "static {\n",
+    // TODO(dweis): Mark this as final.
+    "final", "");
   printer->Indent();
 
   SharedCodeGenerator shared_code_generator(file_);
@@ -453,7 +462,7 @@
     "    getDescriptor() {\n"
     "  return descriptor;\n"
     "}\n"
-    "private static com.google.protobuf.Descriptors.FileDescriptor\n"
+    "private static final com.google.protobuf.Descriptors.FileDescriptor\n"
     "    descriptor;\n"
     "static {\n");
   printer->Indent();
@@ -549,7 +558,7 @@
                                      vector<string>* file_list) {
   if (MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
-      if (HasDescriptorMethods(file_)) {
+      if (HasDescriptorMethods(file_, context_->EnforceLite())) {
         EnumGenerator generator(file_->enum_type(i), immutable_api_,
                                 context_.get());
         GenerateSibling<EnumGenerator>(package_dir, java_package_,
@@ -582,7 +591,7 @@
                                         message_generators_[i].get(),
                                         &MessageGenerator::Generate);
     }
-    if (HasGenericServices(file_)) {
+    if (HasGenericServices(file_, context_->EnforceLite())) {
       for (int i = 0; i < file_->service_count(); i++) {
         google::protobuf::scoped_ptr<ServiceGenerator> generator(
             generator_factory_->NewServiceGenerator(file_->service(i)));
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 080b342..7dbeb94 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -67,7 +67,8 @@
 
 class FileGenerator {
  public:
-  FileGenerator(const FileDescriptor* file, bool immutable_api = true);
+  FileGenerator(const FileDescriptor* file, bool immutable_api = true,
+                bool enforce_lite = false);
   ~FileGenerator();
 
   // Checks for problems that would otherwise lead to cryptic compile errors.
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index 6c6f728..a46c7fc 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -75,6 +75,7 @@
   bool generate_immutable_code = false;
   bool generate_mutable_code = false;
   bool generate_shared_code = false;
+  bool enforce_lite = false;
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "output_list_file") {
       output_list_file = options[i].second;
@@ -84,12 +85,21 @@
       generate_mutable_code = true;
     } else if (options[i].first == "shared") {
       generate_shared_code = true;
+    } else if (options[i].first == "lite") {
+      // When set, the protoc will generate the current files and all the
+      // transitive dependencies as lite runtime.
+      enforce_lite = true;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
     }
   }
 
+  if (enforce_lite && generate_mutable_code) {
+    *error = "lite runtime generator option cannot be used with mutable API.";
+    return false;
+  }
+
   // By default we generate immutable code and shared code for immutable API.
   if (!generate_immutable_code && !generate_mutable_code &&
       !generate_shared_code) {
@@ -105,10 +115,12 @@
 
   vector<FileGenerator*> file_generators;
   if (generate_immutable_code) {
-    file_generators.push_back(new FileGenerator(file, /* immutable = */ true));
+    file_generators.push_back(
+        new FileGenerator(file, /* immutable = */ true, enforce_lite));
   }
   if (generate_mutable_code) {
-    file_generators.push_back(new FileGenerator(file, /* mutable = */ false));
+    file_generators.push_back(
+        new FileGenerator(file, /* mutable = */ false, enforce_lite));
   }
   for (int i = 0; i < file_generators.size(); ++i) {
     if (!file_generators[i]->Validate(error)) {
diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc
index 92ef851..3218b41 100644
--- a/src/google/protobuf/compiler/java/java_generator_factory.cc
+++ b/src/google/protobuf/compiler/java/java_generator_factory.cc
@@ -35,6 +35,7 @@
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
 #include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
 #include <google/protobuf/compiler/java/java_field.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_message.h>
@@ -58,17 +59,20 @@
 
 MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator(
     const Descriptor* descriptor) const {
-  if (descriptor->file()->options().optimize_for() ==
-      FileOptions::LITE_RUNTIME) {
-    return new ImmutableMessageLiteGenerator(descriptor, context_);
-  } else {
+  if (HasDescriptorMethods(descriptor, context_->EnforceLite())) {
     return new ImmutableMessageGenerator(descriptor, context_);
+  } else {
+    return new ImmutableMessageLiteGenerator(descriptor, context_);
   }
 }
 
 ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator(
     const FieldDescriptor* descriptor) const {
-  return new ImmutableExtensionGenerator(descriptor, context_);
+  if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) {
+    return new ImmutableExtensionGenerator(descriptor, context_);
+  } else {
+    return new ImmutableExtensionLiteGenerator(descriptor, context_);
+  }
 }
 
 ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator(
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 5392d6d..c850423 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -170,44 +170,41 @@
 }
 bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
 
-// Does this message class have generated parsing, serialization, and other
-// standard methods for which reflection-based fallback implementations exist?
-inline bool HasGeneratedMethods(const Descriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           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() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const Descriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->file()->options().optimize_for() !=
+             FileOptions::LITE_RUNTIME;
 }
-inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) {
-  return descriptor->file()->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const EnumDescriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->file()->options().optimize_for() !=
+             FileOptions::LITE_RUNTIME;
 }
-inline bool HasDescriptorMethods(const FileDescriptor* descriptor) {
-  return descriptor->options().optimize_for() !=
-           FileOptions::LITE_RUNTIME;
+inline bool HasDescriptorMethods(const FileDescriptor* descriptor,
+                                 bool enforce_lite) {
+  return !enforce_lite &&
+         descriptor->options().optimize_for() != FileOptions::LITE_RUNTIME;
 }
 
 // Should we generate generic services for this file?
-inline bool HasGenericServices(const FileDescriptor *file) {
+inline bool HasGenericServices(const FileDescriptor *file, bool enforce_lite) {
   return file->service_count() > 0 &&
-         file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
+         HasDescriptorMethods(file, enforce_lite) &&
          file->options().java_generic_services();
 }
 
-inline bool IsLazy(const FieldDescriptor* descriptor) {
+inline bool IsLazy(const FieldDescriptor* descriptor, bool enforce_lite) {
   // Currently, the proto-lite version suports lazy field.
   // TODO(niwasaki): Support lazy fields also for other proto runtimes.
-  if (descriptor->file()->options().optimize_for() !=
-      FileOptions::LITE_RUNTIME) {
+  if (HasDescriptorMethods(descriptor->file(), enforce_lite)) {
     return false;
   }
   return descriptor->options().lazy();
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
index 283ba1d..a648f1c 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -193,7 +193,7 @@
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$_.setByteString(input.readBytes(), extensionRegistry);\n");
+    "$name$_.mergeFrom(input, extensionRegistry);\n");
   printer->Print(variables_,
     "$set_has_field_bit_message$;\n");
 }
@@ -378,8 +378,7 @@
     "if (!($has_oneof_case_message$)) {\n"
     "  $oneof_name$_ = new $lazy_type$();\n"
     "}\n"
-    "(($lazy_type$) $oneof_name$_).setByteString(\n"
-    "    input.readBytes(), extensionRegistry);\n"
+    "(($lazy_type$) $oneof_name$_).mergeFrom(input, extensionRegistry);\n"
     "$set_oneof_case_message$;\n");
 }
 
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 3e035c8..17c3646 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -79,9 +79,10 @@
                          int messageBitIndex,
                          int builderBitIndex,
                          const FieldGeneratorInfo* info,
-                         ClassNameResolver* name_resolver,
+                         Context* context,
                          map<string, string>* variables) {
   SetCommonFieldVariables(descriptor, info, variables);
+  ClassNameResolver* name_resolver = context->GetNameResolver();
 
   (*variables)["type"] =
       name_resolver->GetImmutableClassName(descriptor->message_type());
@@ -123,8 +124,7 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   // For repeated fields, one bit is used for whether the array is immutable
   // in the parsing constructor.
@@ -135,18 +135,12 @@
 
   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
       "DefaultEntryHolder.defaultEntry";
-  if (HasDescriptorMethods(descriptor->file())) {
-    (*variables)["lite"] = "";
-    (*variables)["map_field_parameter"] = (*variables)["default_entry"];
-    (*variables)["descriptor"] =
-        name_resolver->GetImmutableClassName(descriptor->file()) +
-        ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
-        "_descriptor, ";
-  } else {
-    (*variables)["lite"] = "Lite";
-    (*variables)["map_field_parameter"] = "";
-    (*variables)["descriptor"] = "";
-  }
+  (*variables)["lite"] = "";
+  (*variables)["map_field_parameter"] = (*variables)["default_entry"];
+  (*variables)["descriptor"] =
+      name_resolver->GetImmutableClassName(descriptor->file()) +
+      ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
+      "_descriptor, ";
 }
 
 }  // namespace
@@ -159,7 +153,7 @@
   : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
   SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
                       context->GetFieldGeneratorInfo(descriptor),
-                      name_resolver_, &variables_);
+                      context, &variables_);
 }
 
 ImmutableMapFieldGenerator::
@@ -424,7 +418,7 @@
         "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
     printer->Print(
         variables_,
-        "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+        "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
         "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
         "} else {\n"
         "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index d203940..6bdebb0 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -79,10 +79,11 @@
                          int messageBitIndex,
                          int builderBitIndex,
                          const FieldGeneratorInfo* info,
-                         ClassNameResolver* name_resolver,
+                         Context* context,
                          map<string, string>* variables) {
   SetCommonFieldVariables(descriptor, info, variables);
 
+  ClassNameResolver* name_resolver = context->GetNameResolver();
   (*variables)["type"] =
       name_resolver->GetImmutableClassName(descriptor->message_type());
   const FieldDescriptor* key = KeyField(descriptor);
@@ -123,8 +124,6 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
 
   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
       "DefaultEntryHolder.defaultEntry";
@@ -142,7 +141,7 @@
   : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
   SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
                       context->GetFieldGeneratorInfo(descriptor),
-                      name_resolver_, &variables_);
+                      context, &variables_);
 }
 
 ImmutableMapFieldLiteGenerator::
@@ -404,7 +403,7 @@
         "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
     printer->Print(
         variables_,
-        "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
+        "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
         "  super.mergeLengthDelimitedField($number$, bytes);\n"
         "} else {\n"
         "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 22a70c3..dfd8ad0 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -95,13 +95,15 @@
   : MessageGenerator(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
-  GOOGLE_CHECK_NE(
-      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
 }
 
 ImmutableMessageGenerator::~ImmutableMessageGenerator() {}
 
-void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+void ImmutableMessageGenerator::GenerateStaticVariables(
+    io::Printer* printer, int* bytecode_estimate) {
   // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is
   // used in the construction of descriptors, we have a tricky bootstrapping
   // problem.  To help control static initialization order, we make sure all
@@ -124,23 +126,29 @@
   } else {
     vars["private"] = "private ";
   }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
 
   // The descriptor for this type.
   printer->Print(vars,
     // TODO(teboring): final needs to be added back. The way to fix it is to
     // generate methods that can construct the types, and then still declare the
     // types, and then init them in clinit with the new method calls.
-    "$private$static com.google.protobuf.Descriptors.Descriptor\n"
+    "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n"
     "  internal_$identifier$_descriptor;\n");
+  *bytecode_estimate += 30;
 
   // And the FieldAccessorTable.
-  GenerateFieldAccessorTable(printer);
+  GenerateFieldAccessorTable(printer, bytecode_estimate);
 
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
     ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
-      .GenerateStaticVariables(printer);
+        .GenerateStaticVariables(printer, bytecode_estimate);
   }
 }
 
@@ -183,7 +191,7 @@
 }
 
 void ImmutableMessageGenerator::
-GenerateFieldAccessorTable(io::Printer* printer) {
+GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate) {
   map<string, string> vars;
   vars["identifier"] = UniqueFileScopeIdentifier(descriptor_);
   if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) {
@@ -193,10 +201,19 @@
   } else {
     vars["private"] = "private ";
   }
+  if (*bytecode_estimate <= kMaxStaticSize) {
+    vars["final"] = "final ";
+  } else {
+    vars["final"] = "";
+  }
   printer->Print(vars,
-    "$private$static\n"
+    "$private$static $final$\n"
     "  com.google.protobuf.GeneratedMessage.FieldAccessorTable\n"
     "    internal_$identifier$_fieldAccessorTable;\n");
+
+  // 6 bytes per field and oneof
+  *bytecode_estimate += 10 + 6 * descriptor_->field_count()
+      + 6 * descriptor_->oneof_decl_count();
 }
 
 int ImmutableMessageGenerator::
@@ -342,7 +359,7 @@
   printer->Print(
     "}\n");
 
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     GenerateParsingConstructor(printer);
   }
 
@@ -408,12 +425,20 @@
       "cap_oneof_name",
       ToUpper(vars["oneof_name"]));
     printer->Print(vars,
-      "private int value = 0;\n"
+      "private final int value;\n"
       "private $oneof_capitalized_name$Case(int value) {\n"
       "  this.value = value;\n"
       "}\n");
     printer->Print(vars,
+      "/**\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
       "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
       "  switch (value) {\n");
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -426,8 +451,7 @@
     }
     printer->Print(
       "    case 0: return $cap_oneof_name$_NOT_SET;\n"
-      "    default: throw new java.lang.IllegalArgumentException(\n"
-      "      \"Value is undefined for this oneof enum.\");\n"
+      "    default: return null;\n"
       "  }\n"
       "}\n"
       "public int getNumber() {\n"
@@ -440,7 +464,7 @@
     printer->Print(vars,
       "public $oneof_capitalized_name$Case\n"
       "get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
       "      $oneof_name$Case_);\n"
       "}\n"
       "\n");
@@ -459,7 +483,7 @@
     printer->Print("\n");
   }
 
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
   }
@@ -664,34 +688,40 @@
     "}\n"
     "public static $classname$ parseFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseDelimitedWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);"
+    "  return com.google.protobuf.GeneratedMessage\n"
+    "      .parseWithIOException(PARSER, input, extensionRegistry);\n"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -1049,22 +1079,52 @@
 
   printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n");
 
+  // hashCode non-oneofs.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
-    if (check_has_bits) {
-      printer->Print(
-        "if (has$name$()) {\n",
-        "name", info->capitalized_name);
-      printer->Indent();
-    }
-    field_generators_.get(field).GenerateHashCode(printer);
-    if (check_has_bits) {
-      printer->Outdent();
-      printer->Print("}\n");
+    if (field->containing_oneof() == NULL) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+          "if (has$name$()) {\n",
+          "name", info->capitalized_name);
+        printer->Indent();
+      }
+      field_generators_.get(field).GenerateHashCode(printer);
+      if (check_has_bits) {
+        printer->Outdent();
+        printer->Print("}\n");
+      }
     }
   }
+
+  // hashCode oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "switch ($oneof_name$Case_) {\n",
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_number$:\n",
+        "field_number",
+        SimpleItoa(field->number()));
+      printer->Indent();
+      field_generators_.get(field).GenerateHashCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Print(
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
       "hash = hashFields(hash, getExtensionFields());\n");
@@ -1105,7 +1165,8 @@
   printer->Print(
       "private $classname$(\n"
       "    com.google.protobuf.CodedInputStream input,\n"
-      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n",
+      "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
+      "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
       "classname", descriptor_->name());
   printer->Indent();
 
@@ -1215,10 +1276,10 @@
   printer->Outdent();
   printer->Print(
       "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n"
-      "  throw new RuntimeException(e.setUnfinishedMessage(this));\n"
+      "  throw e.setUnfinishedMessage(this);\n"
       "} catch (java.io.IOException e) {\n"
-      "  throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n"
-      "      .setUnfinishedMessage(this));\n"
+      "  throw new com.google.protobuf.InvalidProtocolBufferException(\n"
+      "      e).setUnfinishedMessage(this);\n"
       "} finally {\n");
   printer->Indent();
 
@@ -1260,20 +1321,9 @@
       "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
       "    throws com.google.protobuf.InvalidProtocolBufferException {\n",
       "classname", descriptor_->name());
-  if (HasGeneratedMethods(descriptor_)) {
-    // The parsing constructor throws an InvalidProtocolBufferException via a
-    // RuntimeException to aid in method pruning. We unwrap it here.
+  if (context_->HasGeneratedMethods(descriptor_)) {
     printer->Print(
-        "  try {\n"
-        "    return new $classname$(input, extensionRegistry);\n"
-        "  } catch (RuntimeException e) {\n"
-        "    if (e.getCause() instanceof\n"
-        "        com.google.protobuf.InvalidProtocolBufferException) {\n"
-        "      throw (com.google.protobuf.InvalidProtocolBufferException)\n"
-        "          e.getCause();\n"
-        "    }\n"
-        "    throw e;\n"
-        "  }\n",
+        "    return new $classname$(input, extensionRegistry);\n",
         "classname", descriptor_->name());
   } else {
     // When parsing constructor isn't generated, use builder to parse
@@ -1328,14 +1378,39 @@
 void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
   printer->Print(
     "private static String getTypeUrl(\n"
+    "    java.lang.String typeUrlPrefix,\n"
     "    com.google.protobuf.Descriptors.Descriptor descriptor) {\n"
-    "  return \"type.googleapis.com/\" + descriptor.getFullName();\n"
+    "  return typeUrlPrefix.endsWith(\"/\")\n"
+    "      ? typeUrlPrefix + descriptor.getFullName()\n"
+    "      : typeUrlPrefix + \"/\" + descriptor.getFullName();\n"
+    "}\n"
+    "\n"
+    "private static String getTypeNameFromTypeUrl(\n"
+    "    java.lang.String typeUrl) {\n"
+    "  int pos = typeUrl.lastIndexOf('/');\n"
+    "  return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n"
     "}\n"
     "\n"
     "public static <T extends com.google.protobuf.Message> Any pack(\n"
     "    T message) {\n"
     "  return Any.newBuilder()\n"
-    "      .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n"
+    "      .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n"
+    "                             message.getDescriptorForType()))\n"
+    "      .setValue(message.toByteString())\n"
+    "      .build();\n"
+    "}\n"
+    "\n"
+    "/**\n"
+    " * Packs a message uisng the given type URL prefix. The type URL will\n"
+    " * be constructed by concatenating the message type's full name to the\n"
+    " * prefix with an optional \"/\" separator if the prefix doesn't end\n"
+    " * with \"/\" already.\n"
+    " */\n"
+    "public static <T extends com.google.protobuf.Message> Any pack(\n"
+    "    T message, java.lang.String typeUrlPrefix) {\n"
+    "  return Any.newBuilder()\n"
+    "      .setTypeUrl(getTypeUrl(typeUrlPrefix,\n"
+    "                             message.getDescriptorForType()))\n"
     "      .setValue(message.toByteString())\n"
     "      .build();\n"
     "}\n"
@@ -1344,8 +1419,8 @@
     "    java.lang.Class<T> clazz) {\n"
     "  T defaultInstance =\n"
     "      com.google.protobuf.Internal.getDefaultInstance(clazz);\n"
-    "  return getTypeUrl().equals(\n"
-    "      getTypeUrl(defaultInstance.getDescriptorForType()));\n"
+    "  return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n"
+    "      defaultInstance.getDescriptorForType().getFullName());\n"
     "}\n"
     "\n"
     "private volatile com.google.protobuf.Message cachedUnpackValue;\n"
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index be5bfb0..e9fc57c 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -56,6 +56,8 @@
 namespace compiler {
 namespace java {
 
+static const int kMaxStaticSize = 1 << 15;  // aka 32k
+
 class MessageGenerator {
  public:
   explicit MessageGenerator(const Descriptor* descriptor);
@@ -64,7 +66,8 @@
   // All static variables have to be declared at the top-level of the file
   // so that we can control initialization order, which is important for
   // DescriptorProto bootstrapping to work.
-  virtual void GenerateStaticVariables(io::Printer* printer) = 0;
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate) = 0;
 
   // Output code which initializes the static variables generated by
   // GenerateStaticVariables(). Returns an estimate of bytecode size.
@@ -96,14 +99,15 @@
   virtual void Generate(io::Printer* printer);
   virtual void GenerateInterface(io::Printer* printer);
   virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
-  virtual void GenerateStaticVariables(io::Printer* printer);
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate);
 
   // Returns an estimate of the number of bytes the printed code will compile to
   virtual int GenerateStaticVariableInitializers(io::Printer* printer);
 
  private:
 
-  void GenerateFieldAccessorTable(io::Printer* printer);
+  void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
 
   // Returns an estimate of the number of bytes the printed code will compile to
   int GenerateFieldAccessorTableInitializer(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc
index 5d53503..b3e9e98 100644
--- a/src/google/protobuf/compiler/java/java_message_builder.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder.cc
@@ -81,8 +81,9 @@
   : descriptor_(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
-  GOOGLE_CHECK_NE(
-      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+  GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A non-lite message generator is used to "
+         "generate lite messages.";
 }
 
 MessageBuilderGenerator::~MessageBuilderGenerator() {}
@@ -113,7 +114,7 @@
   GenerateDescriptorMethods(printer);
   GenerateCommonBuilderMethods(printer);
 
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     GenerateIsInitialized(printer);
     GenerateBuilderParsingMethods(printer);
   }
@@ -134,7 +135,7 @@
     printer->Print(vars,
       "public $oneof_capitalized_name$Case\n"
       "    get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
       "      $oneof_name$Case_);\n"
       "}\n"
       "\n"
@@ -439,7 +440,7 @@
 
   // -----------------------------------------------------------------
 
-  if (HasGeneratedMethods(descriptor_)) {
+  if (context_->HasGeneratedMethods(descriptor_)) {
     printer->Print(
       "public Builder mergeFrom(com.google.protobuf.Message other) {\n"
       "  if (other instanceof $classname$) {\n"
diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
index 8719d00..dd429dc 100644
--- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc
@@ -81,8 +81,9 @@
   : descriptor_(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
-  GOOGLE_CHECK_EQ(
-      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
 }
 
 MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {}
@@ -148,20 +149,6 @@
                      .GenerateBuilderMembers(printer);
   }
 
-  if (!PreserveUnknownFields(descriptor_)) {
-    printer->Print(
-      "public final Builder setUnknownFields(\n"
-      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
-      "  return this;\n"
-      "}\n"
-      "\n"
-      "public final Builder mergeUnknownFields(\n"
-      "    final com.google.protobuf.UnknownFieldSet unknownFields) {\n"
-      "  return this;\n"
-      "}\n"
-      "\n");
-  }
-
   printer->Print(
     "\n"
     "// @@protoc_insertion_point(builder_scope:$full_name$)\n",
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index b5f8e62..455516f 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -70,8 +70,7 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
index 356520e..049679d 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -70,8 +70,6 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -867,7 +865,6 @@
     "    ensure$capitalized_name$IsMutable();\n"
     "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  $on_changed$\n"
     "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 94ed2c3..14cc908 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -46,7 +46,7 @@
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_enum_lite.h>
-#include <google/protobuf/compiler/java/java_extension.h>
+#include <google/protobuf/compiler/java/java_extension_lite.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
 #include <google/protobuf/compiler/java/java_message_builder.h>
@@ -87,19 +87,20 @@
   : MessageGenerator(descriptor), context_(context),
     name_resolver_(context->GetNameResolver()),
     field_generators_(descriptor, context_) {
-  GOOGLE_CHECK_EQ(
-      FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for());
+  GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite()))
+      << "Generator factory error: A lite message generator is used to "
+         "generate non-lite messages.";
 }
 
 ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {}
 
 void ImmutableMessageLiteGenerator::GenerateStaticVariables(
-    io::Printer* printer) {
+    io::Printer* printer, int* bytecode_estimate) {
   // Generate static members for all nested types.
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // TODO(kenton):  Reuse MessageGenerator objects?
     ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
-      .GenerateStaticVariables(printer);
+        .GenerateStaticVariables(printer, bytecode_estimate);
   }
 }
 
@@ -197,6 +198,7 @@
   }
   printer->Indent();
 
+
   GenerateParsingConstructor(printer);
 
   // Nested types
@@ -259,12 +261,20 @@
       "cap_oneof_name",
       ToUpper(vars["oneof_name"]));
     printer->Print(vars,
-      "private int value = 0;\n"
+      "private final int value;\n"
       "private $oneof_capitalized_name$Case(int value) {\n"
       "  this.value = value;\n"
       "}\n");
     printer->Print(vars,
+      "/**\n"
+      " * @deprecated Use {@link #forNumber(int)} instead.\n"
+      " */\n"
+      "@java.lang.Deprecated\n"
       "public static $oneof_capitalized_name$Case valueOf(int value) {\n"
+      "  return forNumber(value);\n"
+      "}\n"
+      "\n"
+      "public static $oneof_capitalized_name$Case forNumber(int value) {\n"
       "  switch (value) {\n");
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
@@ -277,8 +287,7 @@
     }
     printer->Print(
       "    case 0: return $cap_oneof_name$_NOT_SET;\n"
-      "    default: throw new java.lang.IllegalArgumentException(\n"
-      "      \"Value is undefined for this oneof enum.\");\n"
+      "    default: return null;\n"
       "  }\n"
       "}\n"
       "public int getNumber() {\n"
@@ -291,7 +300,7 @@
     printer->Print(vars,
       "public $oneof_capitalized_name$Case\n"
       "get$oneof_capitalized_name$Case() {\n"
-      "  return $oneof_capitalized_name$Case.valueOf(\n"
+      "  return $oneof_capitalized_name$Case.forNumber(\n"
       "      $oneof_name$Case_);\n"
       "}\n"
       "\n"
@@ -317,7 +326,6 @@
     GenerateEqualsAndHashCode(printer);
   }
 
-
   GenerateParseFromMethods(printer);
   GenerateBuilder(printer);
 
@@ -446,7 +454,7 @@
   // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve
   // the outer class's FileDescriptor.
   for (int i = 0; i < descriptor_->extension_count(); i++) {
-    ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
         .Generate(printer);
   }
 
@@ -557,9 +565,6 @@
     "  return size;\n"
     "}\n"
     "\n");
-
-  printer->Print(
-    "private static final long serialVersionUID = 0L;\n");
 }
 
 void ImmutableMessageLiteGenerator::
@@ -571,54 +576,62 @@
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.ByteString data)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
-    "  return parser().parseFrom(data);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.ByteString data,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
-    "  return parser().parseFrom(data, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(byte[] data)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
-    "  return parser().parseFrom(data);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    byte[] data,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws com.google.protobuf.InvalidProtocolBufferException {\n"
-    "  return parser().parseFrom(data, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, data, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseDelimitedFrom(input);\n"
+    "  return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n"
     "}\n"
     "public static $classname$ parseDelimitedFrom(\n"
     "    java.io.InputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseDelimitedFrom(input, extensionRegistry);\n"
+    "  return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseFrom(input);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input);\n"
     "}\n"
     "public static $classname$ parseFrom(\n"
     "    com.google.protobuf.CodedInputStream input,\n"
     "    com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n"
     "    throws java.io.IOException {\n"
-    "  return parser().parseFrom(input, extensionRegistry);\n"
+    "  return com.google.protobuf.GeneratedMessageLite.parseFrom(\n"
+    "      DEFAULT_INSTANCE, input, extensionRegistry);\n"
     "}\n"
     "\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
@@ -906,24 +919,61 @@
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
   printer->Print("boolean result = true;\n");
+  // Compare non-oneofs.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
-    if (check_has_bits) {
-      printer->Print(
-        "result = result && (has$name$() == other.has$name$());\n"
-        "if (has$name$()) {\n",
-        "name", info->capitalized_name);
-      printer->Indent();
-    }
-    field_generators_.get(field).GenerateEqualsCode(printer);
-    if (check_has_bits) {
-      printer->Outdent();
-      printer->Print(
-        "}\n");
+    if (field->containing_oneof() == NULL) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+          "result = result && (has$name$() == other.has$name$());\n"
+          "if (has$name$()) {\n",
+          "name", info->capitalized_name);
+        printer->Indent();
+      }
+      field_generators_.get(field).GenerateEqualsCode(printer);
+      if (check_has_bits) {
+        printer->Outdent();
+        printer->Print(
+          "}\n");
+      }
     }
   }
+
+  // Compare oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "result = result && get$oneof_capitalized_name$Case().equals(\n"
+      "    other.get$oneof_capitalized_name$Case());\n",
+      "oneof_capitalized_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->capitalized_name);
+    printer->Print(
+      "if (!result) return false;\n"
+      "switch ($oneof_name$Case_) {\n",
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
+      printer->Print(
+        "case $field_number$:\n",
+        "field_number",
+        SimpleItoa(field->number()));
+      printer->Indent();
+      field_generators_.get(field).GenerateEqualsCode(printer);
+      printer->Print("break;\n");
+      printer->Outdent();
+    }
+    printer->Print(
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
+  }
+
   if (PreserveUnknownFields(descriptor_)) {
     // Always consider unknown fields for equality. This will sometimes return
     // false for non-canonical ordering when running in LITE_RUNTIME but it's
@@ -957,21 +1007,50 @@
   printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n",
     "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
+  // hashCode non-oneofs.
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(i);
-    const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
-    bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
-    if (check_has_bits) {
+    if (field->containing_oneof() == NULL) {
+      const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
+      bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
+      if (check_has_bits) {
+        printer->Print(
+          "if (has$name$()) {\n",
+          "name", info->capitalized_name);
+        printer->Indent();
+      }
+      field_generators_.get(field).GenerateHashCode(printer);
+      if (check_has_bits) {
+        printer->Outdent();
+        printer->Print("}\n");
+      }
+    }
+  }
+
+  // hashCode oneofs.
+  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
+    printer->Print(
+      "switch ($oneof_name$Case_) {\n",
+      "oneof_name",
+      context_->GetOneofGeneratorInfo(
+          descriptor_->oneof_decl(i))->name);
+    printer->Indent();
+    for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
+      const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
       printer->Print(
-        "if (has$name$()) {\n",
-        "name", info->capitalized_name);
+        "case $field_number$:\n",
+        "field_number",
+        SimpleItoa(field->number()));
       printer->Indent();
-    }
-    field_generators_.get(field).GenerateHashCode(printer);
-    if (check_has_bits) {
+      field_generators_.get(field).GenerateHashCode(printer);
+      printer->Print("break;\n");
       printer->Outdent();
-      printer->Print("}\n");
     }
+    printer->Print(
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
   }
 
   printer->Print(
@@ -990,7 +1069,7 @@
 void ImmutableMessageLiteGenerator::
 GenerateExtensionRegistrationCode(io::Printer* printer) {
   for (int i = 0; i < descriptor_->extension_count(); i++) {
-    ImmutableExtensionGenerator(descriptor_->extension(i), context_)
+    ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_)
       .GenerateRegistrationCode(printer);
   }
 
@@ -1167,7 +1246,6 @@
   }
 }
 
-
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 2bd3cdd..c8ee99b 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -54,7 +54,8 @@
   virtual void Generate(io::Printer* printer);
   virtual void GenerateInterface(io::Printer* printer);
   virtual void GenerateExtensionRegistrationCode(io::Printer* printer);
-  virtual void GenerateStaticVariables(io::Printer* printer);
+  virtual void GenerateStaticVariables(
+      io::Printer* printer, int* bytecode_estimate);
   virtual int GenerateStaticVariableInitializers(io::Printer* printer);
 
  private:
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index 0c363f9..bffe4f1 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -259,6 +259,13 @@
       descriptor->file(), true);
 }
 
+string ClassNameResolver::GetJavaImmutableClassName(
+    const EnumDescriptor* descriptor) {
+  return GetJavaClassFullName(
+      ClassNameWithoutPackage(descriptor, true),
+      descriptor->file(), true);
+}
+
 
 }  // namespace java
 }  // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index ab60b0a..570d8d8 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -98,6 +98,7 @@
   // For example:
   //   com.package.OuterClass$OuterMessage$InnerMessage
   string GetJavaImmutableClassName(const Descriptor* descriptor);
+  string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
  private:
   // Get the full name of a Java class by prepending the Java package name
   // or outer class name.
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 178bbe1..e42ec28 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -75,12 +75,7 @@
       "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
   (*variables)["capitalized_type"] =
       GetCapitalizedType(descriptor, /* immutable = */ true);
-  if (descriptor->is_packed()) {
-    (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag(
-        descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
-  } else {
-    (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
-  }
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
   if (IsReferenceType(GetJavaType(descriptor))) {
@@ -99,8 +94,7 @@
   if (fixed_size != -1) {
     (*variables)["fixed_size"] = SimpleItoa(fixed_size);
   }
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -606,7 +600,7 @@
     "}\n");
 
   if (descriptor_->is_packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
   }
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 5a7bf82..d277e4f 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -129,8 +129,6 @@
   if (fixed_size != -1) {
     (*variables)["fixed_size"] = SimpleItoa(fixed_size);
   }
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -635,7 +633,7 @@
     "}\n");
 
   if (descriptor_->options().packed() &&
-      HasGeneratedMethods(descriptor_->containing_type())) {
+      context_->HasGeneratedMethods(descriptor_->containing_type())) {
     printer->Print(variables_,
       "private int $name$MemoizedSerializedSize = -1;\n");
   }
@@ -758,7 +756,6 @@
     "    ensure$capitalized_name$IsMutable();\n"
     "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  $on_changed$\n"
     "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 7017736..74253c3 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -52,8 +52,9 @@
 namespace java {
 
 SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
-  : name_resolver_(new ClassNameResolver), file_(file) {
-}
+    : name_resolver_(new ClassNameResolver),
+      enforce_lite_(false),
+      file_(file) {}
 
 SharedCodeGenerator::~SharedCodeGenerator() {
 }
@@ -63,7 +64,7 @@
   string java_package = FileJavaPackage(file_);
   string package_dir = JavaPackageToDir(java_package);
 
-  if (HasDescriptorMethods(file_)) {
+  if (HasDescriptorMethods(file_, enforce_lite_)) {
     // Generate descriptors.
     string classname = name_resolver_->GetDescriptorClassName(file_);
     string filename = package_dir + classname + ".java";
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
index 38a32fc..3b573c0 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.h
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -72,6 +72,10 @@
   void Generate(GeneratorContext* generator_context,
                 vector<string>* file_list);
 
+  void SetEnforceLite(bool value) {
+    enforce_lite_ = value;
+  }
+
   void GenerateDescriptors(io::Printer* printer);
 
  private:
@@ -81,6 +85,7 @@
   bool ShouldIncludeDependency(const FileDescriptor* descriptor);
 
   google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
+  bool enforce_lite_;
   const FileDescriptor* file_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
 };
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 7f757e4..b67eeb5 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -87,8 +87,7 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
+  (*variables)["on_changed"] = "onChanged();";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -408,15 +407,6 @@
       "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_has_field_bit_message$\n"
       "$name$_ = s;\n");
-  } else if (!HasDescriptorMethods(descriptor_->file())) {
-    // Lite runtime should attempt to reduce allocations by attempting to
-    // construct the string directly from the input stream buffer. This avoids
-    // spurious intermediary ByteString allocations, cutting overall allocations
-    // in half.
-    printer->Print(variables_,
-      "java.lang.String s = input.readString();\n"
-      "$set_has_field_bit_message$\n"
-      "$name$_ = s;\n");
   } else {
     printer->Print(variables_,
       "com.google.protobuf.ByteString bs = input.readBytes();\n"
@@ -668,15 +658,6 @@
       "java.lang.String s = input.readStringRequireUtf8();\n"
       "$set_oneof_case_message$;\n"
       "$oneof_name$_ = s;\n");
-  } else if (!HasDescriptorMethods(descriptor_->file())) {
-    // Lite runtime should attempt to reduce allocations by attempting to
-    // construct the string directly from the input stream buffer. This avoids
-    // spurious intermediary ByteString allocations, cutting overall allocations
-    // in half.
-    printer->Print(variables_,
-      "java.lang.String s = input.readString();\n"
-      "$set_oneof_case_message$;\n"
-      "$oneof_name$_ = s;\n");
   } else {
     printer->Print(variables_,
       "com.google.protobuf.ByteString bs = input.readBytes();\n"
@@ -934,13 +915,6 @@
   if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
     "java.lang.String s = input.readStringRequireUtf8();\n");
-  } else if (!HasDescriptorMethods(descriptor_->file())) {
-    // Lite runtime should attempt to reduce allocations by attempting to
-    // construct the string directly from the input stream buffer. This avoids
-    // spurious intermediary ByteString allocations, cutting overall allocations
-    // in half.
-    printer->Print(variables_,
-    "java.lang.String s = input.readString();\n");
   } else {
     printer->Print(variables_,
     "com.google.protobuf.ByteString bs = input.readBytes();\n");
@@ -950,7 +924,7 @@
     "  $name$_ = new com.google.protobuf.LazyStringArrayList();\n"
     "  $set_mutable_bit_parser$;\n"
     "}\n");
-  if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
+  if (CheckUtf8(descriptor_)) {
     printer->Print(variables_,
       "$name$_.add(s);\n");
   } else {
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index eb5964b..9012ab5 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -84,8 +84,6 @@
   // by the proto compiler
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
-  (*variables)["on_changed"] =
-      HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : "";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -103,7 +101,7 @@
     (*variables)["clear_has_field_bit_message"] = "";
 
     (*variables)["is_field_present_message"] =
-        "!get" + (*variables)["capitalized_name"] + ".isEmpty()";
+        "!" + (*variables)["name"] + "_.isEmpty()";
   }
 
   // For repeated builders, the underlying list tracks mutability state.
@@ -309,13 +307,11 @@
       "if (other.has$capitalized_name$()) {\n"
       "  $set_has_field_bit_message$\n"
       "  $name$_ = other.$name$_;\n"
-      "  $on_changed$\n"
       "}\n");
   } else {
     printer->Print(variables_,
       "if (!other.get$capitalized_name$().isEmpty()) {\n"
       "  $name$_ = other.$name$_;\n"
-      "  $on_changed$\n"
       "}\n");
   }
 }
@@ -528,8 +524,7 @@
   // all string fields to Strings when copying fields from a Message.
   printer->Print(variables_,
     "$set_oneof_case_message$;\n"
-    "$oneof_name$_ = other.$oneof_name$_;\n"
-    "$on_changed$\n");
+    "$oneof_name$_ = other.$oneof_name$_;\n");
 }
 
 void ImmutableStringOneofFieldLiteGenerator::
@@ -792,7 +787,6 @@
     "    ensure$capitalized_name$IsMutable();\n"
     "    $name$_.addAll(other.$name$_);\n"
     "  }\n"
-    "  $on_changed$\n"
     "}\n");
 }
 
@@ -819,13 +813,8 @@
     "if (!$is_mutable$) {\n"
     "  $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n"
     "}\n");
-  if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) {
-    printer->Print(variables_,
-      "$name$_.add(s);\n");
-  } else {
-    printer->Print(variables_,
-      "$name$_.add(bs);\n");
-  }
+  printer->Print(variables_,
+    "$name$_.add(s);\n");
 }
 
 void RepeatedImmutableStringFieldLiteGenerator::
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index a33eba1..a342e6b 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -68,12 +68,7 @@
   }
   if (file->options().has_java_package()) {
     string result = file->options().java_package();
-    if (!file->options().javanano_use_deprecated_package()) {
-      if (!result.empty()) {
-        result += ".";
-      }
-      result += "nano";
-    }
+    result += "nano";
     params.set_java_package(
       file->name(), result);
   }
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index 5465655..02811a2 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -201,12 +201,10 @@
       result += file->package();
     }
 
-    if (!file->options().javanano_use_deprecated_package()) {
-      if (!result.empty()) {
-        result += ".";
-      }
-      result += "nano";
+    if (!result.empty()) {
+      result += ".";
     }
+    result += "nano";
 
     return result;
   }
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 0de7e2c..534a5b5 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <google/protobuf/compiler/js/js_generator.h>
+#include "google/protobuf/compiler/js/js_generator.h"
 
 #include <assert.h>
 #include <algorithm>
@@ -123,6 +123,16 @@
 
 namespace {
 
+// The mode of operation for bytes fields. Historically JSPB always carried
+// bytes as JS {string}, containing base64 content by convention. With binary
+// and proto3 serialization the new convention is to represent it as binary
+// data in Uint8Array. See b/26173701 for background on the migration.
+enum BytesMode {
+  BYTES_DEFAULT,  // Default type for getBytesField to return.
+  BYTES_B64,      // Explicitly coerce to base64 string where needed.
+  BYTES_U8,       // Explicitly coerce to Uint8Array where needed.
+};
+
 bool IsReserved(const string& ident) {
   for (int i = 0; i < kNumKeyword; i++) {
     if (ident == kKeyword[i]) {
@@ -134,7 +144,7 @@
 
 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto
 // suffix stripped.
-// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc.
+// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc.
 string StripProto(const string& filename) {
   const char* suffix = HasSuffixString(filename, ".protodevel")
       ? ".protodevel" : ".proto";
@@ -144,9 +154,7 @@
 // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
 // file foo/bar/baz.js.
 string GetJSFilename(const string& filename) {
-  const char* suffix = HasSuffixString(filename, ".protodevel")
-      ? ".protodevel" : ".proto";
-  return StripSuffixString(filename, suffix) + "_pb.js";
+  return StripProto(filename) + "_pb.js";
 }
 
 // Given a filename like foo/bar/baz.proto, returns the root directory
@@ -385,15 +393,47 @@
   return result;
 }
 
+// When we're generating one output file per type name, this is the filename
+// that top-level extensions should go in.
+string GetExtensionFileName(const GeneratorOptions& options,
+                            const FileDescriptor* file) {
+  return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetMessageFileName(const GeneratorOptions& options,
+                          const Descriptor* desc) {
+  return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
+// When we're generating one output file per type name, this is the filename
+// that a top-level message should go in.
+string GetEnumFileName(const GeneratorOptions& options,
+                       const EnumDescriptor* desc) {
+  return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
+}
+
 // Returns the message/response ID, if set.
 string GetMessageId(const Descriptor* desc) {
   return string();
 }
 
+bool IgnoreExtensionField(const FieldDescriptor* field) {
+  // Exclude descriptor extensions from output "to avoid clutter" (from original
+  // codegen).
+  return field->is_extension() &&
+         field->containing_type()->file()->name() ==
+             "google/protobuf/descriptor.proto";
+}
+
 
 // Used inside Google only -- do not remove.
 bool IsResponse(const Descriptor* desc) { return false; }
-bool IgnoreField(const FieldDescriptor* field) { return false; }
+
+bool IgnoreField(const FieldDescriptor* field) {
+  return IgnoreExtensionField(field);
+}
 
 
 // Does JSPB ignore this entire oneof? True only if all fields are ignored.
@@ -438,12 +478,32 @@
   return name;
 }
 
+string JSByteGetterSuffix(BytesMode bytes_mode) {
+  switch (bytes_mode) {
+    case BYTES_DEFAULT:
+      return "";
+    case BYTES_B64:
+      return "B64";
+    case BYTES_U8:
+      return "U8";
+    default:
+      assert(false);
+  }
+}
+
 // Returns the field name as a capitalized portion of a getter/setter method
 // name, e.g. MyField for .getMyField().
-string JSGetterName(const FieldDescriptor* field) {
+string JSGetterName(const FieldDescriptor* field,
+                    BytesMode bytes_mode = BYTES_DEFAULT) {
   string name = JSIdent(field,
                         /* is_upper_camel = */ true,
                         /* is_map = */ false);
+  if (field->type() == FieldDescriptor::TYPE_BYTES) {
+    string suffix = JSByteGetterSuffix(bytes_mode);
+    if (!suffix.empty()) {
+      name += "_as" + suffix;
+    }
+  }
   if (name == "Extension" || name == "JsPbMessageId") {
     // Avoid conflicts with base-class names.
     name += "$";
@@ -504,8 +564,7 @@
   return SimpleItoa(index);
 }
 
-// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only
-// need to handle the BMP (16-bit range) here.
+// Decodes a codepoint in \x0000 -- \xFFFF.
 uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
   if (*length == 0) {
     return 0;
@@ -542,80 +601,56 @@
 }
 
 // Escapes the contents of a string to be included within double-quotes ("") in
-// JavaScript. |is_utf8| determines whether the input data (in a C++ string of
-// chars) is UTF-8 encoded (in which case codepoints become JavaScript string
-// characters, escaped with 16-bit hex escapes where necessary) or raw binary
-// (in which case bytes become JavaScript string characters 0 -- 255).
-string EscapeJSString(const string& in, bool is_utf8) {
-  string result;
+// JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
+// Returns false if |out| was truncated because |in| contained invalid UTF-8 or
+// codepoints outside the BMP.
+// TODO(lukestebbing): Support codepoints outside the BMP.
+bool EscapeJSString(const string& in, string* out) {
   size_t decoded = 0;
   for (size_t i = 0; i < in.size(); i += decoded) {
     uint16 codepoint = 0;
-    if (is_utf8) {
-      // Decode the next UTF-8 codepoint.
-      size_t have_bytes = in.size() - i;
-      uint8 bytes[3] = {
+    // Decode the next UTF-8 codepoint.
+    size_t have_bytes = in.size() - i;
+    uint8 bytes[3] = {
         static_cast<uint8>(in[i]),
         static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
         static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
-      };
-      codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
-      if (have_bytes == 0) {
-        break;
-      }
-      decoded = have_bytes;
-    } else {
-      codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
-      decoded = 1;
+    };
+    codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
+    if (have_bytes == 0) {
+      return false;
     }
-
-    // Next byte -- used for minimal octal escapes below.
-    char next_byte = (i + decoded) < in.size() ?
-        in[i + decoded] : 0;
-    bool pad_octal = (next_byte >= '0' && next_byte <= '7');
+    decoded = have_bytes;
 
     switch (codepoint) {
-      case '\0': result += pad_octal ? "\\000" : "\\0";   break;
-      case '\b': result += "\\\b";  break;
-      case '\t': result += "\\\t";  break;
-      case '\n': result += "\\\n";  break;
-      case '\r': result += "\\\r";  break;
-      case '\f': result += "\\\f";  break;
-      case '\\': result += "\\\\";  break;
-      case '"':  result += pad_octal ? "\\042" : "\\42"; break;
-      case '&':  result += pad_octal ? "\\046" : "\\46"; break;
-      case '\'': result += pad_octal ? "\\047" : "\\47"; break;
-      case '<':  result += pad_octal ? "\\074" : "\\74"; break;
-      case '=':  result += pad_octal ? "\\075" : "\\75"; break;
-      case '>':  result += pad_octal ? "\\076" : "\\76"; break;
+      case '\'': *out += "\\x27"; break;
+      case '"': *out += "\\x22"; break;
+      case '<': *out += "\\x3c"; break;
+      case '=': *out += "\\x3d"; break;
+      case '>': *out += "\\x3e"; break;
+      case '&': *out += "\\x26"; break;
+      case '\b': *out += "\\b"; break;
+      case '\t': *out += "\\t"; break;
+      case '\n': *out += "\\n"; break;
+      case '\f': *out += "\\f"; break;
+      case '\r': *out += "\\r"; break;
+      case '\\': *out += "\\\\"; break;
       default:
-        // All other non-ASCII codepoints are escaped.
-        // Original codegen uses hex for >= 0x100 and octal for others.
+        // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
+        // use a single Unicode codepoint escape if the output language is
+        // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
+        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals
         if (codepoint >= 0x20 && codepoint <= 0x7e) {
-          result += static_cast<char>(codepoint);
+          *out += static_cast<char>(codepoint);
+        } else if (codepoint >= 0x100) {
+          *out += StringPrintf("\\u%04x", codepoint);
         } else {
-          if (codepoint >= 0x100) {
-            result += StringPrintf("\\u%04x", codepoint);
-          } else {
-            if (pad_octal || codepoint >= 0100) {
-              result += "\\";
-              result += ('0' + ((codepoint >> 6) & 07));
-              result += ('0' + ((codepoint >> 3) & 07));
-              result += ('0' + ((codepoint >> 0) & 07));
-            } else if (codepoint >= 010) {
-              result += "\\";
-              result += ('0' + ((codepoint >> 3) & 07));
-              result += ('0' + ((codepoint >> 0) & 07));
-            } else {
-              result += "\\";
-              result += ('0' + ((codepoint >> 0) & 07));
-            }
-          }
+          *out += StringPrintf("\\x%02x", codepoint);
         }
         break;
     }
   }
-  return result;
+  return true;
 }
 
 string EscapeBase64(const string& in) {
@@ -740,11 +775,17 @@
       return DoubleToString(field->default_value_double());
     case FieldDescriptor::CPPTYPE_STRING:
       if (field->type() == FieldDescriptor::TYPE_STRING) {
-        return "\"" + EscapeJSString(field->default_value_string(), true) +
-               "\"";
-      } else {
-        return "\"" + EscapeBase64(field->default_value_string()) +
-               "\"";
+        string out;
+        bool is_valid = EscapeJSString(field->default_value_string(), &out);
+        if (!is_valid) {
+          // TODO(lukestebbing): Decide whether this should be a hard error.
+          GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name()
+                       << " was truncated since it contained invalid UTF-8 or"
+                          " codepoints outside the basic multilingual plane.";
+        }
+        return "\"" + out + "\"";
+      } else {  // Bytes
+        return "\"" + EscapeBase64(field->default_value_string()) + "\"";
       }
     case FieldDescriptor::CPPTYPE_MESSAGE:
       return "null";
@@ -801,8 +842,27 @@
   return "number";
 }
 
+string JSStringTypeName(const GeneratorOptions& options,
+                        const FieldDescriptor* field,
+                        BytesMode bytes_mode) {
+  if (field->type() == FieldDescriptor::TYPE_BYTES) {
+    switch (bytes_mode) {
+      case BYTES_DEFAULT:
+        return "(string|Uint8Array)";
+      case BYTES_B64:
+        return "string";
+      case BYTES_U8:
+        return "Uint8Array";
+      default:
+        assert(false);
+    }
+  }
+  return "string";
+}
+
 string JSTypeName(const GeneratorOptions& options,
-                  const FieldDescriptor* field) {
+                  const FieldDescriptor* field,
+                  BytesMode bytes_mode) {
   switch (field->cpp_type()) {
     case FieldDescriptor::CPPTYPE_BOOL:
       return "boolean";
@@ -819,7 +879,7 @@
     case FieldDescriptor::CPPTYPE_DOUBLE:
       return "number";
     case FieldDescriptor::CPPTYPE_STRING:
-      return "string";
+      return JSStringTypeName(options, field, bytes_mode);
     case FieldDescriptor::CPPTYPE_ENUM:
       return GetPath(options, field->enum_type());
     case FieldDescriptor::CPPTYPE_MESSAGE:
@@ -836,20 +896,26 @@
                              bool force_optional,
                              bool force_present,
                              bool singular_if_not_packed,
-                             bool always_singular) {
+                             BytesMode bytes_mode = BYTES_DEFAULT) {
   bool is_primitive =
       (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
-       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE);
+       field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+        (field->type() != FieldDescriptor::TYPE_BYTES ||
+            bytes_mode == BYTES_B64));
 
-  string jstype = JSTypeName(options, field);
+  string jstype = JSTypeName(options, field, bytes_mode);
 
   if (field->is_repeated() &&
-      !always_singular &&
       (field->is_packed() || !singular_if_not_packed)) {
-    if (!is_primitive) {
-      jstype = "!" + jstype;
+    if (field->type() == FieldDescriptor::TYPE_BYTES &&
+        bytes_mode == BYTES_DEFAULT) {
+      jstype = "(Array<!Uint8Array>|Array<string>)";
+    } else {
+      if (!is_primitive) {
+        jstype = "!" + jstype;
+      }
+      jstype = "Array.<" + jstype + ">";
     }
-    jstype = "Array.<" + jstype + ">";
     if (!force_optional) {
       jstype = "!" + jstype;
     }
@@ -884,10 +950,6 @@
 string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
                                    bool is_writer) {
   string name = JSBinaryReaderMethodType(field);
-  if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
-    // Override for `bytes` fields: treat string as raw bytes, not base64.
-    name = "BytesRawString";
-  }
   if (field->is_packed()) {
     name = "Packed" + name;
   } else if (is_writer && field->is_repeated()) {
@@ -1044,7 +1106,7 @@
                       field->number());
 }
 
-string FieldComments(const FieldDescriptor* field) {
+string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
   string comments;
   if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
     comments +=
@@ -1060,6 +1122,11 @@
         " * replace the array itself, then you must call the setter to "
         "update it.\n";
   }
+  if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
+    comments +=
+        " * Note that Uint8Array is not supported on all browsers.\n"
+        " * @see http://caniuse.com/Uint8Array\n";
+  }
   return comments;
 }
 
@@ -1070,8 +1137,10 @@
 }
 
 bool HasExtensions(const Descriptor* desc) {
-  if (desc->extension_count() > 0) {
-    return true;
+  for (int i = 0; i < desc->extension_count(); i++) {
+    if (ShouldGenerateExtension(desc->extension(i))) {
+      return true;
+    }
   }
   for (int i = 0; i < desc->nested_type_count(); i++) {
     if (HasExtensions(desc->nested_type(i))) {
@@ -1123,7 +1192,7 @@
 }
 
 // Returns true for fields that represent "null" as distinct from the default
-// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information.
+// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
 bool HasFieldPresence(const FieldDescriptor* field) {
   return
       (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
@@ -1132,7 +1201,7 @@
 }
 
 // For proto3 fields without presence, returns a string representing the default
-// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more
+// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more
 // information.
 string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
   switch (field->cpp_type()) {
@@ -1151,16 +1220,153 @@
     case FieldDescriptor::CPPTYPE_BOOL:
       return "false";
 
-    case FieldDescriptor::CPPTYPE_STRING:
+    case FieldDescriptor::CPPTYPE_STRING:  // includes BYTES
       return "\"\"";
 
     default:
-      // BYTES and MESSAGE are handled separately.
+      // MESSAGE is handled separately.
       assert(false);
       return "";
   }
 }
 
+// We use this to implement the semantics that same file can be generated
+// multiple times, but the last one wins.  We never actually write the files,
+// but we keep a set of which descriptors were the final one for a given
+// filename.
+class FileDeduplicator {
+ public:
+  explicit FileDeduplicator(const GeneratorOptions& options)
+      : error_on_conflict_(options.error_on_name_conflict) {}
+
+  bool AddFile(const string& filename, const void* desc, string* error) {
+    if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
+      if (error_on_conflict_) {
+        *error = "Name conflict: file name " + filename +
+                 " would be generated by two descriptors";
+        return false;
+      }
+      allowed_descs_.erase(descs_by_filename_[filename]);
+    }
+
+    descs_by_filename_[filename] = desc;
+    allowed_descs_.insert(desc);
+    return true;
+  }
+
+  void GetAllowedSet(set<const void*>* allowed_set) {
+    *allowed_set = allowed_descs_;
+  }
+
+ private:
+  bool error_on_conflict_;
+  map<string, const void*> descs_by_filename_;
+  set<const void*> allowed_descs_;
+};
+
+void DepthFirstSearch(const FileDescriptor* file,
+                      vector<const FileDescriptor*>* list,
+                      set<const FileDescriptor*>* seen) {
+  if (!seen->insert(file).second) {
+    return;
+  }
+
+  // Add all dependencies.
+  for (int i = 0; i < file->dependency_count(); i++) {
+    DepthFirstSearch(file->dependency(i), list, seen);
+  }
+
+  // Add this file.
+  list->push_back(file);
+}
+
+// A functor for the predicate to remove_if() below.  Returns true if a given
+// FileDescriptor is not in the given set.
+class NotInSet {
+ public:
+  explicit NotInSet(const set<const FileDescriptor*>& file_set)
+      : file_set_(file_set) {}
+
+  bool operator()(const FileDescriptor* file) {
+    return file_set_.count(file) == 0;
+  }
+
+ private:
+  const set<const FileDescriptor*>& file_set_;
+};
+
+// This function generates an ordering of the input FileDescriptors that matches
+// the logic of the old code generator.  The order is significant because two
+// different input files can generate the same output file, and the last one
+// needs to win.
+void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input,
+                           vector<const FileDescriptor*>* ordered) {
+  // First generate an ordering of all reachable files (including dependencies)
+  // with depth-first search.  This mimics the behavior of --include_imports,
+  // which is what the old codegen used.
+  ordered->clear();
+  set<const FileDescriptor*> seen;
+  set<const FileDescriptor*> input_set;
+  for (int i = 0; i < input.size(); i++) {
+    DepthFirstSearch(input[i], ordered, &seen);
+    input_set.insert(input[i]);
+  }
+
+  // Now remove the entries that are not actually in our input list.
+  ordered->erase(
+      std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
+      ordered->end());
+}
+
+// If we're generating code in file-per-type mode, avoid overwriting files
+// by choosing the last descriptor that writes each filename and permitting
+// only those to generate code.
+
+bool GenerateJspbAllowedSet(const GeneratorOptions& options,
+                            const vector<const FileDescriptor*>& files,
+                            set<const void*>* allowed_set,
+                            string* error) {
+  vector<const FileDescriptor*> files_ordered;
+  GenerateJspbFileOrder(files, &files_ordered);
+
+  // Choose the last descriptor for each filename.
+  FileDeduplicator dedup(options);
+  for (int i = 0; i < files_ordered.size(); i++) {
+    for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
+      const Descriptor* desc = files_ordered[i]->message_type(j);
+      if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
+        return false;
+      }
+    }
+    for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
+      const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
+      if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
+        return false;
+      }
+    }
+
+    // Pull out all free-floating extensions and generate files for those too.
+    bool has_extension = false;
+
+    for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
+      if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
+        has_extension = true;
+      }
+    }
+
+    if (has_extension) {
+      if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
+                         files_ordered[i], error)) {
+        return false;
+      }
+    }
+  }
+
+  dedup.GetAllowedSet(allowed_set);
+
+  return true;
+}
+
 }  // anonymous namespace
 
 void Generator::GenerateHeader(const GeneratorOptions& options,
@@ -1251,10 +1457,10 @@
   }
 }
 
-void Generator::GenerateRequires(const GeneratorOptions& options,
-                                 io::Printer* printer,
-                                 const Descriptor* desc,
-                                 std::set<string>* provided) const {
+void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
+                                           io::Printer* printer,
+                                           const Descriptor* desc,
+                                           std::set<string>* provided) const {
   std::set<string> required;
   std::set<string> forwards;
   bool have_message = false;
@@ -1266,55 +1472,50 @@
                        /* require_extension = */ HasExtensions(desc));
 }
 
-void Generator::GenerateRequires(const GeneratorOptions& options,
-                                 io::Printer* printer,
-                                 const vector<const FileDescriptor*>& files,
-                                 std::set<string>* provided) const {
-  if (options.import_style == GeneratorOptions::IMPORT_BROWSER) {
-    return;
-  } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
-    // For Closure imports we need to import every message type individually.
-    std::set<string> required;
-    std::set<string> forwards;
-    bool have_extensions = false;
-    bool have_message = false;
+void Generator::GenerateRequiresForLibrary(
+    const GeneratorOptions& options, io::Printer* printer,
+    const vector<const FileDescriptor*>& files,
+    std::set<string>* provided) const {
+  GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE);
+  // For Closure imports we need to import every message type individually.
+  std::set<string> required;
+  std::set<string> forwards;
+  bool have_extensions = false;
+  bool have_message = false;
 
-    for (int i = 0; i < files.size(); i++) {
-      for (int j = 0; j < files[i]->message_type_count(); j++) {
-        FindRequiresForMessage(options,
-                               files[i]->message_type(j),
-                               &required, &forwards, &have_message);
-      }
-      if (!have_extensions && HasExtensions(files[i])) {
-        have_extensions = true;
-      }
-
-      for (int j = 0; j < files[i]->extension_count(); j++) {
-        const FieldDescriptor* extension = files[i]->extension(j);
-        if (IgnoreField(extension)) {
-          continue;
-        }
-        if (extension->containing_type()->full_name() !=
-            "google.protobuf.bridge.MessageSet") {
-          required.insert(GetPath(options, extension->containing_type()));
-        }
-        FindRequiresForField(options, extension, &required, &forwards);
-        have_extensions = true;
-      }
+  for (int i = 0; i < files.size(); i++) {
+    for (int j = 0; j < files[i]->message_type_count(); j++) {
+      FindRequiresForMessage(options,
+                             files[i]->message_type(j),
+                             &required, &forwards, &have_message);
+    }
+    if (!have_extensions && HasExtensions(files[i])) {
+      have_extensions = true;
     }
 
-    GenerateRequiresImpl(options, printer, &required, &forwards, provided,
-                         /* require_jspb = */ have_message,
-                         /* require_extension = */ have_extensions);
-  } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
-    // CommonJS imports are based on files
+    for (int j = 0; j < files[i]->extension_count(); j++) {
+      const FieldDescriptor* extension = files[i]->extension(j);
+      if (IgnoreField(extension)) {
+        continue;
+      }
+      if (extension->containing_type()->full_name() !=
+        "google.protobuf.bridge.MessageSet") {
+        required.insert(GetPath(options, extension->containing_type()));
+      }
+      FindRequiresForField(options, extension, &required, &forwards);
+      have_extensions = true;
+    }
   }
+
+  GenerateRequiresImpl(options, printer, &required, &forwards, provided,
+                       /* require_jspb = */ have_message,
+                       /* require_extension = */ have_extensions);
 }
 
-void Generator::GenerateRequires(const GeneratorOptions& options,
-                                 io::Printer* printer,
-                                 const vector<const FieldDescriptor*>& fields,
-                                 std::set<string>* provided) const {
+void Generator::GenerateRequiresForExtensions(
+    const GeneratorOptions& options, io::Printer* printer,
+    const vector<const FieldDescriptor*>& fields,
+    std::set<string>* provided) const {
   std::set<string> required;
   std::set<string> forwards;
   for (int i = 0; i < fields.size(); i++) {
@@ -1741,17 +1942,34 @@
     }
   } else {
     // Simple field (singular or repeated).
-    if (!HasFieldPresence(field) && !field->is_repeated()) {
+    if ((!HasFieldPresence(field) && !field->is_repeated()) ||
+        field->type() == FieldDescriptor::TYPE_BYTES) {
       // Delegate to the generated get<field>() method in order not to duplicate
-      // the proto3-field-default-value logic here.
+      // the proto3-field-default-value or byte-coercion logic here.
       printer->Print("msg.get$getter$()",
-                     "getter", JSGetterName(field));
+                     "getter", JSGetterName(field, BYTES_B64));
     } else {
       if (field->has_default_value()) {
-        printer->Print("jspb.Message.getField(msg, $index$) != null ? "
-                       "jspb.Message.getField(msg, $index$) : $defaultValue$",
+        printer->Print("jspb.Message.getField(msg, $index$) == null ? "
+                       "$defaultValue$ : ",
                        "index", JSFieldIndex(field),
                        "defaultValue", JSFieldDefault(field));
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+          field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+        if (field->is_repeated()) {
+          printer->Print("jspb.Message.getRepeatedFloatingPointField("
+                         "msg, $index$)",
+                         "index", JSFieldIndex(field));
+        } else if (field->is_optional() && !field->has_default_value()) {
+          printer->Print("jspb.Message.getOptionalFloatingPointField("
+                         "msg, $index$)",
+                         "index", JSFieldIndex(field));
+        } else {
+          // Convert "NaN" to NaN.
+          printer->Print("+jspb.Message.getField(msg, $index$)",
+                         "index", JSFieldIndex(field));
+        }
       } else {
         printer->Print("jspb.Message.getField(msg, $index$)",
                        "index", JSFieldIndex(field));
@@ -1860,6 +2078,40 @@
   }
 }
 
+void GenerateBytesWrapper(const GeneratorOptions& options,
+                          io::Printer* printer,
+                          const FieldDescriptor* field,
+                          BytesMode bytes_mode) {
+  string type =
+      JSFieldTypeAnnotation(options, field,
+                            /* force_optional = */ false,
+                            /* force_present = */ !HasFieldPresence(field),
+                            /* singular_if_not_packed = */ false,
+                            bytes_mode);
+  printer->Print(
+      "/**\n"
+      " * $fielddef$\n"
+      "$comment$"
+      " * This is a type-conversion wrapper around `get$defname$()`\n"
+      " * @return {$type$}\n"
+      " */\n"
+      "$class$.prototype.get$name$ = function() {\n"
+      "  return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
+      "      this.get$defname$()));\n"
+      "};\n"
+      "\n"
+      "\n",
+      "fielddef", FieldDefinition(options, field),
+      "comment", FieldComments(field, bytes_mode),
+      "type", type,
+      "class", GetPath(options, field->containing_type()),
+      "name", JSGetterName(field, bytes_mode),
+      "list", field->is_repeated() ? "List" : "",
+      "suffix", JSByteGetterSuffix(bytes_mode),
+      "defname", JSGetterName(field, BYTES_DEFAULT));
+}
+
+
 void Generator::GenerateClassField(const GeneratorOptions& options,
                                    io::Printer* printer,
                                    const FieldDescriptor* field) const {
@@ -1871,12 +2123,11 @@
         " * @return {$type$}\n"
         " */\n",
         "fielddef", FieldDefinition(options, field),
-        "comment", FieldComments(field),
+        "comment", FieldComments(field, BYTES_DEFAULT),
         "type", JSFieldTypeAnnotation(options, field,
                                       /* force_optional = */ false,
                                       /* force_present = */ false,
-                                      /* singular_if_not_packed = */ false,
-                                      /* always_singular = */ false));
+                                      /* singular_if_not_packed = */ false));
     printer->Print(
         "$class$.prototype.get$name$ = function() {\n"
         "  return /** @type{$type$} */ (\n"
@@ -1890,8 +2141,7 @@
         "type", JSFieldTypeAnnotation(options, field,
                                       /* force_optional = */ false,
                                       /* force_present = */ false,
-                                      /* singular_if_not_packed = */ false,
-                                      /* always_singular = */ false),
+                                      /* singular_if_not_packed = */ false),
         "rpt", (field->is_repeated() ? "Repeated" : ""),
         "index", JSFieldIndex(field),
         "wrapperclass", SubmessageTypeRef(options, field),
@@ -1905,8 +2155,7 @@
         JSFieldTypeAnnotation(options, field,
                               /* force_optional = */ true,
                               /* force_present = */ false,
-                              /* singular_if_not_packed = */ false,
-                              /* always_singular = */ false),
+                              /* singular_if_not_packed = */ false),
         "returndoc", JSReturnDoc(options, field),
         "class", GetPath(options, field->containing_type()),
         "name", JSGetterName(field),
@@ -1935,15 +2184,29 @@
         "returnvalue", JSReturnClause(field));
 
   } else {
-    string typed_annotation;
+    bool untyped =
+        false;
 
     // Simple (primitive) field, either singular or repeated.
-    {
-      typed_annotation = JSFieldTypeAnnotation(options, field,
+
+    // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type;
+    // at this point we "lie" to non-binary users and tell the the return
+    // type is always base64 string, pending a LSC to migrate to typed getters.
+    BytesMode bytes_mode =
+        field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ?
+            BYTES_B64 : BYTES_DEFAULT;
+    string typed_annotation =
+        JSFieldTypeAnnotation(options, field,
                               /* force_optional = */ false,
                               /* force_present = */ !HasFieldPresence(field),
                               /* singular_if_not_packed = */ false,
-                              /* always_singular = */ false),
+                              /* bytes_mode = */ bytes_mode);
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * @return {?} Raw field, untyped.\n"
+          " */\n");
+    } else {
       printer->Print(
           "/**\n"
           " * $fielddef$\n"
@@ -1951,7 +2214,7 @@
           " * @return {$type$}\n"
           " */\n",
           "fielddef", FieldDefinition(options, field),
-          "comment", FieldComments(field),
+          "comment", FieldComments(field, bytes_mode),
           "type", typed_annotation);
     }
 
@@ -1960,7 +2223,10 @@
         "class", GetPath(options, field->containing_type()),
         "name", JSGetterName(field));
 
-    {
+    if (untyped) {
+      printer->Print(
+          "  return ");
+    } else {
       printer->Print(
           "  return /** @type {$type$} */ (",
           "type", typed_annotation);
@@ -1975,17 +2241,39 @@
                      "default", Proto3PrimitiveFieldDefault(field));
     } else {
       if (field->has_default_value()) {
-        printer->Print("jspb.Message.getField(this, $index$) != null ? "
-                       "jspb.Message.getField(this, $index$) : $defaultValue$",
+        printer->Print("jspb.Message.getField(this, $index$) == null ? "
+                       "$defaultValue$ : ",
                        "index", JSFieldIndex(field),
                        "defaultValue", JSFieldDefault(field));
+      }
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+          field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+        if (field->is_repeated()) {
+          printer->Print("jspb.Message.getRepeatedFloatingPointField("
+                         "this, $index$)",
+                         "index", JSFieldIndex(field));
+        } else if (field->is_optional() && !field->has_default_value()) {
+          printer->Print("jspb.Message.getOptionalFloatingPointField("
+                         "this, $index$)",
+                         "index", JSFieldIndex(field));
+        } else {
+          // Convert "NaN" to NaN.
+          printer->Print("+jspb.Message.getField(this, $index$)",
+                         "index", JSFieldIndex(field));
+        }
       } else {
         printer->Print("jspb.Message.getField(this, $index$)",
                        "index", JSFieldIndex(field));
       }
     }
 
-    {
+    if (untyped) {
+      printer->Print(
+          ";\n"
+          "};\n"
+          "\n"
+          "\n");
+    } else {
       printer->Print(
           ");\n"
           "};\n"
@@ -1993,18 +2281,27 @@
           "\n");
     }
 
-    {
+    if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
+      GenerateBytesWrapper(options, printer, field, BYTES_B64);
+      GenerateBytesWrapper(options, printer, field, BYTES_U8);
+    }
+
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * @param {*} value $returndoc$\n"
+          " */\n",
+          "returndoc", JSReturnDoc(options, field));
+    } else {
       printer->Print(
           "/** @param {$optionaltype$} value $returndoc$ */\n",
           "optionaltype",
           JSFieldTypeAnnotation(options, field,
                                 /* force_optional = */ true,
                                 /* force_present = */ !HasFieldPresence(field),
-                                /* singular_if_not_packed = */ false,
-                                /* always_singular = */ false),
+                                /* singular_if_not_packed = */ false),
           "returndoc", JSReturnDoc(options, field));
     }
-
     printer->Print(
         "$class$.prototype.set$name$ = function(value) {\n"
         "  jspb.Message.set$oneoftag$Field(this, $index$",
@@ -2017,14 +2314,22 @@
         "};\n"
         "\n"
         "\n",
-        "type", "",
-        "typeclose", "",
+        "type",
+        untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
+        "typeclose", untyped ? ")" : "",
         "oneofgroup",
         (field->containing_oneof() ? (", " + JSOneofArray(options, field))
                                    : ""),
         "returnvalue", JSReturnClause(field), "rptvalueinit",
         (field->is_repeated() ? " || []" : ""));
 
+    if (untyped) {
+      printer->Print(
+          "/**\n"
+          " * Clears the value. $returndoc$\n"
+          " */\n",
+          "returndoc", JSReturnDoc(options, field));
+    }
 
     if (HasFieldPresence(field)) {
       printer->Print(
@@ -2162,16 +2467,18 @@
         "      var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
         "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
                                            /* singular_if_not_packed = */ true,
-                                           /* always_singular = */ false),
+                                           BYTES_U8),
         "reader", JSBinaryReaderMethodName(field));
   }
 
   if (field->is_repeated() && !field->is_packed()) {
     // Repeated fields receive a |value| one at at a time; append to array
-    // returned by get$name$().
-    printer->Print(
-        "      msg.get$name$().push(value);\n",
-        "name", JSGetterName(field));
+    // returned by get$name$(). Annoyingly, we have to call 'set' after
+    // changing the array.
+    printer->Print("      msg.get$name$().push(value);\n", "name",
+                   JSGetterName(field));
+    printer->Print("      msg.set$name$(msg.get$name$());\n", "name",
+                   JSGetterName(field));
   } else {
     // Singular fields, and packed repeated fields, receive a |value| either as
     // the field's value or as the array of all the field's values; set this as
@@ -2244,7 +2551,7 @@
     const FieldDescriptor* field) const {
   printer->Print(
       "  f = this.get$name$();\n",
-      "name", JSGetterName(field));
+      "name", JSGetterName(field, BYTES_U8));
 
   if (field->is_repeated()) {
     printer->Print(
@@ -2294,7 +2601,6 @@
       "      $index$,\n"
       "      f",
       "writer", JSBinaryWriterMethodName(field),
-      "name", JSGetterName(field),
       "index", SimpleItoa(field->number()));
 
   if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
@@ -2356,8 +2662,7 @@
           options, field,
           /* force_optional = */ false,
           /* force_present = */ true,
-          /* singular_if_not_packed = */ false,
-          /* always_singular = */ false));
+          /* singular_if_not_packed = */ false));
   printer->Print(
       "    $index$,\n"
       "    {$name$: 0},\n"
@@ -2528,7 +2833,7 @@
     printer->Print("var global = Function('return this')();\n\n");
 
     for (int i = 0; i < file->dependency_count(); i++) {
-      const std::string& name = file->dependency(i)->name();
+      const string& name = file->dependency(i)->name();
       printer->Print(
           "var $alias$ = require('$file$');\n",
           "alias", ModuleAlias(name),
@@ -2543,7 +2848,7 @@
   //
   //   // Later generated code expects foo.bar = {} to exist:
   //   foo.bar.Baz = function() { /* ... */ }
-  std::set<std::string> provided;
+  set<string> provided;
 
   // Cover the case where this file declares extensions but no messages.
   // This will ensure that the file-level object will be declared to hold
@@ -2615,7 +2920,7 @@
     FindProvidesForFields(options, &printer, extensions, &provided);
     GenerateProvides(options, &printer, &provided);
     GenerateTestOnly(options, &printer);
-    GenerateRequires(options, &printer, files, &provided);
+    GenerateRequiresForLibrary(options, &printer, files, &provided);
 
     GenerateFilesInDepOrder(options, &printer, files);
 
@@ -2629,66 +2934,20 @@
       return false;
     }
   } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
-    // Collect all types, and print each type to a separate file. Pull out
-    // free-floating extensions while we make this pass.
-    map< string, vector<const FieldDescriptor*> > extensions_by_namespace;
-
-    // If we're generating code in file-per-type mode, avoid overwriting files
-    // by choosing the last descriptor that writes each filename and permitting
-    // only those to generate code.
-
-    // Current descriptor that will generate each filename, indexed by filename.
-    map<string, const void*> desc_by_filename;
-    // Set of descriptors allowed to generate files.
-    set<const void*> allowed_descs;
-
-    for (int i = 0; i < files.size(); i++) {
-      // Collect all (descriptor, filename) pairs.
-      map<const void*, string> descs_in_file;
-      for (int j = 0; j < files[i]->message_type_count(); j++) {
-        const Descriptor* desc = files[i]->message_type(j);
-        string filename =
-            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
-        descs_in_file[desc] = filename;
-      }
-      for (int j = 0; j < files[i]->enum_type_count(); j++) {
-        const EnumDescriptor* desc = files[i]->enum_type(j);
-        string filename =
-            options.output_dir + "/" + ToFileName(desc->name()) + ".js";
-        descs_in_file[desc] = filename;
-      }
-
-      // For each (descriptor, filename) pair, update the
-      // descriptors-by-filename map, and if a previous descriptor was already
-      // writing the filename, remove it from the allowed-descriptors set.
-      map<const void*, string>::iterator it;
-      for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
-        const void* desc = it->first;
-        const string& filename = it->second;
-        if (desc_by_filename.find(filename) != desc_by_filename.end()) {
-          if (options.error_on_name_conflict) {
-            *error = "Name conflict: file name " + filename +
-                     " would be generated by two descriptors";
-            return false;
-          }
-          allowed_descs.erase(desc_by_filename[filename]);
-        }
-        desc_by_filename[filename] = desc;
-        allowed_descs.insert(desc);
-      }
+    set<const void*> allowed_set;
+    if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
+      return false;
     }
 
-    // Generate code.
     for (int i = 0; i < files.size(); i++) {
       const FileDescriptor* file = files[i];
       for (int j = 0; j < file->message_type_count(); j++) {
         const Descriptor* desc = file->message_type(j);
-        if (allowed_descs.find(desc) == allowed_descs.end()) {
+        if (allowed_set.count(desc) == 0) {
           continue;
         }
 
-        string filename = options.output_dir + "/" +
-            ToFileName(desc->name()) + ".js";
+        string filename = GetMessageFileName(options, desc);
         google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
             context->Open(filename));
         GOOGLE_CHECK(output.get());
@@ -2700,7 +2959,7 @@
         FindProvidesForMessage(options, &printer, desc, &provided);
         GenerateProvides(options, &printer, &provided);
         GenerateTestOnly(options, &printer);
-        GenerateRequires(options, &printer, desc, &provided);
+        GenerateRequiresForMessage(options, &printer, desc, &provided);
 
         GenerateClass(options, &printer, desc);
 
@@ -2710,13 +2969,11 @@
       }
       for (int j = 0; j < file->enum_type_count(); j++) {
         const EnumDescriptor* enumdesc = file->enum_type(j);
-        if (allowed_descs.find(enumdesc) == allowed_descs.end()) {
+        if (allowed_set.count(enumdesc) == 0) {
           continue;
         }
 
-        string filename = options.output_dir + "/" +
-            ToFileName(enumdesc->name()) + ".js";
-
+        string filename = GetEnumFileName(options, enumdesc);
         google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
             context->Open(filename));
         GOOGLE_CHECK(output.get());
@@ -2735,38 +2992,36 @@
           return false;
         }
       }
-      // Pull out all free-floating extensions and generate files for those too.
-      for (int j = 0; j < file->extension_count(); j++) {
-        const FieldDescriptor* extension = file->extension(j);
-        extensions_by_namespace[GetPath(options, files[i])]
-            .push_back(extension);
-      }
-    }
+      // File-level extensions (message-level extensions are generated under
+      // the enclosing message).
+      if (allowed_set.count(file) == 1) {
+        string filename = GetExtensionFileName(options, file);
 
-    // Generate extensions in separate files.
-    map< string, vector<const FieldDescriptor*> >::iterator it;
-    for (it = extensions_by_namespace.begin();
-         it != extensions_by_namespace.end();
-         ++it) {
-      string filename = options.output_dir + "/" +
-          ToFileName(it->first) + ".js";
+        google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+            context->Open(filename));
+        GOOGLE_CHECK(output.get());
+        io::Printer printer(output.get(), '$');
 
-      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
-          context->Open(filename));
-      GOOGLE_CHECK(output.get());
-      io::Printer printer(output.get(), '$');
+        GenerateHeader(options, &printer);
 
-      GenerateHeader(options, &printer);
+        std::set<string> provided;
+        vector<const FieldDescriptor*> fields;
 
-      std::set<string> provided;
-      FindProvidesForFields(options, &printer, it->second, &provided);
-      GenerateProvides(options, &printer, &provided);
-      GenerateTestOnly(options, &printer);
-      GenerateRequires(options, &printer, it->second, &provided);
+        for (int j = 0; j < files[i]->extension_count(); j++) {
+          if (ShouldGenerateExtension(files[i]->extension(j))) {
+            fields.push_back(files[i]->extension(j));
+          }
+        }
 
-      for (int j = 0; j < it->second.size(); j++) {
-        if (ShouldGenerateExtension(it->second[j])) {
-          GenerateExtension(options, &printer, it->second[j]);
+        FindProvidesForFields(options, &printer, fields, &provided);
+        GenerateProvides(options, &printer, &provided);
+        GenerateTestOnly(options, &printer);
+        GenerateRequiresForExtensions(options, &printer, fields, &provided);
+
+        for (int j = 0; j < files[i]->extension_count(); j++) {
+          if (ShouldGenerateExtension(files[i]->extension(j))) {
+            GenerateExtension(options, &printer, files[i]->extension(j));
+          }
         }
       }
     }
@@ -2777,7 +3032,7 @@
       const google::protobuf::FileDescriptor* file = files[i];
 
       string filename = options.output_dir + "/" + GetJSFilename(file->name());
-      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+      scoped_ptr<io::ZeroCopyOutputStream> output(
           context->Open(filename));
       GOOGLE_CHECK(output.get());
       io::Printer printer(output.get(), '$');
diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h
index db9178d..6fd7ca5 100755
--- a/src/google/protobuf/compiler/js/js_generator.h
+++ b/src/google/protobuf/compiler/js/js_generator.h
@@ -146,19 +146,19 @@
                         io::Printer* printer) const;
 
   // Generate goog.requires() calls.
-  void GenerateRequires(const GeneratorOptions& options,
-                        io::Printer* printer,
-                        const vector<const FileDescriptor*>& file,
-                        std::set<string>* provided) const;
-  void GenerateRequires(const GeneratorOptions& options,
+  void GenerateRequiresForLibrary(const GeneratorOptions& options,
+                                  io::Printer* printer,
+                                  const vector<const FileDescriptor*>& files,
+                                  std::set<string>* provided) const;
+  void GenerateRequiresForMessage(const GeneratorOptions& options,
                         io::Printer* printer,
                         const Descriptor* desc,
                         std::set<string>* provided) const;
   // For extension fields at file scope.
-  void GenerateRequires(const GeneratorOptions& options,
-                        io::Printer* printer,
-                        const vector<const FieldDescriptor*>& fields,
-                        std::set<string>* provided) const;
+  void GenerateRequiresForExtensions(
+      const GeneratorOptions& options, io::Printer* printer,
+      const vector<const FieldDescriptor*>& fields,
+      std::set<string>* provided) const;
   void GenerateRequiresImpl(const GeneratorOptions& options,
                             io::Printer* printer,
                             std::set<string>* required,
diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc
index 121d917..82bb342 100644
--- a/src/google/protobuf/compiler/mock_code_generator.cc
+++ b/src/google/protobuf/compiler/mock_code_generator.cc
@@ -32,20 +32,26 @@
 
 #include <google/protobuf/compiler/mock_code_generator.h>
 
+#include <stdlib.h>
+#include <iostream>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
+#include <vector>
 
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/testing/file.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/io/printer.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <gtest/gtest.h>
-#include <google/protobuf/stubs/stl_util.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h
index 8c8348d..e1665f8 100644
--- a/src/google/protobuf/compiler/mock_code_generator.h
+++ b/src/google/protobuf/compiler/mock_code_generator.h
@@ -34,10 +34,15 @@
 #define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
 
 #include <string>
+
 #include <google/protobuf/compiler/code_generator.h>
 
 namespace google {
 namespace protobuf {
+class FileDescriptor;
+}  // namespace protobuf
+
+namespace protobuf {
 namespace compiler {
 
 // A mock CodeGenerator, used by command_line_interface_unittest.  This is in
diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc
index 2bebf1f..2ff50f6 100644
--- a/src/google/protobuf/compiler/plugin.cc
+++ b/src/google/protobuf/compiler/plugin.cc
@@ -93,6 +93,65 @@
   const vector<const FileDescriptor*>& parsed_files_;
 };
 
+bool GenerateCode(const CodeGeneratorRequest& request,
+    const CodeGenerator& generator, CodeGeneratorResponse* response,
+    string* error_msg) {
+  DescriptorPool pool;
+  for (int i = 0; i < request.proto_file_size(); i++) {
+    const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
+    if (file == NULL) {
+      // BuildFile() already wrote an error message.
+      return false;
+    }
+  }
+
+  vector<const FileDescriptor*> parsed_files;
+  for (int i = 0; i < request.file_to_generate_size(); i++) {
+    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
+    if (parsed_files.back() == NULL) {
+      *error_msg = "protoc asked plugin to generate a file but "
+                   "did not provide a descriptor for the file: " +
+                   request.file_to_generate(i);
+      return false;
+    }
+  }
+
+  GeneratorResponseContext context(response, parsed_files);
+
+  if (generator.HasGenerateAll()) {
+    string error;
+    bool succeeded = generator.GenerateAll(
+        parsed_files, request.parameter(), &context, &error);
+
+    if (!succeeded && error.empty()) {
+      error = "Code generator returned false but provided no error "
+              "description.";
+    }
+    if (!error.empty()) {
+      response->set_error(error);
+    }
+  } else {
+    for (int i = 0; i < parsed_files.size(); i++) {
+      const FileDescriptor* file = parsed_files[i];
+
+      string error;
+      bool succeeded = generator.Generate(
+          file, request.parameter(), &context, &error);
+
+      if (!succeeded && error.empty()) {
+        error = "Code generator returned false but provided no error "
+                "description.";
+      }
+      if (!error.empty()) {
+        response->set_error(file->name() + ": " + error);
+        break;
+      }
+    }
+  }
+
+  return true;
+}
+
 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
 
   if (argc > 1) {
@@ -112,62 +171,18 @@
     return 1;
   }
 
-  DescriptorPool pool;
-  for (int i = 0; i < request.proto_file_size(); i++) {
-    const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
-    if (file == NULL) {
-      // BuildFile() already wrote an error message.
-      return 1;
-    }
-  }
-
-  vector<const FileDescriptor*> parsed_files;
-  for (int i = 0; i < request.file_to_generate_size(); i++) {
-    parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
-    if (parsed_files.back() == NULL) {
-      std::cerr << argv[0] << ": protoc asked plugin to generate a file but "
-                              "did not provide a descriptor for the file: "
-                << request.file_to_generate(i) << std::endl;
-      return 1;
-    }
-  }
-
+  string error_msg;
   CodeGeneratorResponse response;
-  GeneratorResponseContext context(&response, parsed_files);
 
-  if (generator->HasGenerateAll()) {
-    string error;
-    bool succeeded = generator->GenerateAll(
-        parsed_files, request.parameter(), &context, &error);
-
-    if (!succeeded && error.empty()) {
-      error = "Code generator returned false but provided no error "
-              "description.";
-    }
-    if (!error.empty()) {
-      response.set_error(error);
+  if (GenerateCode(request, *generator, &response, &error_msg)) {
+    if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
+      std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
+      return 1;
     }
   } else {
-    for (int i = 0; i < parsed_files.size(); i++) {
-      const FileDescriptor* file = parsed_files[i];
-
-      string error;
-      bool succeeded = generator->Generate(
-          file, request.parameter(), &context, &error);
-
-      if (!succeeded && error.empty()) {
-        error = "Code generator returned false but provided no error "
-                "description.";
-      }
-      if (!error.empty()) {
-        response.set_error(file->name() + ": " + error);
-        break;
-      }
+    if (!error_msg.empty()) {
+      std::cerr << argv[0] << ": " << error_msg << std::endl;
     }
-  }
-
-  if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
-    std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
     return 1;
   }
 
diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h
index 679f9bd..d2793a9 100644
--- a/src/google/protobuf/compiler/plugin.h
+++ b/src/google/protobuf/compiler/plugin.h
@@ -40,6 +40,13 @@
 //   }
 // You must link your plugin against libprotobuf and libprotoc.
 //
+// The core part of PluginMain is to invoke the given CodeGenerator on a
+// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is
+// abstracted out and made into function GenerateCode so that it can be reused,
+// for example, to implement a variant of PluginMain that does some
+// preprocessing on the input CodeGeneratorRequest before feeding the request
+// to the given code generator.
+//
 // To get protoc to use the plugin, do one of the following:
 // * Place the plugin binary somewhere in the PATH and give it the name
 //   "protoc-gen-NAME" (replacing "NAME" with the name of your plugin).  If you
@@ -55,16 +62,27 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
 #define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
 
+#include <string>
+
 #include <google/protobuf/stubs/common.h>
 namespace google {
 namespace protobuf {
 namespace compiler {
 
 class CodeGenerator;    // code_generator.h
+class CodeGeneratorRequest;
+class CodeGeneratorResponse;
 
 // Implements main() for a protoc plugin exposing the given code generator.
 LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
 
+// Generates code using the given code generator. Returns true if the code
+// generation is successful. If the code geneartion fails, error_msg may be
+// populated to describe the failure cause.
+bool GenerateCode(const CodeGeneratorRequest& request,
+    const CodeGenerator& generator, CodeGeneratorResponse* response,
+    string* error_msg);
+
 }  // namespace compiler
 }  // namespace protobuf
 
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 4d500f9..0553dd0 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -235,7 +235,7 @@
         // infinity * 0 = nan
         return "(1e10000 * 0)";
       } else {
-        return SimpleDtoa(value);
+        return "float(" + SimpleDtoa(value) + ")";
       }
     }
     case FieldDescriptor::CPPTYPE_FLOAT: {
@@ -251,7 +251,7 @@
         // infinity - infinity = nan
         return "(1e10000 * 0)";
       } else {
-        return SimpleFtoa(value);
+        return "float(" + SimpleFtoa(value) + ")";
       }
     }
     case FieldDescriptor::CPPTYPE_BOOL:
diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc
index a30ac30..6e25866 100644
--- a/src/google/protobuf/compiler/subprocess.cc
+++ b/src/google/protobuf/compiler/subprocess.cc
@@ -361,7 +361,7 @@
   string output_data;
 
   int input_pos = 0;
-  int max_fd = max(child_stdin_, child_stdout_);
+  int max_fd = std::max(child_stdin_, child_stdout_);
 
   while (child_stdout_ != -1) {
     fd_set read_fds;