|  | @@ -35,6 +35,7 @@
 | 
	
		
			
				|  |  |  #include <google/protobuf/compiler/java/java_file.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <memory>
 | 
	
		
			
				|  |  | +#include <set>
 | 
	
		
			
				|  |  |  #ifndef _SHARED_PTR_H
 | 
	
		
			
				|  |  |  #include <google/protobuf/stubs/shared_ptr.h>
 | 
	
		
			
				|  |  |  #endif
 | 
	
	
		
			
				|  | @@ -62,6 +63,19 @@ namespace java {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +struct FieldDescriptorCompare {
 | 
	
		
			
				|  |  | +  bool operator ()(const FieldDescriptor* f1, const FieldDescriptor* f2) {
 | 
	
		
			
				|  |  | +    if(f1 == NULL) {
 | 
	
		
			
				|  |  | +      return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(f2 == NULL) {
 | 
	
		
			
				|  |  | +      return true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return f1->full_name() < f2->full_name();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef std::set<const FieldDescriptor*, FieldDescriptorCompare> FieldDescriptorSet;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Recursively searches the given message to collect extensions.
 | 
	
		
			
				|  |  |  // Returns true if all the extensions can be recognized. The extensions will be
 | 
	
	
		
			
				|  | @@ -69,7 +83,7 @@ namespace {
 | 
	
		
			
				|  |  |  // Returns false when there are unknown fields, in which case the data in the
 | 
	
		
			
				|  |  |  // extensions output parameter is not reliable and should be discarded.
 | 
	
		
			
				|  |  |  bool CollectExtensions(const Message& message,
 | 
	
		
			
				|  |  | -                       vector<const FieldDescriptor*>* extensions) {
 | 
	
		
			
				|  |  | +                       FieldDescriptorSet* extensions) {
 | 
	
		
			
				|  |  |    const Reflection* reflection = message.GetReflection();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // There are unknown fields that could be extensions, thus this call fails.
 | 
	
	
		
			
				|  | @@ -79,7 +93,7 @@ bool CollectExtensions(const Message& message,
 | 
	
		
			
				|  |  |    reflection->ListFields(message, &fields);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (int i = 0; i < fields.size(); i++) {
 | 
	
		
			
				|  |  | -    if (fields[i]->is_extension()) extensions->push_back(fields[i]);
 | 
	
		
			
				|  |  | +    if (fields[i]->is_extension()) extensions->insert(fields[i]);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) {
 | 
	
		
			
				|  |  |        if (fields[i]->is_repeated()) {
 | 
	
	
		
			
				|  | @@ -106,7 +120,7 @@ bool CollectExtensions(const Message& message,
 | 
	
		
			
				|  |  |  // in order to handle this case.
 | 
	
		
			
				|  |  |  void CollectExtensions(const FileDescriptorProto& file_proto,
 | 
	
		
			
				|  |  |                         const DescriptorPool& alternate_pool,
 | 
	
		
			
				|  |  | -                       vector<const FieldDescriptor*>* extensions,
 | 
	
		
			
				|  |  | +                       FieldDescriptorSet* extensions,
 | 
	
		
			
				|  |  |                         const string& file_data) {
 | 
	
		
			
				|  |  |    if (!CollectExtensions(file_proto, extensions)) {
 | 
	
		
			
				|  |  |      // There are unknown fields in the file_proto, which are probably
 | 
	
	
		
			
				|  | @@ -139,6 +153,36 @@ void CollectExtensions(const FileDescriptorProto& file_proto,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Our static initialization methods can become very, very large.
 | 
	
		
			
				|  |  | +// So large that if we aren't careful we end up blowing the JVM's
 | 
	
		
			
				|  |  | +// 64K bytes of bytecode/method. Fortunately, since these static
 | 
	
		
			
				|  |  | +// methods are executed only once near the beginning of a program,
 | 
	
		
			
				|  |  | +// there's usually plenty of stack space available and we can
 | 
	
		
			
				|  |  | +// extend our methods by simply chaining them to another method
 | 
	
		
			
				|  |  | +// with a tail call. This inserts the sequence call-next-method,
 | 
	
		
			
				|  |  | +// end this one, begin-next-method as needed.
 | 
	
		
			
				|  |  | +void MaybeRestartJavaMethod(io::Printer* printer,
 | 
	
		
			
				|  |  | +                            int *bytecode_estimate,
 | 
	
		
			
				|  |  | +                            int *method_num,
 | 
	
		
			
				|  |  | +                            const char *chain_statement,
 | 
	
		
			
				|  |  | +                            const char *method_decl) {
 | 
	
		
			
				|  |  | + 
 | 
	
		
			
				|  |  | +  // The goal here is to stay under 64K bytes of jvm bytecode/method,
 | 
	
		
			
				|  |  | +  // since otherwise we hit a hardcoded limit in the jvm and javac will
 | 
	
		
			
				|  |  | +  // then fail with the error "code too large". This limit lets our
 | 
	
		
			
				|  |  | +  // estimates be off by a factor of two and still we're okay.
 | 
	
		
			
				|  |  | +  static const int bytesPerMethod = 1<<15;  // aka 32K
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if ((*bytecode_estimate) > bytesPerMethod) {
 | 
	
		
			
				|  |  | +    ++(*method_num);
 | 
	
		
			
				|  |  | +    printer->Print(chain_statement, "method_num", SimpleItoa(*method_num));
 | 
	
		
			
				|  |  | +    printer->Outdent();
 | 
	
		
			
				|  |  | +    printer->Print("}\n");
 | 
	
		
			
				|  |  | +    printer->Print(method_decl, "method_num", SimpleItoa(*method_num));
 | 
	
		
			
				|  |  | +    printer->Indent();
 | 
	
		
			
				|  |  | +    *bytecode_estimate = 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  }  // namespace
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -270,9 +314,16 @@ void FileGenerator::Generate(io::Printer* printer) {
 | 
	
		
			
				|  |  |      printer->Print(
 | 
	
		
			
				|  |  |        "static {\n");
 | 
	
		
			
				|  |  |      printer->Indent();
 | 
	
		
			
				|  |  | +    int bytecode_estimate = 0;
 | 
	
		
			
				|  |  | +    int method_num = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      for (int i = 0; i < file_->message_type_count(); i++) {
 | 
	
		
			
				|  |  | -      message_generators_[i]->GenerateStaticVariableInitializers(printer);
 | 
	
		
			
				|  |  | +      bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
 | 
	
		
			
				|  |  | +      MaybeRestartJavaMethod(
 | 
	
		
			
				|  |  | +        printer,
 | 
	
		
			
				|  |  | +        &bytecode_estimate, &method_num,
 | 
	
		
			
				|  |  | +        "_clinit_autosplit_$method_num$();\n",
 | 
	
		
			
				|  |  | +        "private static void _clinit_autosplit_$method_num$() {\n");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      printer->Outdent();
 | 
	
	
		
			
				|  | @@ -303,12 +354,24 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
 | 
	
		
			
				|  |  |    SharedCodeGenerator shared_code_generator(file_);
 | 
	
		
			
				|  |  |    shared_code_generator.GenerateDescriptors(printer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  int bytecode_estimate = 0;
 | 
	
		
			
				|  |  | +  int method_num = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (int i = 0; i < file_->message_type_count(); i++) {
 | 
	
		
			
				|  |  | -    message_generators_[i]->GenerateStaticVariableInitializers(printer);
 | 
	
		
			
				|  |  | +    bytecode_estimate += message_generators_[i]->GenerateStaticVariableInitializers(printer);
 | 
	
		
			
				|  |  | +    MaybeRestartJavaMethod(
 | 
	
		
			
				|  |  | +      printer,
 | 
	
		
			
				|  |  | +      &bytecode_estimate, &method_num,
 | 
	
		
			
				|  |  | +      "_clinit_autosplit_dinit_$method_num$();\n",
 | 
	
		
			
				|  |  | +      "private static void _clinit_autosplit_dinit_$method_num$() {\n");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    for (int i = 0; i < file_->extension_count(); i++) {
 | 
	
		
			
				|  |  | -    extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
 | 
	
		
			
				|  |  | +    bytecode_estimate += extension_generators_[i]->GenerateNonNestedInitializationCode(printer);
 | 
	
		
			
				|  |  | +    MaybeRestartJavaMethod(
 | 
	
		
			
				|  |  | +      printer,
 | 
	
		
			
				|  |  | +      &bytecode_estimate, &method_num,
 | 
	
		
			
				|  |  | +      "_clinit_autosplit_dinit_$method_num$();\n",
 | 
	
		
			
				|  |  | +      "private static void _clinit_autosplit_dinit_$method_num$() {\n");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // Proto compiler builds a DescriptorPool, which holds all the descriptors to
 | 
	
	
		
			
				|  | @@ -330,7 +393,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
 | 
	
		
			
				|  |  |    file_->CopyTo(&file_proto);
 | 
	
		
			
				|  |  |    string file_data;
 | 
	
		
			
				|  |  |    file_proto.SerializeToString(&file_data);
 | 
	
		
			
				|  |  | -  vector<const FieldDescriptor*> extensions;
 | 
	
		
			
				|  |  | +  FieldDescriptorSet extensions;
 | 
	
		
			
				|  |  |    CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (extensions.size() > 0) {
 | 
	
	
		
			
				|  | @@ -339,10 +402,17 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable(
 | 
	
		
			
				|  |  |      printer->Print(
 | 
	
		
			
				|  |  |        "com.google.protobuf.ExtensionRegistry registry =\n"
 | 
	
		
			
				|  |  |        "    com.google.protobuf.ExtensionRegistry.newInstance();\n");
 | 
	
		
			
				|  |  | -    for (int i = 0; i < extensions.size(); i++) {
 | 
	
		
			
				|  |  | +    FieldDescriptorSet::iterator it;
 | 
	
		
			
				|  |  | +    for (it = extensions.begin(); it != extensions.end(); it++) {
 | 
	
		
			
				|  |  |        google::protobuf::scoped_ptr<ExtensionGenerator> generator(
 | 
	
		
			
				|  |  | -          generator_factory_->NewExtensionGenerator(extensions[i]));
 | 
	
		
			
				|  |  | -      generator->GenerateRegistrationCode(printer);
 | 
	
		
			
				|  |  | +          generator_factory_->NewExtensionGenerator(*it));
 | 
	
		
			
				|  |  | +      bytecode_estimate += generator->GenerateRegistrationCode(printer);
 | 
	
		
			
				|  |  | +      MaybeRestartJavaMethod(
 | 
	
		
			
				|  |  | +        printer,
 | 
	
		
			
				|  |  | +        &bytecode_estimate, &method_num,
 | 
	
		
			
				|  |  | +        "_clinit_autosplit_dinit_$method_num$(registry);\n",
 | 
	
		
			
				|  |  | +        "private static void _clinit_autosplit_dinit_$method_num$(\n"
 | 
	
		
			
				|  |  | +        "    com.google.protobuf.ExtensionRegistry registry) {\n");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      printer->Print(
 | 
	
		
			
				|  |  |        "com.google.protobuf.Descriptors.FileDescriptor\n"
 | 
	
	
		
			
				|  | @@ -394,7 +464,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer*
 | 
	
		
			
				|  |  |    file_->CopyTo(&file_proto);
 | 
	
		
			
				|  |  |    string file_data;
 | 
	
		
			
				|  |  |    file_proto.SerializeToString(&file_data);
 | 
	
		
			
				|  |  | -  vector<const FieldDescriptor*> extensions;
 | 
	
		
			
				|  |  | +  FieldDescriptorSet extensions;
 | 
	
		
			
				|  |  |    CollectExtensions(file_proto, *file_->pool(), &extensions, file_data);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (extensions.size() > 0) {
 |