From 76195058e25d19fc918996d55d3ad69ee55cb77e Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Wed, 6 Jan 2016 18:06:43 -0800 Subject: Patch internal change 111557819. Defer calls to mutable_unknown_fields() until it is actually required to save memory for C++ lite runtime. Change-Id: Ica9c1fd276cdb164942d1e7b6e098c83ee3ffdc5 --- src/google/protobuf/compiler/cpp/cpp_message.cc | 26 +++++-- src/google/protobuf/io/coded_stream.cc | 18 +++++ src/google/protobuf/io/coded_stream.h | 1 + .../protobuf/io/zero_copy_stream_impl_lite.cc | 31 ++++++++ .../protobuf/io/zero_copy_stream_impl_lite.h | 24 +++++++ src/google/protobuf/stubs/callback.h | 83 ++++++++++++++++++++++ 6 files changed, 179 insertions(+), 4 deletions(-) (limited to 'src/google') diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index af409c29..8304ebbd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -1772,6 +1772,17 @@ GenerateShutdownCode(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + // mutable_unknown_fields wrapper function for LazyStringOutputStream + // callback. + if (!UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "static ::std::string* MutableUnknownFieldsFor$classname$(\n" + " $classname$* ptr) {\n" + " return ptr->mutable_unknown_fields();\n" + "}\n" + "\n", + "classname", classname_); + } if (IsAnyMessage(descriptor_)) { printer->Print( "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" @@ -2814,7 +2825,9 @@ GenerateMergeFrom(io::Printer* printer) { "}\n"); } else { printer->Print( - "mutable_unknown_fields()->append(from.unknown_fields());\n"); + "if (!from.unknown_fields().empty()) {\n" + " mutable_unknown_fields()->append(from.unknown_fields());\n" + "}\n"); } } @@ -2889,11 +2902,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "classname", classname_); if (!UseUnknownFieldSet(descriptor_->file())) { + // Use LazyStringOutputString to avoid initializing unknown fields string + // unless it is actually needed. For the same reason, disable eager refresh + // on the CodedOutputStream. printer->Print( - " ::google::protobuf::io::StringOutputStream unknown_fields_string(\n" - " mutable_unknown_fields());\n" + " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" + " ::google::protobuf::internal::NewPermanentCallback(\n" + " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" - " &unknown_fields_string);\n"); + " &unknown_fields_string, false);\n", + "classname", classname_); } printer->Print( diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 4bcd354f..e3a34d0a 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -629,6 +629,24 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) had_error_ = false; } +CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output, + bool do_eager_refresh) + : output_(output), + buffer_(NULL), + buffer_size_(0), + total_bytes_(0), + had_error_(false), + aliasing_enabled_(false) { + if (do_eager_refresh) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); + // The Refresh() may have failed. If the client doesn't write any data, + // though, don't consider this an error. If the client does write data, then + // another Refresh() will be attempted and it will set the error once again. + had_error_ = false; + } +} + CodedOutputStream::~CodedOutputStream() { Trim(); } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 2da096c5..020f20c7 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -666,6 +666,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { public: // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. explicit CodedOutputStream(ZeroCopyOutputStream* output); + CodedOutputStream(ZeroCopyOutputStream* output, bool do_eager_refresh); // Destroy the CodedOutputStream and position the underlying // ZeroCopyOutputStream immediately after the last byte written. diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 686e63f2..083beca4 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -157,6 +157,7 @@ StringOutputStream::~StringOutputStream() { } bool StringOutputStream::Next(void** data, int* size) { + GOOGLE_CHECK_NE(NULL, target_); int old_size = target_->size(); // Grow the string. @@ -188,14 +189,44 @@ bool StringOutputStream::Next(void** data, int* size) { void StringOutputStream::BackUp(int count) { GOOGLE_CHECK_GE(count, 0); + GOOGLE_CHECK_NE(NULL, target_); GOOGLE_CHECK_LE(count, target_->size()); target_->resize(target_->size() - count); } int64 StringOutputStream::ByteCount() const { + GOOGLE_CHECK_NE(NULL, target_); return target_->size(); } +void StringOutputStream::SetString(string* target) { + target_ = target; +} + +// =================================================================== + +LazyStringOutputStream::LazyStringOutputStream( + ResultCallback* callback) + : StringOutputStream(NULL), + callback_(GOOGLE_CHECK_NOTNULL(callback)), + string_is_set_(false) { +} + +LazyStringOutputStream::~LazyStringOutputStream() { +} + +bool LazyStringOutputStream::Next(void** data, int* size) { + if (!string_is_set_) { + SetString(callback_->Run()); + string_is_set_ = true; + } + return StringOutputStream::Next(data, size); +} + +int64 LazyStringOutputStream::ByteCount() const { + return string_is_set_ ? StringOutputStream::ByteCount() : 0; +} + // =================================================================== CopyingInputStream::~CopyingInputStream() {} diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index a598ef2e..1c397dea 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -148,6 +148,9 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { void BackUp(int count); int64 ByteCount() const; + protected: + void SetString(string* target); + private: static const int kMinimumSize = 16; @@ -156,6 +159,27 @@ class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream); }; +// LazyStringOutputStream is a StringOutputStream with lazy acquisition of +// the output string from a callback. The string is owned externally, and not +// deleted in the stream destructor. +class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream { + public: + // Callback should be permanent (non-self-deleting). Ownership is transferred + // to the LazyStringOutputStream. + explicit LazyStringOutputStream(ResultCallback* callback); + ~LazyStringOutputStream(); + + // implements ZeroCopyOutputStream, overriding StringOutputStream ----------- + bool Next(void** data, int* size); + int64 ByteCount() const; + + private: + const scoped_ptr > callback_; + bool string_is_set_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream); +}; + // Note: There is no StringInputStream. Instead, just create an // ArrayInputStream as follows: // ArrayInputStream input(str.data(), str.size()); diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h index 6da530d3..1ba6ea7a 100644 --- a/src/google/protobuf/stubs/callback.h +++ b/src/google/protobuf/stubs/callback.h @@ -78,6 +78,18 @@ class LIBPROTOBUF_EXPORT Closure { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure); }; +template +class LIBPROTOBUF_EXPORT ResultCallback { + public: + ResultCallback() {} + virtual ~ResultCallback() {} + + virtual R Run() = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ResultCallback); +}; + template class LIBPROTOBUF_EXPORT ResultCallback1 { public: @@ -240,6 +252,50 @@ class MethodClosure2 : public Closure { Arg2 arg2_; }; +template +class FunctionResultCallback_0_0 : public ResultCallback { + public: + typedef R (*FunctionType)(); + + FunctionResultCallback_0_0(FunctionType function, bool self_deleting) + : function_(function), self_deleting_(self_deleting) {} + ~FunctionResultCallback_0_0() {} + + R Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + R result = function_(); + if (needs_delete) delete this; + return result; + } + + private: + FunctionType function_; + bool self_deleting_; +}; + +template +class FunctionResultCallback_1_0 : public ResultCallback { + public: + typedef R (*FunctionType)(P1); + + FunctionResultCallback_1_0(FunctionType function, bool self_deleting, + P1 p1) + : function_(function), self_deleting_(self_deleting), p1_(p1) {} + ~FunctionResultCallback_1_0() {} + + R Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + R result = function_(p1_); + if (needs_delete) delete this; + return result; + } + + private: + FunctionType function_; + bool self_deleting_; + P1 p1_; +}; + template class FunctionResultCallback_0_1 : public ResultCallback1 { public: @@ -408,6 +464,33 @@ inline Closure* NewPermanentCallback( object, method, false, arg1, arg2); } +// See ResultCallback +template +inline ResultCallback* NewCallback(R (*function)()) { + return new internal::FunctionResultCallback_0_0(function, true); +} + +// See ResultCallback +template +inline ResultCallback* NewPermanentCallback(R (*function)()) { + return new internal::FunctionResultCallback_0_0(function, false); +} + +// See ResultCallback +template +inline ResultCallback* NewCallback(R (*function)(P1), P1 p1) { + return new internal::FunctionResultCallback_1_0( + function, true, p1); +} + +// See ResultCallback +template +inline ResultCallback* NewPermanentCallback( + R (*function)(P1), P1 p1) { + return new internal::FunctionResultCallback_1_0( + function, false, p1); +} + // See ResultCallback1 template inline ResultCallback1* NewCallback(R (*function)(A1)) { -- cgit v1.2.3