Replace the fake ParseMessage/ParseGroup function calls in with ones that accept a lambda. It allows the callers to drop the mock "message" types that only exist to have an _InternalParse function in them. It also gives more freedom to the caller to do things like force inlining when it matters.

Do more inlining in certain callers of ParseLoop to avoid the extra stack frame.
This reduces the overall cost of maintaining the stack frames in functions like FastMtS1.

PiperOrigin-RevId: 590943926
pull/15056/head
Protobuf Team Bot 12 months ago committed by Copybara-Service
parent 34908e2898
commit f0a8c474cc
  1. 3
      src/google/protobuf/generated_message_tctable_impl.h
  2. 48
      src/google/protobuf/generated_message_tctable_lite.cc
  3. 76
      src/google/protobuf/parse_context.h

@ -394,6 +394,9 @@ class PROTOBUF_EXPORT TcParser final {
static const char* ParseLoop(MessageLite* msg, const char* ptr,
ParseContext* ctx,
const TcParseTableBase* table);
static const char* ParseLoopInlined(MessageLite* msg, const char* ptr,
ParseContext* ctx,
const TcParseTableBase* table);
// Functions referenced by generated fast tables (numeric types):
// F: fixed V: varint Z: zigzag

@ -73,7 +73,7 @@ const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) {
// Core fast parsing implementation:
//////////////////////////////////////////////////////////////////////////////
PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ParseLoopInlined(
MessageLite* msg, const char* ptr, ParseContext* ctx,
const TcParseTableBase* table) {
// Note: TagDispatch uses a dispatch table at "&table->fast_entries".
@ -98,6 +98,12 @@ PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
return ptr;
}
PROTOBUF_NOINLINE const char* TcParser::ParseLoop(
MessageLite* msg, const char* ptr, ParseContext* ctx,
const TcParseTableBase* table) {
return ParseLoopInlined(msg, ptr, ctx, table);
}
// On the fast path, a (matching) 1-byte tag already has the decoded value.
static uint32_t FastDecodeTag(uint8_t coded_tag) {
return coded_tag;
@ -387,11 +393,12 @@ inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl(
if (field == nullptr) {
field = inner_table->default_instance->New(msg->GetArena());
}
if (group_coding) {
return ctx->ParseGroup<TcParser>(field, ptr, FastDecodeTag(saved_tag),
inner_table);
}
return ctx->ParseMessage<TcParser>(field, ptr, inner_table);
const auto inner_loop = [&](const char* ptr) {
return ParseLoopInlined(field, ptr, ctx, inner_table);
};
return group_coding ? ctx->ParseGroupInlined(ptr, FastDecodeTag(saved_tag),
inner_loop)
: ctx->ParseLengthDelimitedInlined(ptr, inner_loop);
} else {
if (field == nullptr) {
const MessageLite* default_instance =
@ -474,12 +481,12 @@ inline PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedParseMessageAuxImpl(
ptr += sizeof(TagType);
MessageLite* submsg = field.AddMessage(default_instance);
if (aux_is_table) {
if (group_coding) {
ptr = ctx->ParseGroup<TcParser>(submsg, ptr,
FastDecodeTag(expected_tag), aux.table);
} else {
ptr = ctx->ParseMessage<TcParser>(submsg, ptr, aux.table);
}
const auto inner_loop = [&](const char* ptr) {
return ParseLoopInlined(submsg, ptr, ctx, aux.table);
};
ptr = group_coding ? ctx->ParseGroupInlined(
ptr, FastDecodeTag(expected_tag), inner_loop)
: ctx->ParseLengthDelimitedInlined(ptr, inner_loop);
} else {
if (group_coding) {
ptr = ctx->ParseGroup(submsg, ptr, FastDecodeTag(expected_tag));
@ -2369,10 +2376,11 @@ PROTOBUF_NOINLINE const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) {
if (need_init || field == nullptr) {
field = inner_table->default_instance->New(msg->GetArena());
}
if (is_group) {
return ctx->ParseGroup<TcParser>(field, ptr, decoded_tag, inner_table);
}
return ctx->ParseMessage<TcParser>(field, ptr, inner_table);
const auto inner_loop = [&](const char* ptr) {
return ParseLoop(field, ptr, ctx, inner_table);
};
return is_group ? ctx->ParseGroupInlined(ptr, decoded_tag, inner_loop)
: ctx->ParseLengthDelimitedInlined(ptr, inner_loop);
} else {
if (need_init || field == nullptr) {
const MessageLite* def;
@ -2428,9 +2436,11 @@ const char* TcParser::MpRepeatedMessageOrGroup(PROTOBUF_TC_PARAM_DECL) {
uint32_t next_tag;
do {
MessageLite* value = field.AddMessage(default_instance);
ptr = is_group ? ctx->ParseGroup<TcParser>(value, ptr2, decoded_tag,
inner_table)
: ctx->ParseMessage<TcParser>(value, ptr2, inner_table);
const auto inner_loop = [&](const char* ptr) {
return ParseLoop(value, ptr, ctx, inner_table);
};
ptr = is_group ? ctx->ParseGroupInlined(ptr2, decoded_tag, inner_loop)
: ctx->ParseLengthDelimitedInlined(ptr2, inner_loop);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) goto error;
if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) goto parse_loop;
ptr2 = ReadTag(ptr, &next_tag);

@ -494,34 +494,18 @@ class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
const char* ParseMessage(MessageLite* msg, const char* ptr);
// This overload supports those few cases where ParseMessage is called
// on a class that is not actually a proto message.
// TODO: Eliminate this use case.
template <typename T,
typename std::enable_if<!std::is_base_of<MessageLite, T>::value,
bool>::type = true>
PROTOBUF_NODISCARD const char* ParseMessage(T* msg, const char* ptr);
// Read the length prefix, push the new limit, call the func(ptr), and then
// pop the limit. Useful for situations that don't value an actual message,
// like map entries.
// pop the limit. Useful for situations that don't have an actual message.
template <typename Func>
PROTOBUF_NODISCARD const char* ParseLengthDelimitedInlined(const char*,
const Func& func);
template <typename TcParser, typename Table>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
MessageLite* msg, const char* ptr, const Table* table) {
LimitToken old;
ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = TcParser::ParseLoop(msg, ptr, this, table);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
// Push the recursion depth, call the func(ptr), and then pop depth. Useful
// for situations that don't have an actual message.
template <typename Func>
PROTOBUF_NODISCARD const char* ParseGroupInlined(const char* ptr,
uint32_t start_tag,
const Func& func);
template <typename T>
PROTOBUF_NODISCARD PROTOBUF_NDEBUG_INLINE const char* ParseGroup(
@ -541,24 +525,6 @@ class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
return ptr;
}
template <typename TcParser, typename Table>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char* ParseGroup(
MessageLite* msg, const char* ptr, uint32_t tag, const Table* table) {
if (--depth_ < 0) return nullptr;
group_depth_++;
auto old_depth = depth_;
auto old_group_depth = group_depth_;
ptr = TcParser::ParseLoop(msg, ptr, this, table);
if (ptr != nullptr) {
ABSL_DCHECK_EQ(old_depth, depth_);
ABSL_DCHECK_EQ(old_group_depth, group_depth_);
}
group_depth_--;
depth_++;
if (PROTOBUF_PREDICT_FALSE(!ConsumeEndGroup(tag))) return nullptr;
return ptr;
}
private:
// Out-of-line routine to save space in ParseContext::ParseMessage<T>
// LimitToken old;
@ -1105,15 +1071,14 @@ inline int32_t ReadVarintZigZag32(const char** p) {
return WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
}
template <typename T, typename std::enable_if<
!std::is_base_of<MessageLite, T>::value, bool>::type>
PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
const char* ptr) {
template <typename Func>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
ParseContext::ParseLengthDelimitedInlined(const char* ptr, const Func& func) {
LimitToken old;
ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = msg->_InternalParse(ptr, this);
PROTOBUF_ALWAYS_INLINE_CALL ptr = func(ptr);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
if (!PopLimit(std::move(old))) return nullptr;
@ -1122,13 +1087,20 @@ PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
template <typename Func>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
ParseContext::ParseLengthDelimitedInlined(const char* ptr, const Func& func) {
LimitToken old;
ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
if (ptr == nullptr) return ptr;
ParseContext::ParseGroupInlined(const char* ptr, uint32_t start_tag,
const Func& func) {
if (--depth_ < 0) return nullptr;
group_depth_++;
auto old_depth = depth_;
auto old_group_depth = group_depth_;
PROTOBUF_ALWAYS_INLINE_CALL ptr = func(ptr);
if (ptr != nullptr) {
ABSL_DCHECK_EQ(old_depth, depth_);
ABSL_DCHECK_EQ(old_group_depth, group_depth_);
}
group_depth_--;
depth_++;
if (!PopLimit(std::move(old))) return nullptr;
if (PROTOBUF_PREDICT_FALSE(!ConsumeEndGroup(start_tag))) return nullptr;
return ptr;
}

Loading…
Cancel
Save