generated_message_tctable_impl.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
  31. #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
  32. #include <cstdint>
  33. #include <type_traits>
  34. #include <google/protobuf/parse_context.h>
  35. #include <google/protobuf/extension_set.h>
  36. #include <google/protobuf/generated_message_tctable_decl.h>
  37. #include <google/protobuf/message_lite.h>
  38. #include <google/protobuf/metadata_lite.h>
  39. #include <google/protobuf/port.h>
  40. #include <google/protobuf/wire_format_lite.h>
  41. // Must come last:
  42. #include <google/protobuf/port_def.inc>
  43. namespace google {
  44. namespace protobuf {
  45. class Message;
  46. class UnknownFieldSet;
  47. namespace internal {
  48. // PROTOBUF_TC_PARAM_DECL are the parameters for tailcall functions.
  49. //
  50. // Note that this is performance sensitive: changing the parameters will change
  51. // the registers used by the ABI calling convention, which subsequently affects
  52. // register selection logic inside the function.
  53. #define PROTOBUF_TC_PARAM_DECL \
  54. ::google::protobuf::MessageLite *msg, const char *ptr, \
  55. ::google::protobuf::internal::ParseContext *ctx, \
  56. const ::google::protobuf::internal::TailCallParseTableBase *table, \
  57. uint64_t hasbits, ::google::protobuf::internal::TcFieldData data
  58. // PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
  59. #define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
  60. class TcParserBase {
  61. public:
  62. static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
  63. static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
  64. template <typename FieldType, typename TagType>
  65. PROTOBUF_NOINLINE static const char* SingularParseMessage(
  66. PROTOBUF_TC_PARAM_DECL) {
  67. if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
  68. return table->fallback(PROTOBUF_TC_PARAM_PASS);
  69. }
  70. ptr += sizeof(TagType);
  71. hasbits |= (uint64_t{1} << data.hasbit_idx());
  72. auto& field = RefAt<FieldType*>(msg, data.offset());
  73. if (field == nullptr) {
  74. auto arena = ctx->data().arena;
  75. if (Arena::is_arena_constructable<FieldType>::value) {
  76. field = Arena::CreateMessage<FieldType>(arena);
  77. } else {
  78. field = Arena::Create<FieldType>(arena);
  79. }
  80. }
  81. SyncHasbits(msg, hasbits, table);
  82. return ctx->ParseMessage(field, ptr);
  83. }
  84. template <typename FieldType, typename TagType>
  85. PROTOBUF_NOINLINE static const char* RepeatedParseMessage(
  86. PROTOBUF_TC_PARAM_DECL) {
  87. if (PROTOBUF_PREDICT_FALSE(static_cast<TagType>(data.coded_tag()) != 0)) {
  88. return table->fallback(PROTOBUF_TC_PARAM_PASS);
  89. }
  90. ptr += sizeof(TagType);
  91. auto& field = RefAt<RepeatedPtrField<FieldType>>(msg, data.offset());
  92. SyncHasbits(msg, hasbits, table);
  93. ptr = ctx->ParseMessage(field.Add(), ptr);
  94. return ptr;
  95. }
  96. template <typename LayoutType, typename TagType>
  97. static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
  98. template <typename LayoutType, typename TagType>
  99. static const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
  100. enum VarintDecode { kNoConversion = 0, kZigZag = 1 };
  101. template <typename FieldType, typename TagType, VarintDecode zigzag>
  102. static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
  103. template <typename FieldType, typename TagType, VarintDecode zigzag>
  104. static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
  105. enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
  106. template <typename TagType, Utf8Type utf8>
  107. static const char* SingularString(PROTOBUF_TC_PARAM_DECL);
  108. template <typename TagType, Utf8Type utf8>
  109. static const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
  110. protected:
  111. template <typename T>
  112. static T& RefAt(void* x, size_t offset) {
  113. T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
  114. GOOGLE_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(target) % alignof(T));
  115. return *target;
  116. }
  117. static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
  118. MessageLite* msg, uint64_t hasbits, const TailCallParseTableBase* table) {
  119. const uint32_t has_bits_offset = table->has_bits_offset;
  120. if (has_bits_offset) {
  121. // Only the first 32 has-bits are updated. Nothing above those is stored,
  122. // but e.g. messages without has-bits update the upper bits.
  123. RefAt<uint32_t>(msg, has_bits_offset) = static_cast<uint32_t>(hasbits);
  124. }
  125. }
  126. static inline PROTOBUF_ALWAYS_INLINE const char* Return(
  127. PROTOBUF_TC_PARAM_DECL) {
  128. SyncHasbits(msg, hasbits, table);
  129. return ptr;
  130. }
  131. static inline PROTOBUF_ALWAYS_INLINE const char* Error(
  132. PROTOBUF_TC_PARAM_DECL) {
  133. SyncHasbits(msg, hasbits, table);
  134. return nullptr;
  135. }
  136. class ScopedArenaSwap final {
  137. public:
  138. ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
  139. : ctx_(ctx), saved_(ctx->data().arena) {
  140. ctx_->data().arena = msg->GetArenaForAllocation();
  141. }
  142. ScopedArenaSwap(const ScopedArenaSwap&) = delete;
  143. ~ScopedArenaSwap() { ctx_->data().arena = saved_; }
  144. private:
  145. ParseContext* const ctx_;
  146. Arena* const saved_;
  147. };
  148. template <class MessageBaseT, class UnknownFieldsT>
  149. static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
  150. #define CHK_(x) \
  151. if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
  152. SyncHasbits(msg, hasbits, table);
  153. uint32_t tag;
  154. ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
  155. CHK_(ptr);
  156. if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
  157. ctx->SetLastTag(tag);
  158. return ptr;
  159. }
  160. uint32_t num = tag >> 3;
  161. if (table->extension_range_low <= num &&
  162. num <= table->extension_range_high) {
  163. return RefAt<ExtensionSet>(msg, table->extension_offset)
  164. .ParseField(tag, ptr,
  165. static_cast<const MessageBaseT*>(table->default_instance),
  166. &msg->_internal_metadata_, ctx);
  167. }
  168. return UnknownFieldParse(
  169. tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
  170. ptr, ctx);
  171. #undef CHK_
  172. }
  173. };
  174. // TcParser implements most of the parsing logic for tailcall tables.
  175. //
  176. // This is templated on lg2(table size), since dispatching depends upon the size
  177. // of the table. The template parameter avoids runtime overhead for computing
  178. // the table entry index.
  179. template <uint32_t kPowerOf2>
  180. struct TcParser final : TcParserBase {
  181. // Dispatch to the designated parse function
  182. inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch(
  183. PROTOBUF_TC_PARAM_DECL) {
  184. const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
  185. constexpr size_t kIdxMask = ((1 << (kPowerOf2)) - 1);
  186. const size_t idx = (coded_tag >> 3) & kIdxMask;
  187. data = table->table()[idx].bits;
  188. data.data ^= coded_tag;
  189. PROTOBUF_MUSTTAIL return table->table()[idx].target(PROTOBUF_TC_PARAM_PASS);
  190. }
  191. // We can only safely call from field to next field if the call is optimized
  192. // to a proper tail call. Otherwise we blow through stack. Clang and gcc
  193. // reliably do this optimization in opt mode, but do not perform this in debug
  194. // mode. Luckily the structure of the algorithm is such that it's always
  195. // possible to just return and use the enclosing parse loop as a trampoline.
  196. static const char* TailCall(PROTOBUF_TC_PARAM_DECL) {
  197. constexpr bool always_return = !PROTOBUF_TAILCALL;
  198. if (always_return || !ctx->DataAvailable(ptr)) {
  199. PROTOBUF_MUSTTAIL return Return(PROTOBUF_TC_PARAM_PASS);
  200. }
  201. PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
  202. }
  203. static const char* ParseLoop(MessageLite* msg, const char* ptr,
  204. ParseContext* ctx,
  205. const TailCallParseTableBase* table) {
  206. ScopedArenaSwap saved(msg, ctx);
  207. const uint32_t has_bits_offset = table->has_bits_offset;
  208. while (!ctx->Done(&ptr)) {
  209. uint64_t hasbits = 0;
  210. if (has_bits_offset) hasbits = RefAt<uint32_t>(msg, has_bits_offset);
  211. ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
  212. if (ptr == nullptr) break;
  213. if (ctx->LastTag() != 1) break; // Ended on terminating tag
  214. }
  215. return ptr;
  216. }
  217. template <typename LayoutType, typename TagType>
  218. static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
  219. template <typename FieldType, typename TagType, VarintDecode zigzag>
  220. static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
  221. };
  222. // Declare helper functions:
  223. #include <google/protobuf/generated_message_tctable_impl.inc>
  224. } // namespace internal
  225. } // namespace protobuf
  226. } // namespace google
  227. #include <google/protobuf/port_undef.inc>
  228. #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__