From d37d46dfbcedadeb439ad0367f8afcf8867dca43 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Sat, 25 Apr 2009 02:53:47 +0000 Subject: Integrate recent changes from Google-internal code tree. See CHANGES.txt for details. --- src/google/protobuf/compiler/cpp/cpp_file.cc | 152 ++++++++++++++++++++------- 1 file changed, 115 insertions(+), 37 deletions(-) (limited to 'src/google/protobuf/compiler/cpp/cpp_file.cc') diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 6487979f..dcc48552 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -143,17 +143,20 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Open namespace. GenerateNamespaceOpeners(printer); - // Forward-declare the AssignGlobalDescriptors function, so that we can - // declare it to be a friend of each class. + // Forward-declare the AddDescriptors and AssignDescriptors functions, so + // that we can declare them to be friends of each class. printer->Print( "\n" "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$ $builddescriptorsname$();\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(\n" - " ::google::protobuf::FileDescriptor* file);\n" - "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "void $dllexport_decl$ $adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "dllexport_decl", dllexport_decl_); + printer->Print( + // Note that we don't put dllexport_decl on this because it is only called + // by the .pb.cc file in which it is defined. + "void $assigndescriptorsname$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); // Generate forward declarations of classes. for (int i = 0; i < file_->message_type_count(); i++) { @@ -232,6 +235,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "\n" "#include \"$basename$.pb.h\"\n" + "#include \n" "#include \n" "#include \n" "#include \n" @@ -296,23 +300,46 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { - // BuildDescriptors() is a file-level procedure which initializes all of - // the Descriptor objects for this file. It runs the first time one of the - // descriptors is accessed. This will always be at static initialization - // time, because every message has a statically-initialized default instance, - // and the constructor for a message class accesses its descriptor. See the - // constructor and the descriptor() method of message classes. + // AddDescriptors() is a file-level procedure which adds the encoded + // FileDescriptorProto for this .proto file to the global DescriptorPool + // for generated files (DescriptorPool::generated_pool()). It always runs + // at static initialization time, so all files will be registered before + // main() starts. This procedure also constructs default instances and + // registers extensions. // - // We also construct the reflection object for each class inside - // BuildDescriptors(). + // Its sibling, AssignDescriptors(), actually pulls the compiled + // FileDescriptor from the DescriptorPool and uses it to populate all of + // the global variables which store pointers to the descriptor objects. + // It also constructs the reflection objects. It is called the first time + // anyone calls descriptor() or GetReflection() on one of the types defined + // in the file. - // First we generate a method to assign the global descriptors. printer->Print( "\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(" - "const ::google::protobuf::FileDescriptor* file) {\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "void $assigndescriptorsname$() {\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); printer->Indent(); + + // Make sure the file has found its way into the pool. If a descriptor + // is requested *during* static init then AddDescriptors() may not have + // been called yet, so we call it manually. Note that it's fine if + // AddDescriptors() is called multiple times. + printer->Print( + "$adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + + // Get the file's descriptor from the pool. + printer->Print( + "const ::google::protobuf::FileDescriptor* file =\n" + " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n" + " \"$filename$\");\n" + // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file" + // being unused when compiling an empty .proto file. + "GOOGLE_CHECK(file != NULL);\n", + "filename", file_->name()); + + // Go through all the stuff defined in this file and generated code to + // assign the global descriptor pointers based on the file descriptor. for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->GenerateDescriptorInitializer(printer, i); } @@ -322,29 +349,63 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->service_count(); i++) { service_generators_[i]->GenerateDescriptorInitializer(printer, i); } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + // ----------------------------------------------------------------- + + // protobuf_AssignDescriptorsOnce(): The first time it is called, calls + // AssignDescriptors(). All later times, waits for the first call to + // complete and then returns. + printer->Print( + "namespace {\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "inline void protobuf_AssignDescriptorsOnce() {\n" + " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" + " &$assigndescriptorsname$);\n" + "}\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + + // protobuf_RegisterTypes(): Calls + // MessageFactory::InternalRegisterGeneratedType() for each message type. + printer->Print( + "void protobuf_RegisterTypes() {\n" + " protobuf_AssignDescriptorsOnce();\n"); + printer->Indent(); + for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + message_generators_[i]->GenerateTypeRegistrations(printer); } printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "\n" + "} // namespace\n"); + // ----------------------------------------------------------------- + + // Now generate the AddDescriptors() function. printer->Print( "\n" - "void $builddescriptorsname$() {\n" + "void $adddescriptorsname$() {\n" + // We don't need any special synchronization here because this code is + // called at static init time before any threads exist. " static bool already_here = false;\n" " if (already_here) return;\n" " already_here = true;\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - " ::google::protobuf::DescriptorPool* pool =\n" - " ::google::protobuf::DescriptorPool::internal_generated_pool();\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); printer->Indent(); - // Call the BuildDescriptors() methods for all of our dependencies, to make - // sure they get initialized first. + // Call the AddDescriptors() methods for all of our dependencies, to make + // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. @@ -355,10 +416,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Print("$name$::", "name", dependency_package_parts[i]); } - // Call its BuildDescriptors function. + // Call its AddDescriptors function. printer->Print( "$name$();\n", - "name", GlobalBuildDescriptorsName(dependency->name())); + "name", GlobalAddDescriptorsName(dependency->name())); } // Embed the descriptor. We simply serialize the entire FileDescriptorProto @@ -370,7 +431,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { file_proto.SerializeToString(&file_data); printer->Print( - "pool->InternalBuildGeneratedFile("); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); // Only write 40 bytes per line. static const int kBytesPerLine = 40; @@ -379,24 +440,41 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", CEscape(file_data.substr(i, kBytesPerLine))); } printer->Print( - ", $size$,\n" - "&$builddescriptorsname$_AssignGlobalDescriptors);\n", - "size", SimpleItoa(file_data.size()), - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + ", $size$);\n", + "size", SimpleItoa(file_data.size())); + + // Call MessageFactory::InternalRegisterGeneratedFile(). + printer->Print( + "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" + " \"$filename$\", &protobuf_RegisterTypes);\n", + "filename", file_->name()); + + // Allocate and initialize default instances. This can't be done lazily + // since default instances are returned by simple accessors and are used with + // extensions. Speaking of which, we also register extensions at this time. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } printer->Outdent(); printer->Print( "}\n" "\n" - "// Force BuildDescriptors() to be called at static initialization time.\n" + "// Force AddDescriptors() to be called at static initialization time.\n" "struct StaticDescriptorInitializer_$filename$ {\n" " StaticDescriptorInitializer_$filename$() {\n" - " $builddescriptorsname$();\n" + " $adddescriptorsname$();\n" " }\n" "} static_descriptor_initializer_$filename$_;\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename", FilenameIdentifier(file_->name())); } -- cgit v1.2.3