|
|
|
@ -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) { |
|
|
|
|