generated_message_tctable_impl.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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, it is
  49. // defined in port_def.inc.
  50. //
  51. // Note that this is performance sensitive: changing the parameters will change
  52. // the registers used by the ABI calling convention, which subsequently affects
  53. // register selection logic inside the function.
  54. // PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
  55. #define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, table, hasbits, data
  56. // PROTOBUF_TC_PARSE_* decide which function is used to parse message-typed
  57. // fields. The guard macros are defined in port_def.inc.
  58. #if PROTOBUF_TC_STATIC_PARSE_SINGULAR1
  59. #define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1
  60. #else
  61. #define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \
  62. ::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint8_t>
  63. #endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR1
  64. #if PROTOBUF_TC_STATIC_PARSE_SINGULAR2
  65. #define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2
  66. #else
  67. #define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \
  68. ::google::protobuf::internal::TcParserBase::SingularParseMessage<MESSAGE, uint16_t>
  69. #endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR2
  70. #if PROTOBUF_TC_STATIC_PARSE_REPEATED1
  71. #define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1
  72. #else
  73. #define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \
  74. ::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint8_t>
  75. #endif // PROTOBUF_TC_STATIC_PARSE_REPEATED1
  76. #if PROTOBUF_TC_STATIC_PARSE_REPEATED2
  77. #define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2
  78. #else
  79. #define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \
  80. ::google::protobuf::internal::TcParserBase::RepeatedParseMessage<MESSAGE, uint16_t>
  81. #endif // PROTOBUF_TC_STATIC_PARSE_REPEATED2
  82. #ifndef NDEBUG
  83. template <size_t align>
  84. #ifndef _MSC_VER
  85. [[noreturn]]
  86. #endif
  87. void AlignFail(uintptr_t address) {
  88. GOOGLE_LOG(FATAL) << "Unaligned (" << align << ") access at " << address;
  89. }
  90. extern template void AlignFail<4>(uintptr_t);
  91. extern template void AlignFail<8>(uintptr_t);
  92. #endif
  93. class TcParserBase {
  94. public:
  95. static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
  96. static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
  97. template <typename FieldType, typename TagType>
  98. PROTOBUF_NOINLINE static const char* SingularParseMessage(
  99. PROTOBUF_TC_PARAM_DECL) {
  100. if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
  101. return table->fallback(PROTOBUF_TC_PARAM_PASS);
  102. }
  103. ptr += sizeof(TagType);
  104. hasbits |= (uint64_t{1} << data.hasbit_idx());
  105. auto& field = RefAt<FieldType*>(msg, data.offset());
  106. if (field == nullptr) {
  107. auto arena = ctx->data().arena;
  108. if (Arena::is_arena_constructable<FieldType>::value) {
  109. field = Arena::CreateMessage<FieldType>(arena);
  110. } else {
  111. field = Arena::Create<FieldType>(arena);
  112. }
  113. }
  114. SyncHasbits(msg, hasbits, table);
  115. return ctx->ParseMessage(field, ptr);
  116. }
  117. template <typename FieldType, typename TagType>
  118. PROTOBUF_NOINLINE static const char* RepeatedParseMessage(
  119. PROTOBUF_TC_PARAM_DECL) {
  120. if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
  121. return table->fallback(PROTOBUF_TC_PARAM_PASS);
  122. }
  123. ptr += sizeof(TagType);
  124. auto& field = RefAt<RepeatedPtrField<FieldType>>(msg, data.offset());
  125. SyncHasbits(msg, hasbits, table);
  126. ptr = ctx->ParseMessage(field.Add(), ptr);
  127. return ptr;
  128. }
  129. template <typename LayoutType, typename TagType>
  130. static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
  131. template <typename LayoutType, typename TagType>
  132. static const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
  133. enum VarintDecode { kNoConversion = 0, kZigZag = 1 };
  134. template <typename FieldType, typename TagType, VarintDecode zigzag>
  135. static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
  136. template <typename FieldType, typename TagType, VarintDecode zigzag>
  137. static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
  138. enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
  139. template <typename TagType, Utf8Type utf8>
  140. static const char* SingularString(PROTOBUF_TC_PARAM_DECL);
  141. template <typename TagType, Utf8Type utf8>
  142. static const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
  143. template <typename T>
  144. static inline T& RefAt(void* x, size_t offset) {
  145. T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
  146. #ifndef NDEBUG
  147. if (PROTOBUF_PREDICT_FALSE(
  148. reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
  149. AlignFail<alignof(T)>(reinterpret_cast<uintptr_t>(target));
  150. }
  151. #endif
  152. return *target;
  153. }
  154. static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
  155. MessageLite* msg, uint64_t hasbits, const TailCallParseTableBase* table) {
  156. const uint32_t has_bits_offset = table->has_bits_offset;
  157. if (has_bits_offset) {
  158. // Only the first 32 has-bits are updated. Nothing above those is stored,
  159. // but e.g. messages without has-bits update the upper bits.
  160. RefAt<uint32_t>(msg, has_bits_offset) = static_cast<uint32_t>(hasbits);
  161. }
  162. }
  163. protected:
  164. static inline PROTOBUF_ALWAYS_INLINE const char* Return(
  165. PROTOBUF_TC_PARAM_DECL) {
  166. SyncHasbits(msg, hasbits, table);
  167. return ptr;
  168. }
  169. static inline PROTOBUF_ALWAYS_INLINE const char* Error(
  170. PROTOBUF_TC_PARAM_DECL) {
  171. SyncHasbits(msg, hasbits, table);
  172. return nullptr;
  173. }
  174. class ScopedArenaSwap final {
  175. public:
  176. ScopedArenaSwap(MessageLite* msg, ParseContext* ctx)
  177. : ctx_(ctx), saved_(ctx->data().arena) {
  178. ctx_->data().arena = msg->GetArenaForAllocation();
  179. }
  180. ScopedArenaSwap(const ScopedArenaSwap&) = delete;
  181. ~ScopedArenaSwap() { ctx_->data().arena = saved_; }
  182. private:
  183. ParseContext* const ctx_;
  184. Arena* const saved_;
  185. };
  186. template <class MessageBaseT, class UnknownFieldsT>
  187. static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
  188. #define CHK_(x) \
  189. if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr /* NOLINT */
  190. SyncHasbits(msg, hasbits, table);
  191. uint32_t tag;
  192. ptr = ::PROTOBUF_NAMESPACE_ID::internal::ReadTag(ptr, &tag);
  193. CHK_(ptr);
  194. if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
  195. ctx->SetLastTag(tag);
  196. return ptr;
  197. }
  198. uint32_t num = tag >> 3;
  199. if (table->extension_range_low <= num &&
  200. num <= table->extension_range_high) {
  201. return RefAt<ExtensionSet>(msg, table->extension_offset)
  202. .ParseField(tag, ptr,
  203. static_cast<const MessageBaseT*>(table->default_instance),
  204. &msg->_internal_metadata_, ctx);
  205. }
  206. return UnknownFieldParse(
  207. tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
  208. ptr, ctx);
  209. #undef CHK_
  210. }
  211. };
  212. // TcParser implements most of the parsing logic for tailcall tables.
  213. //
  214. // This is templated on lg2(table size), since dispatching depends upon the size
  215. // of the table. The template parameter avoids runtime overhead for computing
  216. // the table entry index.
  217. template <uint32_t kPowerOf2>
  218. struct TcParser final : TcParserBase {
  219. // Dispatch to the designated parse function
  220. inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch(
  221. PROTOBUF_TC_PARAM_DECL) {
  222. const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
  223. constexpr size_t kIdxMask = ((1 << (kPowerOf2)) - 1);
  224. const size_t idx = (coded_tag >> 3) & kIdxMask;
  225. data = table->table()[idx].bits;
  226. data.data ^= coded_tag;
  227. PROTOBUF_MUSTTAIL return table->table()[idx].target(PROTOBUF_TC_PARAM_PASS);
  228. }
  229. // We can only safely call from field to next field if the call is optimized
  230. // to a proper tail call. Otherwise we blow through stack. Clang and gcc
  231. // reliably do this optimization in opt mode, but do not perform this in debug
  232. // mode. Luckily the structure of the algorithm is such that it's always
  233. // possible to just return and use the enclosing parse loop as a trampoline.
  234. static const char* TailCall(PROTOBUF_TC_PARAM_DECL) {
  235. constexpr bool always_return = !PROTOBUF_TAILCALL;
  236. if (always_return || !ctx->DataAvailable(ptr)) {
  237. PROTOBUF_MUSTTAIL return Return(PROTOBUF_TC_PARAM_PASS);
  238. }
  239. PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
  240. }
  241. static const char* ParseLoop(MessageLite* msg, const char* ptr,
  242. ParseContext* ctx,
  243. const TailCallParseTableBase* table) {
  244. ScopedArenaSwap saved(msg, ctx);
  245. const uint32_t has_bits_offset = table->has_bits_offset;
  246. while (!ctx->Done(&ptr)) {
  247. uint64_t hasbits = 0;
  248. if (has_bits_offset) hasbits = RefAt<uint32_t>(msg, has_bits_offset);
  249. ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {});
  250. if (ptr == nullptr) break;
  251. if (ctx->LastTag() != 1) break; // Ended on terminating tag
  252. }
  253. return ptr;
  254. }
  255. template <typename LayoutType, typename TagType>
  256. static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
  257. template <typename FieldType, typename TagType, VarintDecode zigzag>
  258. static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
  259. };
  260. // Declare helper functions:
  261. #include <google/protobuf/generated_message_tctable_impl.inc>
  262. } // namespace internal
  263. } // namespace protobuf
  264. } // namespace google
  265. #include <google/protobuf/port_undef.inc>
  266. #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__