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