Reduce stack frame size of `TextFormat::Printer::PrintUnknownFields` by offloading `std::string` temporaries into a separate function.

PiperOrigin-RevId: 513627351
pull/12119/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 34b7d583bd
commit 0a9282b82b
  1. 27
      src/google/protobuf/text_format.cc
  2. 7
      src/google/protobuf/text_format.h
  3. 17
      src/google/protobuf/text_format_unittest.cc

@ -2699,18 +2699,23 @@ void TextFormat::Printer::PrintFieldValue(const Message& message,
return Parser().ParseFieldValueFromString(input, field, message);
}
template <typename... T>
PROTOBUF_NOINLINE void TextFormat::OutOfLinePrintString(
BaseTextGenerator* generator, const T&... values) {
generator->PrintString(absl::StrCat(values...));
}
void TextFormat::Printer::PrintUnknownFields(
const UnknownFieldSet& unknown_fields, BaseTextGenerator* generator,
int recursion_budget) const {
for (int i = 0; i < unknown_fields.field_count(); i++) {
const UnknownField& field = unknown_fields.field(i);
std::string field_number = absl::StrCat(field.number());
switch (field.type()) {
case UnknownField::TYPE_VARINT:
generator->PrintString(field_number);
OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ");
generator->PrintString(absl::StrCat(field.varint()));
OutOfLinePrintString(generator, field.varint());
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@ -2718,10 +2723,10 @@ void TextFormat::Printer::PrintUnknownFields(
}
break;
case UnknownField::TYPE_FIXED32: {
generator->PrintString(field_number);
OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ", "0x");
generator->PrintString(
absl::StrCat(absl::Hex(field.fixed32(), absl::kZeroPad8)));
OutOfLinePrintString(generator,
absl::Hex(field.fixed32(), absl::kZeroPad8));
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@ -2730,10 +2735,10 @@ void TextFormat::Printer::PrintUnknownFields(
break;
}
case UnknownField::TYPE_FIXED64: {
generator->PrintString(field_number);
OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ", "0x");
generator->PrintString(
absl::StrCat(absl::Hex(field.fixed64(), absl::kZeroPad16)));
OutOfLinePrintString(generator,
absl::Hex(field.fixed64(), absl::kZeroPad16));
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@ -2742,7 +2747,7 @@ void TextFormat::Printer::PrintUnknownFields(
break;
}
case UnknownField::TYPE_LENGTH_DELIMITED: {
generator->PrintString(field_number);
OutOfLinePrintString(generator, field.number());
const std::string& value = field.length_delimited();
// We create a CodedInputStream so that we can adhere to our recursion
// budget when we attempt to parse the data. UnknownFieldSet parsing is
@ -2783,7 +2788,7 @@ void TextFormat::Printer::PrintUnknownFields(
break;
}
case UnknownField::TYPE_GROUP:
generator->PrintString(field_number);
OutOfLinePrintString(generator, field.number());
if (single_line_mode_) {
generator->PrintMaybeWithMarker(MarkerToken(), " ", "{ ");
} else {

@ -141,7 +141,7 @@ class PROTOBUF_EXPORT TextFormat {
// Print text to the output stream.
virtual void Print(const char* text, size_t size) = 0;
void PrintString(const std::string& str) { Print(str.data(), str.size()); }
void PrintString(absl::string_view str) { Print(str.data(), str.size()); }
template <size_t n>
void PrintLiteral(const char (&text)[n]) {
@ -724,6 +724,11 @@ class PROTOBUF_EXPORT TextFormat {
ParseLocationRange location);
static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
const FieldDescriptor* field);
// To reduce stack frame bloat we use an out-of-line function to print
// strings. This avoid local std::string temporaries.
template <typename... T>
static void OutOfLinePrintString(BaseTextGenerator* generator,
const T&... values);
};

@ -297,6 +297,22 @@ TEST_F(TextFormatTest, PrintUnknownFields) {
message.DebugString());
}
TEST_F(TextFormatTest, PrintUnknownFieldsDeepestStackWorks) {
// Test printing of unknown fields in a message.
unittest::TestEmptyMessage message;
UnknownFieldSet* unknown_fields = message.mutable_unknown_fields();
for (int i = 0; i < 200; ++i) {
unknown_fields = unknown_fields->AddGroup(1);
}
unknown_fields->AddVarint(2, 100);
std::string str;
EXPECT_TRUE(TextFormat::PrintToString(message, &str));
}
TEST_F(TextFormatTest, PrintUnknownFieldsHidden) {
// Test printing of unknown fields in a message when suppressed.
@ -2350,6 +2366,7 @@ TEST(TextFormatFloatingPointTest, PreservesNegative0) {
std::signbit(out_message.optional_double()));
}
} // namespace text_format_unittest
} // namespace protobuf
} // namespace google

Loading…
Cancel
Save