Forráskód Böngészése

Merge "Avoid class initializers to help ProGuard."

Max Cai 12 éve
szülő
commit
b3bc6095b2

+ 12 - 0
java/src/main/java/com/google/protobuf/nano/InternalNano.java

@@ -45,6 +45,18 @@ public final class InternalNano {
 
   private InternalNano() {}
 
+  /**
+   * An object to provide synchronization when lazily initializing static fields
+   * of {@link MessageNano} subclasses.
+   * <p>
+   * To enable earlier versions of ProGuard to inline short methods from a
+   * generated MessageNano subclass to the call sites, that class must not have
+   * a class initializer, which will be created if there is any static variable
+   * initializers. To lazily initialize the static variables in a thread-safe
+   * manner, the initialization code will synchronize on this object.
+   */
+  public static final Object LAZY_INIT_LOCK = new Object();
+
   /**
    * Helper called by generated code to construct default values for string
    * fields.

+ 17 - 18
java/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java

@@ -62,7 +62,7 @@ public final class MessageNanoPrinter {
 
         StringBuffer buf = new StringBuffer();
         try {
-            print(null, message.getClass(), message, new StringBuffer(), buf);
+            print(null, message, new StringBuffer(), buf);
         } catch (IllegalAccessException e) {
             return "Error printing proto: " + e.getMessage();
         }
@@ -70,33 +70,32 @@ public final class MessageNanoPrinter {
     }
 
     /**
-     * Function that will print the given message/class into the StringBuffer.
+     * Function that will print the given message/field into the StringBuffer.
      * Meant to be called recursively.
      *
      * @param identifier the identifier to use, or {@code null} if this is the root message to
      *        print.
-     * @param clazz the class of {@code message}.
-     * @param message the value to print. May in fact be a primitive value or byte array and not a
+     * @param object the value to print. May in fact be a primitive value or byte array and not a
      *        message.
      * @param indentBuf the indentation each line should begin with.
      * @param buf the output buffer.
      */
-    private static void print(String identifier, Class<?> clazz, Object message,
+    private static void print(String identifier, Object object,
             StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException {
-        if (message == null) {
+        if (object == null) {
             // This can happen if...
             //   - we're about to print a message, String, or byte[], but it not present;
             //   - we're about to print a primitive, but "reftype" optional style is enabled, and
             //     the field is unset.
             // In both cases the appropriate behavior is to output nothing.
-        } else if (MessageNano.class.isAssignableFrom(clazz)) {  // Nano proto message
+        } else if (object instanceof MessageNano) {  // Nano proto message
             int origIndentBufLength = indentBuf.length();
             if (identifier != null) {
                 buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
                 indentBuf.append(INDENT);
             }
 
-            for (Field field : clazz.getFields()) {
+            for (Field field : object.getClass().getFields()) {
                 // Proto fields are public, non-static variables that do not begin or end with '_'
                 int modifiers = field.getModifiers();
                 String fieldName = field.getName();
@@ -106,24 +105,24 @@ public final class MessageNanoPrinter {
                     continue;
                 }
 
-                Class <?> fieldType = field.getType();
-                Object value = field.get(message);
+                Class<?> fieldType = field.getType();
+                Object value = field.get(object);
 
                 if (fieldType.isArray()) {
                     Class<?> arrayType = fieldType.getComponentType();
 
                     // bytes is special since it's not repeated, but is represented by an array
                     if (arrayType == byte.class) {
-                        print(fieldName, fieldType, value, indentBuf, buf);
+                        print(fieldName, value, indentBuf, buf);
                     } else {
                         int len = value == null ? 0 : Array.getLength(value);
                         for (int i = 0; i < len; i++) {
                             Object elem = Array.get(value, i);
-                            print(fieldName, arrayType, elem, indentBuf, buf);
+                            print(fieldName, elem, indentBuf, buf);
                         }
                     }
                 } else {
-                    print(fieldName, fieldType, value, indentBuf, buf);
+                    print(fieldName, value, indentBuf, buf);
                 }
             }
             if (identifier != null) {
@@ -134,13 +133,13 @@ public final class MessageNanoPrinter {
             // Non-null primitive value
             identifier = deCamelCaseify(identifier);
             buf.append(indentBuf).append(identifier).append(": ");
-            if (message instanceof String) {
-                String stringMessage = sanitizeString((String) message);
+            if (object instanceof String) {
+                String stringMessage = sanitizeString((String) object);
                 buf.append("\"").append(stringMessage).append("\"");
-            } else if (message instanceof byte[]) {
-                appendQuotedBytes((byte[]) message, buf);
+            } else if (object instanceof byte[]) {
+                appendQuotedBytes((byte[]) object, buf);
             } else {
-                buf.append(message);
+                buf.append(object);
             }
             buf.append("\n");
         }

+ 3 - 3
src/google/protobuf/compiler/javanano/javanano_enum_field.cc

@@ -87,7 +87,7 @@ EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
 EnumFieldGenerator::~EnumFieldGenerator() {}
 
 void EnumFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
   printer->Print(variables_,
     "public $type$ $name$;\n");
 
@@ -214,7 +214,7 @@ AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
 AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
 
 void AccessorEnumFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
   printer->Print(variables_,
     "private int $name$_;\n"
     "public int get$capitalized_name$() {\n"
@@ -291,7 +291,7 @@ RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& para
 RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
 
 void RepeatedEnumFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
   printer->Print(variables_,
     "public $type$[] $name$;\n");
 }

+ 7 - 5
src/google/protobuf/compiler/javanano/javanano_enum_field.h

@@ -46,11 +46,12 @@ namespace javanano {
 
 class EnumFieldGenerator : public FieldGenerator {
  public:
-  explicit EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  explicit EnumFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
   ~EnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
@@ -72,7 +73,7 @@ class AccessorEnumFieldGenerator : public FieldGenerator {
   ~AccessorEnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
@@ -89,11 +90,12 @@ class AccessorEnumFieldGenerator : public FieldGenerator {
 
 class RepeatedEnumFieldGenerator : public FieldGenerator {
  public:
-  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  explicit RepeatedEnumFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
   ~RepeatedEnumFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCodeFromPacked(io::Printer* printer) const;

+ 25 - 14
src/google/protobuf/compiler/javanano/javanano_field.cc

@@ -46,6 +46,19 @@ namespace javanano {
 
 FieldGenerator::~FieldGenerator() {}
 
+bool FieldGenerator::SavedDefaultNeeded() const {
+  // No saved default for this field by default.
+  // Subclasses whose instances may need saved defaults will override this
+  // and return the appropriate value.
+  return false;
+}
+
+void FieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+  // No saved default for this field by default.
+  // Subclasses whose instances may need saved defaults will override this
+  // and generate the appropriate init code to the printer.
+}
+
 void FieldGenerator::GenerateMergingCodeFromPacked(io::Printer* printer) const {
   // Reaching here indicates a bug. Cases are:
   //   - This FieldGenerator should support packing, but this method should be
@@ -56,24 +69,26 @@ void FieldGenerator::GenerateMergingCodeFromPacked(io::Printer* printer) const {
              << "called on field generator that does not support packing.";
 }
 
-FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params &params)
+// =============================================
+
+FieldGeneratorMap::FieldGeneratorMap(
+    const Descriptor* descriptor, const Params &params)
   : descriptor_(descriptor),
     field_generators_(
-      new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
-    extension_generators_(
-      new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+      new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
 
   int next_has_bit_index = 0;
+  bool saved_defaults_needed = false;
   // Construct all the FieldGenerators.
   for (int i = 0; i < descriptor->field_count(); i++) {
-    field_generators_[i].reset(
-        MakeGenerator(descriptor->field(i), params, &next_has_bit_index));
-  }
-  for (int i = 0; i < descriptor->extension_count(); i++) {
-    extension_generators_[i].reset(
-        MakeGenerator(descriptor->extension(i), params, &next_has_bit_index));
+    FieldGenerator* field_generator = MakeGenerator(
+        descriptor->field(i), params, &next_has_bit_index);
+    saved_defaults_needed = saved_defaults_needed
+        || field_generator->SavedDefaultNeeded();
+    field_generators_[i].reset(field_generator);
   }
   total_bits_ = next_has_bit_index;
+  saved_defaults_needed_ = saved_defaults_needed;
 }
 
 FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
@@ -122,10 +137,6 @@ const FieldGenerator& FieldGeneratorMap::get(
   return *field_generators_[field->index()];
 }
 
-const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
-  return *extension_generators_[index];
-}
-
 }  // namespace javanano
 }  // namespace compiler
 }  // namespace protobuf

+ 16 - 4
src/google/protobuf/compiler/javanano/javanano_field.h

@@ -53,11 +53,23 @@ namespace javanano {
 
 class FieldGenerator {
  public:
-  //FieldGenerator() {}
   FieldGenerator(const Params& params) : params_(params) {}
   virtual ~FieldGenerator();
 
-  virtual void GenerateMembers(io::Printer* printer) const = 0;
+  virtual bool SavedDefaultNeeded() const;
+  virtual void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+
+  // Generates code for Java fields and methods supporting this field.
+  // If this field needs a saved default (SavedDefaultNeeded() is true),
+  // then @lazy_init controls how the static field for that default value
+  // and its initialization code should be generated. If @lazy_init is
+  // true, the static field is not declared final and the initialization
+  // code is generated only when GenerateInitSavedDefaultCode is called;
+  // otherwise, the static field is declared final and initialized inline.
+  // GenerateInitSavedDefaultCode will not be called in the latter case.
+  virtual void GenerateMembers(
+      io::Printer* printer, bool lazy_init) const = 0;
+
   virtual void GenerateClearCode(io::Printer* printer) const = 0;
   virtual void GenerateMergingCode(io::Printer* printer) const = 0;
 
@@ -84,14 +96,14 @@ class FieldGeneratorMap {
   ~FieldGeneratorMap();
 
   const FieldGenerator& get(const FieldDescriptor* field) const;
-  const FieldGenerator& get_extension(int index) const;
   int total_bits() const { return total_bits_; }
+  bool saved_defaults_needed() const { return saved_defaults_needed_; }
 
  private:
   const Descriptor* descriptor_;
   scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
-  scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
   int total_bits_;
+  bool saved_defaults_needed_;
 
   static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
       const Params &params, int* next_has_bit_index);

+ 1 - 3
src/google/protobuf/compiler/javanano/javanano_helpers.cc

@@ -261,9 +261,7 @@ string FieldConstantName(const FieldDescriptor *field) {
 }
 
 string FieldDefaultConstantName(const FieldDescriptor *field) {
-  string name = field->name() + "_DEFAULT";
-  UpperString(&name);
-  return name;
+  return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
 }
 
 JavaType GetJavaType(FieldDescriptor::Type field_type) {

+ 82 - 10
src/google/protobuf/compiler/javanano/javanano_message.cc

@@ -155,14 +155,6 @@ void MessageGenerator::Generate(io::Printer* printer) {
       "    com.google.protobuf.nano.MessageNano {\n");
   }
   printer->Indent();
-  printer->Print(
-    "\n"
-    "public static final $classname$[] EMPTY_ARRAY = {};\n"
-    "\n"
-    "public $classname$() {\n"
-    "  clear();\n"
-    "}\n",
-    "classname", descriptor_->name());
 
   // Nested types and extensions
   for (int i = 0; i < descriptor_->extension_count(); i++) {
@@ -177,6 +169,42 @@ void MessageGenerator::Generate(io::Printer* printer) {
     MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
   }
 
+  // Lazy initialization of otherwise static final fields can help prevent the
+  // class initializer from being generated. We want to prevent it because it
+  // stops ProGuard from inlining any methods in this class into call sites and
+  // therefore reducing the method count. However, extensions are best kept as
+  // public static final fields with initializers, so with their existence we
+  // won't bother with lazy initialization.
+  bool lazy_init = descriptor_->extension_count() == 0;
+
+  // Empty array
+  if (lazy_init) {
+    printer->Print(
+      "\n"
+      "private static volatile $classname$[] _emptyArray;\n"
+      "public static $classname$[] emptyArray() {\n"
+      "  // Lazily initializes the empty array\n"
+      "  if (_emptyArray == null) {\n"
+      "    synchronized (\n"
+      "        com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+      "      if (_emptyArray == null) {\n"
+      "        _emptyArray = new $classname$[0];\n"
+      "      }\n"
+      "    }\n"
+      "  }\n"
+      "  return _emptyArray;\n"
+      "}\n",
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "\n"
+      "private static final $classname$[] EMPTY_ARRAY = {};\n"
+      "public static $classname$[] emptyArray() {\n"
+      "  return EMPTY_ARRAY;\n"
+      "}\n",
+      "classname", descriptor_->name());
+  }
+
   // Integers for bit fields
   int totalInts = (field_generators_.total_bits() + 31) / 32;
   if (totalInts > 0) {
@@ -187,13 +215,57 @@ void MessageGenerator::Generate(io::Printer* printer) {
     }
   }
 
-  // Fields
+  // Fields and maybe their default values
   for (int i = 0; i < descriptor_->field_count(); i++) {
     printer->Print("\n");
     PrintFieldComment(printer, descriptor_->field(i));
-    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(
+        printer, lazy_init);
+  }
+
+  // Constructor, with lazy init code if needed
+  if (lazy_init && field_generators_.saved_defaults_needed()) {
+    printer->Print(
+      "\n"
+      "private static volatile boolean _classInitialized;\n"
+      "\n"
+      "public $classname$() {\n"
+      "  // Lazily initializes the field defaults\n"
+      "  if (!_classInitialized) {\n"
+      "    synchronized (\n"
+      "        com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+      "      if (!_classInitialized) {\n",
+      "classname", descriptor_->name());
+    printer->Indent();
+    printer->Indent();
+    printer->Indent();
+    printer->Indent();
+    for (int i = 0; i < descriptor_->field_count(); i++) {
+      field_generators_.get(descriptor_->field(i))
+          .GenerateInitSavedDefaultCode(printer);
+    }
+    printer->Outdent();
+    printer->Outdent();
+    printer->Outdent();
+    printer->Outdent();
+    printer->Print(
+      "        _classInitialized = true;\n"
+      "      }\n"
+      "    }\n"
+      "  }\n"
+      "  clear();\n"
+      "}\n");
+  } else {
+    printer->Print(
+      "\n"
+      "public $classname$() {\n"
+      "  clear();\n"
+      "}\n",
+      "classname", descriptor_->name());
   }
 
+  // Other methods in this class
+
   GenerateClear(printer);
 
   if (params_.generate_equals()) {

+ 3 - 3
src/google/protobuf/compiler/javanano/javanano_message_field.cc

@@ -82,7 +82,7 @@ MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
 MessageFieldGenerator::~MessageFieldGenerator() {}
 
 void MessageFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
   printer->Print(variables_,
     "public $type$ $name$;\n");
 }
@@ -158,7 +158,7 @@ RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& p
 RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
 
 void RepeatedMessageFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
   printer->Print(variables_,
     "public $type$[] $name$;\n");
 }
@@ -166,7 +166,7 @@ GenerateMembers(io::Printer* printer) const {
 void RepeatedMessageFieldGenerator::
 GenerateClearCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$ = $type$.EMPTY_ARRAY;\n");
+    "$name$ = $type$.emptyArray();\n");
 }
 
 void RepeatedMessageFieldGenerator::

+ 4 - 3
src/google/protobuf/compiler/javanano/javanano_message_field.h

@@ -46,11 +46,12 @@ namespace javanano {
 
 class MessageFieldGenerator : public FieldGenerator {
  public:
-  explicit MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  explicit MessageFieldGenerator(
+      const FieldDescriptor* descriptor, const Params& params);
   ~MessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
@@ -72,7 +73,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
   ~RepeatedMessageFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;

+ 68 - 26
src/google/protobuf/compiler/javanano/javanano_primitive_field.cc

@@ -251,35 +251,41 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params param
   } else {
     (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
   }
-  (*variables)["default"] = DefaultValue(params, descriptor);
-  (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
-  // For C++-string types (string and bytes), we might need to have
-  // the generated code do the unicode decoding (see comments in
-  // InternalNano.java for gory details.). We would like to do this
-  // once into a "private static final" field and re-use that from
+  // Deals with defaults. For C++-string types (string and bytes),
+  // we might need to have the generated code do the unicode decoding
+  // (see comments in InternalNano.java for gory details.). We would
+  // like to do this once into a static field and re-use that from
   // then on.
   if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
       !descriptor->default_value_string().empty() &&
       !params.use_reference_types_for_primitives()) {
-    string default_value;
     if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
-      default_value = strings::Substitute(
+      (*variables)["default"] = DefaultValue(params, descriptor);
+      (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+      (*variables)["default_constant_value"] = strings::Substitute(
           "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
           CEscape(descriptor->default_value_string()));
-      (*variables)["default_copy_if_needed"] = (*variables)["default"] + ".clone()";
+      (*variables)["default_copy_if_needed"] =
+          (*variables)["default"] + ".clone()";
+    } else if (AllAscii(descriptor->default_value_string())) {
+      // All chars are ASCII.  In this case directly referencing a
+      // CEscape()'d string literal works fine.
+      (*variables)["default"] =
+          "\"" + CEscape(descriptor->default_value_string()) + "\"";
+      (*variables)["default_copy_if_needed"] = (*variables)["default"];
     } else {
-      if (AllAscii(descriptor->default_value_string())) {
-        // All chars are ASCII.  In this case CEscape() works fine.
-        default_value = "\"" + CEscape(descriptor->default_value_string()) + "\"";
-      } else {
-        default_value = strings::Substitute(
-            "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
-            CEscape(descriptor->default_value_string()));
-      }
+      // Strings where some chars are non-ASCII. We need to save the
+      // default value.
+      (*variables)["default"] = DefaultValue(params, descriptor);
+      (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+      (*variables)["default_constant_value"] = strings::Substitute(
+          "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
+          CEscape(descriptor->default_value_string()));
       (*variables)["default_copy_if_needed"] = (*variables)["default"];
     }
-    (*variables)["default_constant_value"] = default_value;
   } else {
+    // Non-string, non-bytes field. Defaults are literals.
+    (*variables)["default"] = DefaultValue(params, descriptor);
     (*variables)["default_copy_if_needed"] = (*variables)["default"];
   }
   (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
@@ -306,12 +312,29 @@ PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
 
 PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
 
+bool PrimitiveFieldGenerator::SavedDefaultNeeded() const {
+  return variables_.find("default_constant") != variables_.end();
+}
+
+void PrimitiveFieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+  if (variables_.find("default_constant") != variables_.end()) {
+    printer->Print(variables_,
+      "$default_constant$ = $default_constant_value$;\n");
+  }
+}
+
 void PrimitiveFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
-  if (variables_.find("default_constant_value") != variables_.end()) {
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+  if (variables_.find("default_constant") != variables_.end()) {
     // Those primitive types that need a saved default.
-    printer->Print(variables_,
-      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
+    if (lazy_init) {
+      printer->Print(variables_,
+        "private static $type$ $default_constant$;\n");
+    } else {
+      printer->Print(variables_,
+        "private static final $type$ $default_constant$ =\n"
+        "    $default_constant_value$;\n");
+    }
   }
 
   printer->Print(variables_,
@@ -514,11 +537,30 @@ AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
 
 AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {}
 
+bool AccessorPrimitiveFieldGenerator::SavedDefaultNeeded() const {
+  return variables_.find("default_constant") != variables_.end();
+}
+
 void AccessorPrimitiveFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
-  if (variables_.find("default_constant_value") != variables_.end()) {
+GenerateInitSavedDefaultCode(io::Printer* printer) const {
+  if (variables_.find("default_constant") != variables_.end()) {
     printer->Print(variables_,
-      "private static final $type$ $default_constant$ = $default_constant_value$;\n");
+      "$default_constant$ = $default_constant_value$;\n");
+  }
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+  if (variables_.find("default_constant") != variables_.end()) {
+    // Those primitive types that need a saved default.
+    if (lazy_init) {
+      printer->Print(variables_,
+        "private static $type$ $default_constant$;\n");
+    } else {
+      printer->Print(variables_,
+        "private static final $type$ $default_constant$ =\n"
+        "    $default_constant_value$;\n");
+    }
   }
   printer->Print(variables_,
     "private $type$ $name$_;\n"
@@ -671,7 +713,7 @@ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params&
 RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
 
 void RepeatedPrimitiveFieldGenerator::
-GenerateMembers(io::Printer* printer) const {
+GenerateMembers(io::Printer* printer, bool /*unused init_defaults*/) const {
   printer->Print(variables_,
     "public $type$[] $name$;\n");
 }

+ 10 - 5
src/google/protobuf/compiler/javanano/javanano_primitive_field.h

@@ -46,11 +46,14 @@ namespace javanano {
 
 class PrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params &params);
+  explicit PrimitiveFieldGenerator(
+      const FieldDescriptor* descriptor, const Params &params);
   ~PrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  bool SavedDefaultNeeded() const;
+  void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
@@ -69,12 +72,14 @@ class PrimitiveFieldGenerator : public FieldGenerator {
 
 class AccessorPrimitiveFieldGenerator : public FieldGenerator {
  public:
-  explicit AccessorPrimitiveFieldGenerator( const FieldDescriptor* descriptor,
+  explicit AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
       const Params &params, int has_bit_index);
   ~AccessorPrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  bool SavedDefaultNeeded() const;
+  void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateSerializationCode(io::Printer* printer) const;
@@ -95,7 +100,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
   ~RepeatedPrimitiveFieldGenerator();
 
   // implements FieldGenerator ---------------------------------------
-  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMembers(io::Printer* printer, bool lazy_init) const;
   void GenerateClearCode(io::Printer* printer) const;
   void GenerateMergingCode(io::Printer* printer) const;
   void GenerateMergingCodeFromPacked(io::Printer* printer) const;