• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
9 #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
10 
11 #include <cassert>
12 #include <cstdint>
13 #include <cstdlib>
14 #include <string>
15 #include <type_traits>
16 
17 #include "absl/base/optimization.h"
18 #include "absl/log/absl_log.h"
19 #include "absl/strings/cord.h"
20 #include "absl/strings/string_view.h"
21 #include "google/protobuf/extension_set.h"
22 #include "google/protobuf/generated_message_tctable_decl.h"
23 #include "google/protobuf/map.h"
24 #include "google/protobuf/message_lite.h"
25 #include "google/protobuf/metadata_lite.h"
26 #include "google/protobuf/parse_context.h"
27 #include "google/protobuf/port.h"
28 #include "google/protobuf/raw_ptr.h"
29 #include "google/protobuf/repeated_field.h"
30 #include "google/protobuf/repeated_ptr_field.h"
31 #include "google/protobuf/serial_arena.h"
32 #include "google/protobuf/wire_format_lite.h"
33 
34 // Must come last:
35 #include "google/protobuf/port_def.inc"
36 
37 namespace google {
38 namespace protobuf {
39 
40 class Message;
41 class UnknownFieldSet;
42 
43 namespace internal {
44 
45 enum {
46   kInlinedStringAuxIdx = 0,
47   kSplitOffsetAuxIdx = 1,
48   kSplitSizeAuxIdx = 2,
49 };
50 
51 // Field layout enums.
52 //
53 // Structural information about fields is packed into a 16-bit value. The enum
54 // types below represent bitwise fields, along with their respective widths,
55 // shifts, and masks.
56 //
57 //     Bit:
58 //     +-----------------------+-----------------------+
59 //     |15        ..          8|7         ..          0|
60 //     +-----------------------+-----------------------+
61 //     :  .  :  .  :  .  :  .  :  .  :  .  : 3|========| [3] FieldType
62 //     :     :     :     :     :     :  . 4|==|  :     : [1] FieldSplit
63 //     :     :     :     :     :    6|=====|  .  :     : [2] FieldCardinality
64 //     :  .  :  .  :  .  : 9|========|  .  :  .  :  .  : [3] FieldRep
65 //     :     :     :11|=====|  :     :     :     :     : [2] TransformValidation
66 //     :  .  :13|=====|  :  .  :  .  :  .  :  .  :  .  : [2] FormatDiscriminator
67 //     +-----------------------+-----------------------+
68 //     |15        ..          8|7         ..          0|
69 //     +-----------------------+-----------------------+
70 //
71 namespace field_layout {
72 // clang-format off
73 
74 
75 // Field kind (3 bits):
76 // These values broadly represent a wire type and an in-memory storage class.
77 enum FieldKind : uint16_t {
78   kFkShift = 0,
79   kFkBits = 3,
80   kFkMask = ((1 << kFkBits) - 1) << kFkShift,
81 
82   kFkNone = 0,
83   kFkVarint,        // WT=0     rep=8,32,64 bits
84   kFkPackedVarint,  // WT=2     rep=8,32,64 bits
85   kFkFixed,         // WT=1,5   rep=32,64 bits
86   kFkPackedFixed,   // WT=2     rep=32,64 bits
87   kFkString,        // WT=2     rep=various
88   kFkMessage,       // WT=2,3,4 rep=MessageLite*
89   // Maps are a special case of Message, but use different parsing logic.
90   kFkMap,           // WT=2     rep=Map(Lite)<various, various>
91 };
92 
93 static_assert(kFkMap < (1 << kFkBits), "too many types");
94 
95 // Split (1 bit):
96 enum FieldSplit : uint16_t {
97   kSplitShift = kFkShift+ kFkBits,
98   kSplitBits  = 1,
99   kSplitMask  = ((1 << kSplitBits) - 1) << kSplitShift,
100 
101   kSplitFalse = 0,
102   kSplitTrue  = 1 << kSplitShift,
103 };
104 
105 // Cardinality (2 bits):
106 // These values determine how many values a field can have and its presence.
107 // Packed fields are represented in FieldType.
108 enum Cardinality : uint16_t {
109   kFcShift    = kSplitShift+ kSplitBits,
110   kFcBits     = 2,
111   kFcMask     = ((1 << kFcBits) - 1) << kFcShift,
112 
113   kFcSingular = 0,
114   kFcOptional = 1 << kFcShift,
115   kFcRepeated = 2 << kFcShift,
116   kFcOneof    = 3 << kFcShift,
117 };
118 
119 
120 // Field representation (3 bits):
121 // These values are the specific refinements of storage classes in FieldType.
122 enum FieldRep : uint16_t {
123   kRepShift    = kFcShift + kFcBits,
124   kRepBits     = 3,
125   kRepMask     = ((1 << kRepBits) - 1) << kRepShift,
126 
127   // Numeric types (used for optional and repeated fields):
128   kRep8Bits    = 0,
129   kRep32Bits   = 2 << kRepShift,
130   kRep64Bits   = 3 << kRepShift,
131   // String types:
132   kRepAString  = 0,               // ArenaStringPtr
133   kRepIString  = 1 << kRepShift,  // InlinedString
134   kRepCord     = 2 << kRepShift,  // absl::Cord
135   kRepSPiece   = 3 << kRepShift,  // StringPieceField
136   kRepSString  = 4 << kRepShift,  // std::string*
137   // Message types (WT=2 unless otherwise noted):
138   kRepMessage  = 0,               // MessageLite*
139   kRepGroup    = 1 << kRepShift,  // MessageLite* (WT=3,4)
140   kRepLazy     = 2 << kRepShift,  // LazyField*
141 };
142 
143 // Transform/validation (2 bits):
144 // These values determine transforms or validation to/from wire format.
145 enum TransformValidation : uint16_t {
146   kTvShift     = kRepShift + kRepBits,
147   kTvBits      = 2,
148   kTvMask      = ((1 << kTvBits) - 1) << kTvShift,
149 
150   // Varint fields:
151   kTvZigZag    = 1 << kTvShift,
152   kTvEnum      = 2 << kTvShift,  // validate using ValidateEnum()
153   kTvRange     = 3 << kTvShift,  // validate using FieldAux::enum_range
154   // String fields:
155   kTvUtf8Debug = 1 << kTvShift,  // proto2
156   kTvUtf8      = 2 << kTvShift,  // proto3
157 
158   // Message fields:
159   kTvDefault   = 1 << kTvShift,  // Aux has default_instance*
160   kTvTable     = 2 << kTvShift,  // Aux has TcParseTableBase*
161   kTvWeakPtr   = 3 << kTvShift,  // Aux has default_instance** (for weak)
162 
163   // Lazy message fields:
164   kTvEager     = 1 << kTvShift,
165   kTvLazy      = 2 << kTvShift,
166 };
167 
168 static_assert((kTvEnum & kTvRange) != 0,
169               "enum validation types must share a bit");
170 static_assert((kTvEnum & kTvRange & kTvZigZag) == 0,
171               "zigzag encoding is not enum validation");
172 
173 // Format discriminators (2 bits):
174 enum FormatDiscriminator : uint16_t {
175   kFmtShift      = kTvShift + kTvBits,
176   kFmtBits       = 2,
177   kFmtMask       = ((1 << kFmtBits) - 1) << kFmtShift,
178 
179   // Numeric:
180   kFmtUnsigned   = 1 << kFmtShift,  // fixed, varint
181   kFmtSigned     = 2 << kFmtShift,  // fixed, varint
182   kFmtFloating   = 3 << kFmtShift,  // fixed
183   kFmtEnum       = 3 << kFmtShift,  // varint
184   // Strings:
185   kFmtUtf8       = 1 << kFmtShift,  // string (proto3, enforce_utf8=true)
186   kFmtUtf8Escape = 2 << kFmtShift,  // string (proto2, enforce_utf8=false)
187   // Bytes:
188   kFmtArray      = 1 << kFmtShift,  // bytes
189   // Messages:
190   kFmtShow       = 1 << kFmtShift,  // message, map
191 };
192 
193 // Update this assertion (and comments above) when adding or removing bits:
194 static_assert(kFmtShift + kFmtBits == 13, "number of bits changed");
195 
196 // This assertion should not change unless the storage width changes:
197 static_assert(kFmtShift + kFmtBits <= 16, "too many bits");
198 
199 // Convenience aliases (16 bits, with format):
200 enum FieldType : uint16_t {
201   // Numeric types:
202   kBool            = 0 | kFkVarint | kRep8Bits,
203 
204   kFixed32         = 0 | kFkFixed  | kRep32Bits | kFmtUnsigned,
205   kUInt32          = 0 | kFkVarint | kRep32Bits | kFmtUnsigned,
206   kSFixed32        = 0 | kFkFixed  | kRep32Bits | kFmtSigned,
207   kInt32           = 0 | kFkVarint | kRep32Bits | kFmtSigned,
208   kSInt32          = 0 | kFkVarint | kRep32Bits | kFmtSigned | kTvZigZag,
209   kFloat           = 0 | kFkFixed  | kRep32Bits | kFmtFloating,
210   kEnum            = 0 | kFkVarint | kRep32Bits | kFmtEnum   | kTvEnum,
211   kEnumRange       = 0 | kFkVarint | kRep32Bits | kFmtEnum   | kTvRange,
212   kOpenEnum        = 0 | kFkVarint | kRep32Bits | kFmtEnum,
213 
214   kFixed64         = 0 | kFkFixed  | kRep64Bits | kFmtUnsigned,
215   kUInt64          = 0 | kFkVarint | kRep64Bits | kFmtUnsigned,
216   kSFixed64        = 0 | kFkFixed  | kRep64Bits | kFmtSigned,
217   kInt64           = 0 | kFkVarint | kRep64Bits | kFmtSigned,
218   kSInt64          = 0 | kFkVarint | kRep64Bits | kFmtSigned | kTvZigZag,
219   kDouble          = 0 | kFkFixed  | kRep64Bits | kFmtFloating,
220 
221   kPackedBool      = 0 | kFkPackedVarint | kRep8Bits,
222 
223   kPackedFixed32   = 0 | kFkPackedFixed  | kRep32Bits | kFmtUnsigned,
224   kPackedUInt32    = 0 | kFkPackedVarint | kRep32Bits | kFmtUnsigned,
225   kPackedSFixed32  = 0 | kFkPackedFixed  | kRep32Bits | kFmtSigned,
226   kPackedInt32     = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned,
227   kPackedSInt32    = 0 | kFkPackedVarint | kRep32Bits | kFmtSigned | kTvZigZag,
228   kPackedFloat     = 0 | kFkPackedFixed  | kRep32Bits | kFmtFloating,
229   kPackedEnum      = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvEnum,
230   kPackedEnumRange = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum   | kTvRange,
231   kPackedOpenEnum  = 0 | kFkPackedVarint | kRep32Bits | kFmtEnum,
232 
233   kPackedFixed64   = 0 | kFkPackedFixed  | kRep64Bits | kFmtUnsigned,
234   kPackedUInt64    = 0 | kFkPackedVarint | kRep64Bits | kFmtUnsigned,
235   kPackedSFixed64  = 0 | kFkPackedFixed  | kRep64Bits | kFmtSigned,
236   kPackedInt64     = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned,
237   kPackedSInt64    = 0 | kFkPackedVarint | kRep64Bits | kFmtSigned | kTvZigZag,
238   kPackedDouble    = 0 | kFkPackedFixed  | kRep64Bits | kFmtFloating,
239 
240   // String types:
241   kBytes           = 0 | kFkString | kFmtArray,
242   kRawString       = 0 | kFkString | kFmtUtf8  | kTvUtf8Debug,
243   kUtf8String      = 0 | kFkString | kFmtUtf8  | kTvUtf8,
244 
245   // Message types:
246   kMessage         = kFkMessage,
247 
248   // Map types:
249   kMap             = kFkMap,
250 };
251 // clang-format on
252 }  // namespace field_layout
253 
254 #ifndef NDEBUG
255 PROTOBUF_EXPORT void AlignFail(std::integral_constant<size_t, 4>,
256                                std::uintptr_t address);
257 PROTOBUF_EXPORT void AlignFail(std::integral_constant<size_t, 8>,
258                                std::uintptr_t address);
AlignFail(std::integral_constant<size_t,1>,std::uintptr_t address)259 inline void AlignFail(std::integral_constant<size_t, 1>,
260                       std::uintptr_t address) {}
261 #endif
262 
263 #define PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(fn) \
264   PROTOBUF_TC_PARSE_FUNCTION_X(fn##S1)             \
265   PROTOBUF_TC_PARSE_FUNCTION_X(fn##S2)
266 
267 #define PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(fn) \
268   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(fn)         \
269   PROTOBUF_TC_PARSE_FUNCTION_X(fn##R1)               \
270   PROTOBUF_TC_PARSE_FUNCTION_X(fn##R2)
271 
272 #define PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(fn) \
273   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(fn)     \
274   PROTOBUF_TC_PARSE_FUNCTION_X(fn##P1)             \
275   PROTOBUF_TC_PARSE_FUNCTION_X(fn##P2)
276 
277 #define PROTOBUF_TC_PARSE_FUNCTION_LIST_END_GROUP() \
278   PROTOBUF_TC_PARSE_FUNCTION_X(FastEndG1)           \
279   PROTOBUF_TC_PARSE_FUNCTION_X(FastEndG2)
280 
281 // TcParseFunction defines the set of table driven, tail call optimized parse
282 // functions. This list currently does not include all types such as maps.
283 //
284 // This table identifies the logical set of functions, it does not imply that
285 // functions of the same name do exist, and some entries may point to thunks or
286 // generic implementations accepting multiple types of input.
287 //
288 // The names are encoded as follows:
289 //   kFast<type>[<validation>][cardinality][tag_width]
290 //
291 //   type:
292 //     V8  - bool
293 //     V32 - int32/uint32 varint
294 //     Z32 - int32/uint32 varint with zigzag encoding
295 //     V64 - int64/uint64 varint
296 //     Z64 - int64/uint64 varint with zigzag encoding
297 //     F32 - int32/uint32/float fixed width value
298 //     F64 - int64/uint64/double fixed width value
299 //     E   - enum
300 //     B   - string (bytes)*
301 //     S   - utf8 string, verified in debug mode only*
302 //     U   - utf8 string, strictly verified*
303 //     Gd  - group
304 //     Gt  - group width table driven parse tables
305 //     Md  - message
306 //     Mt  - message width table driven parse tables
307 //     End - End group tag
308 //
309 // * string types can have a `c` or `i` suffix, indicating the
310 //   underlying storage type to be cord or inlined respectively.
311 //
312 //  validation:
313 //    For enums:
314 //      v  - verify
315 //      r  - verify; enum values are a contiguous range
316 //      r0 - verify; enum values are a small contiguous range starting at 0
317 //      r1 - verify; enum values are a small contiguous range starting at 1
318 //    For strings:
319 //      u - validate utf8 encoding
320 //      v - validate utf8 encoding for debug only
321 //
322 //  cardinality:
323 //    S - singular / optional
324 //    R - repeated
325 //    P - packed
326 //    G - group terminated
327 //
328 //  tag_width:
329 //    1: single byte encoded tag
330 //    2: two byte encoded tag
331 //
332 // Examples:
333 //   FastV8S1, FastZ64S2, FastEr1P2, FastBcS1, FastMtR2, FastEndG1
334 //
335 #define PROTOBUF_TC_PARSE_FUNCTION_LIST                           \
336   /* These functions have the Fast entry ABI */                   \
337   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV8)                  \
338   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV32)                 \
339   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV64)                 \
340   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastZ32)                 \
341   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastZ64)                 \
342   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastF32)                 \
343   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastF64)                 \
344   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEv)                  \
345   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr)                  \
346   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr0)                 \
347   PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr1)                 \
348   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastB)                 \
349   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastS)                 \
350   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastU)                 \
351   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastBi)                  \
352   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastSi)                  \
353   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastUi)                  \
354   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastBc)                  \
355   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastSc)                  \
356   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastUc)                  \
357   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastGd)                \
358   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastGt)                \
359   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastMd)                \
360   PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastMt)                \
361   PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastMl)                  \
362   PROTOBUF_TC_PARSE_FUNCTION_LIST_END_GROUP()                     \
363   PROTOBUF_TC_PARSE_FUNCTION_X(MessageSetWireFormatParseLoopLite) \
364   PROTOBUF_TC_PARSE_FUNCTION_X(MessageSetWireFormatParseLoop)     \
365   PROTOBUF_TC_PARSE_FUNCTION_X(ReflectionParseLoop)               \
366   /* These functions have the fallback ABI */                     \
367   PROTOBUF_TC_PARSE_FUNCTION_X(GenericFallback)                   \
368   PROTOBUF_TC_PARSE_FUNCTION_X(GenericFallbackLite)               \
369   PROTOBUF_TC_PARSE_FUNCTION_X(ReflectionFallback)                \
370   PROTOBUF_TC_PARSE_FUNCTION_X(DiscardEverythingFallback)
371 
372 #define PROTOBUF_TC_PARSE_FUNCTION_X(value) k##value,
373 enum class TcParseFunction : uint8_t { kNone, PROTOBUF_TC_PARSE_FUNCTION_LIST };
374 #undef PROTOBUF_TC_PARSE_FUNCTION_X
375 
376 // TcParser implements most of the parsing logic for tailcall tables.
377 class PROTOBUF_EXPORT TcParser final {
378  public:
379   template <typename T>
380   static constexpr auto GetTable() -> decltype(&T::_table_.header) {
381     return &T::_table_.header;
382   }
383 
ParseMessage(MessageLite * msg,const char * ptr,ParseContext * ctx,const TcParseTableBase * tc_table)384   static PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
385       MessageLite* msg, const char* ptr, ParseContext* ctx,
386       const TcParseTableBase* tc_table) {
387     return ctx->ParseLengthDelimitedInlined(ptr, [&](const char* ptr) {
388       return ParseLoop(msg, ptr, ctx, tc_table);
389     });
390   }
391 
ParseGroup(MessageLite * msg,const char * ptr,ParseContext * ctx,const TcParseTableBase * tc_table,uint32_t start_tag)392   static PROTOBUF_ALWAYS_INLINE const char* ParseGroup(
393       MessageLite* msg, const char* ptr, ParseContext* ctx,
394       const TcParseTableBase* tc_table, uint32_t start_tag) {
395     return ctx->ParseGroupInlined(ptr, start_tag, [&](const char* ptr) {
396       return ParseLoop(msg, ptr, ctx, tc_table);
397     });
398   }
399 
400   // == ABI of the tail call functions ==
401   // All the tail call functions have the same signature as required by clang's
402   // `musttail` attribute. However, their ABIs are different.
403   // See TcFieldData's comments for details on the layouts.
404   // The ABIs are as follow:
405   //
406   //  - The following functions ignore `data`:
407   //      ToTagDispatch, TagDispatch, MiniParse, ToParseLoop, Error,
408   //      FastUnknownEnumFallback.
409   //  - FastXXX functions expect `data` with a fast table entry ABI.
410   //  - FastEndGX functions expect `data` with a non-field entry ABI.
411   //  - MpXXX functions expect `data` with a mini table ABI.
412   //  - The fallback functions (both GenericFallbackXXX and the codegen ones)
413   //    expect only the tag in `data`. In addition, if a null `ptr` is passed,
414   //    the function is used as a way to get a UnknownFieldOps vtable, returned
415   //    via the `const char*` return type. See `GetUnknownFieldOps()`
416 
417   PROTOBUF_CC static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL);
418   PROTOBUF_CC static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL);
419   PROTOBUF_CC static const char* ReflectionFallback(PROTOBUF_TC_PARAM_DECL);
420   PROTOBUF_CC static const char* ReflectionParseLoop(PROTOBUF_TC_PARAM_DECL);
421 
422   // This fallback will discard any field that reaches there.
423   // Note that fields parsed via fast/MiniParse are not going to be discarded
424   // even when this is enabled.
425   PROTOBUF_CC static const char* DiscardEverythingFallback(
426       PROTOBUF_TC_PARAM_DECL);
427 
428   // These follow the "fast" function ABI but implement the whole loop for
429   // message_set_wire_format types.
430   PROTOBUF_CC static const char* MessageSetWireFormatParseLoop(
431       PROTOBUF_TC_PARAM_NO_DATA_DECL);
432   PROTOBUF_CC static const char* MessageSetWireFormatParseLoopLite(
433       PROTOBUF_TC_PARAM_NO_DATA_DECL);
434 
435   static const char* ParseLoop(MessageLite* msg, const char* ptr,
436                                ParseContext* ctx,
437                                const TcParseTableBase* table);
438   PROTOBUF_NOINLINE PROTOBUF_CC static const char* ParseLoopPreserveNone(
439       MessageLite* msg, const char* ptr, ParseContext* ctx,
440       const TcParseTableBase* table);
441 
442   // Functions referenced by generated fast tables (numeric types):
443   //   F: fixed      V: varint     Z: zigzag
444   //   8/32/64: storage type width (bits)
445   //   S: singular   R: repeated   P: packed
446   //   1/2: tag length (bytes)
447 
448   // Fixed:
449   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32S1(
450       PROTOBUF_TC_PARAM_DECL);
451   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32S2(
452       PROTOBUF_TC_PARAM_DECL);
453   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32R1(
454       PROTOBUF_TC_PARAM_DECL);
455   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32R2(
456       PROTOBUF_TC_PARAM_DECL);
457   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32P1(
458       PROTOBUF_TC_PARAM_DECL);
459   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF32P2(
460       PROTOBUF_TC_PARAM_DECL);
461   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64S1(
462       PROTOBUF_TC_PARAM_DECL);
463   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64S2(
464       PROTOBUF_TC_PARAM_DECL);
465   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64R1(
466       PROTOBUF_TC_PARAM_DECL);
467   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64R2(
468       PROTOBUF_TC_PARAM_DECL);
469   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64P1(
470       PROTOBUF_TC_PARAM_DECL);
471   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastF64P2(
472       PROTOBUF_TC_PARAM_DECL);
473 
474   // Varint:
475   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8S1(
476       PROTOBUF_TC_PARAM_DECL);
477   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8S2(
478       PROTOBUF_TC_PARAM_DECL);
479   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8R1(
480       PROTOBUF_TC_PARAM_DECL);
481   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8R2(
482       PROTOBUF_TC_PARAM_DECL);
483   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8P1(
484       PROTOBUF_TC_PARAM_DECL);
485   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV8P2(
486       PROTOBUF_TC_PARAM_DECL);
487   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32S1(
488       PROTOBUF_TC_PARAM_DECL);
489   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32S2(
490       PROTOBUF_TC_PARAM_DECL);
491   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32R1(
492       PROTOBUF_TC_PARAM_DECL);
493   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32R2(
494       PROTOBUF_TC_PARAM_DECL);
495   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32P1(
496       PROTOBUF_TC_PARAM_DECL);
497   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV32P2(
498       PROTOBUF_TC_PARAM_DECL);
499   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64S1(
500       PROTOBUF_TC_PARAM_DECL);
501   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64S2(
502       PROTOBUF_TC_PARAM_DECL);
503   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64R1(
504       PROTOBUF_TC_PARAM_DECL);
505   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64R2(
506       PROTOBUF_TC_PARAM_DECL);
507   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64P1(
508       PROTOBUF_TC_PARAM_DECL);
509   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastV64P2(
510       PROTOBUF_TC_PARAM_DECL);
511 
512   // Varint (with zigzag):
513   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32S1(
514       PROTOBUF_TC_PARAM_DECL);
515   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32S2(
516       PROTOBUF_TC_PARAM_DECL);
517   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32R1(
518       PROTOBUF_TC_PARAM_DECL);
519   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32R2(
520       PROTOBUF_TC_PARAM_DECL);
521   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32P1(
522       PROTOBUF_TC_PARAM_DECL);
523   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ32P2(
524       PROTOBUF_TC_PARAM_DECL);
525   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64S1(
526       PROTOBUF_TC_PARAM_DECL);
527   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64S2(
528       PROTOBUF_TC_PARAM_DECL);
529   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64R1(
530       PROTOBUF_TC_PARAM_DECL);
531   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64R2(
532       PROTOBUF_TC_PARAM_DECL);
533   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64P1(
534       PROTOBUF_TC_PARAM_DECL);
535   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastZ64P2(
536       PROTOBUF_TC_PARAM_DECL);
537 
538   template <typename FieldType, int unused_data_offset, int unused_hasbit_idx>
SingularVarintNoZag1()539   static constexpr TailCallParseFunc SingularVarintNoZag1() {
540     if (sizeof(FieldType) == 1) {
541       return &FastV8S1;
542     }
543     if (sizeof(FieldType) == 4) {
544       return &FastV32S1;
545     }
546     if (sizeof(FieldType) == 8) {
547       return &FastV64S1;
548     }
549     static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
550                       sizeof(FieldType) == 8,
551                   "");
552     ABSL_LOG(FATAL) << "This should be unreachable";
553   }
554 
555   // Functions referenced by generated fast tables (closed enum):
556   //   E: closed enum (N.B.: open enums use V32, above)
557   //   r: enum range  v: enum validator (ValidateEnum function)
558   //   S: singular   R: repeated   P: packed
559   //   1/2: tag length (bytes)
560   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErS1(
561       PROTOBUF_TC_PARAM_DECL);
562   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErS2(
563       PROTOBUF_TC_PARAM_DECL);
564   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErR1(
565       PROTOBUF_TC_PARAM_DECL);
566   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErR2(
567       PROTOBUF_TC_PARAM_DECL);
568   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErP1(
569       PROTOBUF_TC_PARAM_DECL);
570   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastErP2(
571       PROTOBUF_TC_PARAM_DECL);
572   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvS1(
573       PROTOBUF_TC_PARAM_DECL);
574   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvS2(
575       PROTOBUF_TC_PARAM_DECL);
576   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvR1(
577       PROTOBUF_TC_PARAM_DECL);
578   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvR2(
579       PROTOBUF_TC_PARAM_DECL);
580   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvP1(
581       PROTOBUF_TC_PARAM_DECL);
582   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEvP2(
583       PROTOBUF_TC_PARAM_DECL);
584 
585   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0S1(
586       PROTOBUF_TC_PARAM_DECL);
587   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0S2(
588       PROTOBUF_TC_PARAM_DECL);
589   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0R1(
590       PROTOBUF_TC_PARAM_DECL);
591   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0R2(
592       PROTOBUF_TC_PARAM_DECL);
593   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0P1(
594       PROTOBUF_TC_PARAM_DECL);
595   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr0P2(
596       PROTOBUF_TC_PARAM_DECL);
597   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1S1(
598       PROTOBUF_TC_PARAM_DECL);
599   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1S2(
600       PROTOBUF_TC_PARAM_DECL);
601   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1R1(
602       PROTOBUF_TC_PARAM_DECL);
603   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1R2(
604       PROTOBUF_TC_PARAM_DECL);
605   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1P1(
606       PROTOBUF_TC_PARAM_DECL);
607   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEr1P2(
608       PROTOBUF_TC_PARAM_DECL);
609 
610   // Functions referenced by generated fast tables (string types):
611   //   B: bytes      S: string     U: UTF-8 string
612   //   (empty): ArenaStringPtr     i: InlinedString
613   //   S: singular   R: repeated
614   //   1/2: tag length (bytes)
615   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBS1(
616       PROTOBUF_TC_PARAM_DECL);
617   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBS2(
618       PROTOBUF_TC_PARAM_DECL);
619   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBR1(
620       PROTOBUF_TC_PARAM_DECL);
621   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBR2(
622       PROTOBUF_TC_PARAM_DECL);
623   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSS1(
624       PROTOBUF_TC_PARAM_DECL);
625   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSS2(
626       PROTOBUF_TC_PARAM_DECL);
627   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSR1(
628       PROTOBUF_TC_PARAM_DECL);
629   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSR2(
630       PROTOBUF_TC_PARAM_DECL);
631   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUS1(
632       PROTOBUF_TC_PARAM_DECL);
633   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUS2(
634       PROTOBUF_TC_PARAM_DECL);
635   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUR1(
636       PROTOBUF_TC_PARAM_DECL);
637   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUR2(
638       PROTOBUF_TC_PARAM_DECL);
639 
640   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBiS1(
641       PROTOBUF_TC_PARAM_DECL);
642   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBiS2(
643       PROTOBUF_TC_PARAM_DECL);
644   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSiS1(
645       PROTOBUF_TC_PARAM_DECL);
646   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastSiS2(
647       PROTOBUF_TC_PARAM_DECL);
648   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUiS1(
649       PROTOBUF_TC_PARAM_DECL);
650   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUiS2(
651       PROTOBUF_TC_PARAM_DECL);
652 
653   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBcS1(
654       PROTOBUF_TC_PARAM_DECL);
655   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastBcS2(
656       PROTOBUF_TC_PARAM_DECL);
657   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastScS1(
658       PROTOBUF_TC_PARAM_DECL);
659   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastScS2(
660       PROTOBUF_TC_PARAM_DECL);
661   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUcS1(
662       PROTOBUF_TC_PARAM_DECL);
663   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUcS2(
664       PROTOBUF_TC_PARAM_DECL);
665 
666   // Functions referenced by generated fast tables (message types):
667   //   M: message    G: group
668   //   d: default*   t: TcParseTable* (the contents of aux)  l: lazy
669   //   S: singular   R: repeated
670   //   1/2: tag length (bytes)
671   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMdS1(
672       PROTOBUF_TC_PARAM_DECL);
673   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMdS2(
674       PROTOBUF_TC_PARAM_DECL);
675   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGdS1(
676       PROTOBUF_TC_PARAM_DECL);
677   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGdS2(
678       PROTOBUF_TC_PARAM_DECL);
679   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMtS1(
680       PROTOBUF_TC_PARAM_DECL);
681   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMtS2(
682       PROTOBUF_TC_PARAM_DECL);
683   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGtS1(
684       PROTOBUF_TC_PARAM_DECL);
685   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGtS2(
686       PROTOBUF_TC_PARAM_DECL);
687 
688   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMdR1(
689       PROTOBUF_TC_PARAM_DECL);
690   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMdR2(
691       PROTOBUF_TC_PARAM_DECL);
692   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGdR1(
693       PROTOBUF_TC_PARAM_DECL);
694   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGdR2(
695       PROTOBUF_TC_PARAM_DECL);
696   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMtR1(
697       PROTOBUF_TC_PARAM_DECL);
698   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMtR2(
699       PROTOBUF_TC_PARAM_DECL);
700   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGtR1(
701       PROTOBUF_TC_PARAM_DECL);
702   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastGtR2(
703       PROTOBUF_TC_PARAM_DECL);
704 
705   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMlS1(
706       PROTOBUF_TC_PARAM_DECL);
707   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastMlS2(
708       PROTOBUF_TC_PARAM_DECL);
709 
710   // NOTE: Do not dedup RefAt by having one call the other with a const_cast. It
711   // causes ICEs of gcc 7.5.
712   // https://github.com/protocolbuffers/protobuf/issues/13715
713   template <typename T>
RefAt(void * x,size_t offset)714   static inline T& RefAt(void* x, size_t offset) {
715     T* target = reinterpret_cast<T*>(static_cast<char*>(x) + offset);
716 #if !defined(NDEBUG) && !(defined(_MSC_VER) && defined(_M_IX86))
717     // Check the alignment in debug mode, except in 32-bit msvc because it does
718     // not respect the alignment as expressed by `alignof(T)`
719     if (PROTOBUF_PREDICT_FALSE(
720             reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
721       AlignFail(std::integral_constant<size_t, alignof(T)>(),
722                 reinterpret_cast<uintptr_t>(target));
723       // Explicit abort to let compilers know this code-path does not return
724       abort();
725     }
726 #endif
727     return *target;
728   }
729 
730   template <typename T>
RefAt(const void * x,size_t offset)731   static inline const T& RefAt(const void* x, size_t offset) {
732     const T* target =
733         reinterpret_cast<const T*>(static_cast<const char*>(x) + offset);
734 #if !defined(NDEBUG) && !(defined(_MSC_VER) && defined(_M_IX86))
735     // Check the alignment in debug mode, except in 32-bit msvc because it does
736     // not respect the alignment as expressed by `alignof(T)`
737     if (PROTOBUF_PREDICT_FALSE(
738             reinterpret_cast<uintptr_t>(target) % alignof(T) != 0)) {
739       AlignFail(std::integral_constant<size_t, alignof(T)>(),
740                 reinterpret_cast<uintptr_t>(target));
741       // Explicit abort to let compilers know this code-path does not return
742       abort();
743     }
744 #endif
745     return *target;
746   }
747 
748   static const TcParseTableBase* GetTableFromAux(
749       uint16_t type_card, TcParseTableBase::FieldAux aux);
750   static MessageLite* NewMessage(const TcParseTableBase* table, Arena* arena);
751   static MessageLite* AddMessage(const TcParseTableBase* table,
752                                  RepeatedPtrFieldBase& field);
753 
754   template <typename T, bool is_split>
MaybeCreateRepeatedRefAt(void * x,size_t offset,MessageLite * msg)755   static inline T& MaybeCreateRepeatedRefAt(void* x, size_t offset,
756                                             MessageLite* msg) {
757     if (!is_split) return RefAt<T>(x, offset);
758     void*& ptr = RefAt<void*>(x, offset);
759     if (ptr == DefaultRawPtr()) {
760       ptr = Arena::Create<T>(msg->GetArena());
761     }
762     return *static_cast<T*>(ptr);
763   }
764 
765   template <typename T, bool is_split>
MaybeCreateRepeatedFieldRefAt(void * x,size_t offset,MessageLite * msg)766   static inline RepeatedField<T>& MaybeCreateRepeatedFieldRefAt(
767       void* x, size_t offset, MessageLite* msg) {
768     return MaybeCreateRepeatedRefAt<RepeatedField<T>, is_split>(x, offset, msg);
769   }
770 
771   template <typename T, bool is_split>
MaybeCreateRepeatedPtrFieldRefAt(void * x,size_t offset,MessageLite * msg)772   static inline RepeatedPtrField<T>& MaybeCreateRepeatedPtrFieldRefAt(
773       void* x, size_t offset, MessageLite* msg) {
774     return MaybeCreateRepeatedRefAt<RepeatedPtrField<T>, is_split>(x, offset,
775                                                                    msg);
776   }
777 
778   template <typename T>
ReadAt(const void * x,size_t offset)779   static inline T ReadAt(const void* x, size_t offset) {
780     T out;
781     memcpy(&out, static_cast<const char*>(x) + offset, sizeof(T));
782     return out;
783   }
784 
785   // Mini parsing:
786   //
787   // This function parses a field from incoming data based on metadata stored in
788   // the message definition. If the field is not defined in the message, it is
789   // stored in either the ExtensionSet (if applicable) or the UnknownFieldSet.
790   //
791   // NOTE: Currently, this function only calls the table-level fallback
792   // function, so it should only be called as the fallback from fast table
793   // parsing.
794   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MiniParse(
795       PROTOBUF_TC_PARAM_NO_DATA_DECL);
796 
797   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEndG1(
798       PROTOBUF_TC_PARAM_DECL);
799   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastEndG2(
800       PROTOBUF_TC_PARAM_DECL);
801 
802   // For `map` mini parsing generate a type card for the key/value.
803   template <typename MapField>
GetMapAuxInfo(bool fail_on_utf8_failure,bool log_debug_utf8_failure,bool validated_enum_value,int key_type,int value_type)804   static constexpr MapAuxInfo GetMapAuxInfo(bool fail_on_utf8_failure,
805                                             bool log_debug_utf8_failure,
806                                             bool validated_enum_value,
807                                             int key_type, int value_type) {
808     using MapType = typename MapField::MapType;
809     using Node = typename MapType::Node;
810     static_assert(alignof(Node) == alignof(NodeBase), "");
811     // Verify the assumption made in MpMap, guaranteed by Map<>.
812     assert(PROTOBUF_FIELD_OFFSET(Node, kv.first) == sizeof(NodeBase));
813     return {
814         MakeMapTypeCard(static_cast<WireFormatLite::FieldType>(key_type)),
815         MakeMapTypeCard(static_cast<WireFormatLite::FieldType>(value_type)),
816         true,
817         !std::is_base_of<MapFieldBaseForParse, MapField>::value,
818         fail_on_utf8_failure,
819         log_debug_utf8_failure,
820         validated_enum_value,
821         Node::size_info(),
822     };
823   }
824 
825  private:
826   // Optimized small tag varint parser for int32/int64
827   template <typename FieldType>
828   PROTOBUF_CC static const char* FastVarintS1(PROTOBUF_TC_PARAM_DECL);
829 
830   friend class GeneratedTcTableLiteTest;
831   static void* MaybeGetSplitBase(MessageLite* msg, bool is_split,
832                                  const TcParseTableBase* table);
833 
834   // Test only access to verify that the right function is being called via
835   // MiniParse.
836   struct TestMiniParseResult {
837     TailCallParseFunc called_func;
838     uint32_t tag;
839     const TcParseTableBase::FieldEntry* found_entry;
840     const char* ptr;
841   };
842   PROTOBUF_NOINLINE
843   static TestMiniParseResult TestMiniParse(PROTOBUF_TC_PARAM_DECL);
844   template <bool export_called_function>
845   PROTOBUF_CC static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
846 
847   template <typename TagType, bool group_coding, bool aux_is_table>
848   PROTOBUF_CC static inline const char* SingularParseMessageAuxImpl(
849       PROTOBUF_TC_PARAM_DECL);
850   template <typename TagType, bool group_coding, bool aux_is_table>
851   PROTOBUF_CC static inline const char* RepeatedParseMessageAuxImpl(
852       PROTOBUF_TC_PARAM_DECL);
853   template <typename TagType>
854   PROTOBUF_CC static inline const char* LazyMessage(PROTOBUF_TC_PARAM_DECL);
855 
856   template <typename TagType>
857   PROTOBUF_CC static const char* FastEndGroupImpl(PROTOBUF_TC_PARAM_DECL);
858 
SyncHasbits(MessageLite * msg,uint64_t hasbits,const TcParseTableBase * table)859   static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits(
860       MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) {
861     const uint32_t has_bits_offset = table->has_bits_offset;
862     if (has_bits_offset) {
863       // Only the first 32 has-bits are updated. Nothing above those is stored,
864       // but e.g. messages without has-bits update the upper bits.
865       RefAt<uint32_t>(msg, has_bits_offset) |= static_cast<uint32_t>(hasbits);
866     }
867   }
868 
869   PROTOBUF_CC static const char* TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
870   PROTOBUF_CC static const char* ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
871   PROTOBUF_CC static const char* ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_DECL);
872   PROTOBUF_NOINLINE
873   PROTOBUF_CC static const char* Error(PROTOBUF_TC_PARAM_NO_DATA_DECL);
874 
875   PROTOBUF_NOINLINE PROTOBUF_CC static const char* FastUnknownEnumFallback(
876       PROTOBUF_TC_PARAM_DECL);
877   PROTOBUF_NOINLINE
878   PROTOBUF_CC static const char* MpUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
879 
880   class ScopedArenaSwap;
881 
882   struct UnknownFieldOps {
883     void (*write_varint)(MessageLite* msg, int number, int value);
884     void (*write_length_delimited)(MessageLite* msg, int number,
885                                    absl::string_view value);
886   };
887 
888   static const UnknownFieldOps& GetUnknownFieldOps(
889       const TcParseTableBase* table);
890 
891   template <typename UnknownFieldsT>
WriteVarintToUnknown(MessageLite * msg,int number,int value)892   static void WriteVarintToUnknown(MessageLite* msg, int number, int value) {
893     internal::WriteVarint(
894         number, value,
895         msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>());
896   }
897   template <typename UnknownFieldsT>
WriteLengthDelimitedToUnknown(MessageLite * msg,int number,absl::string_view value)898   static void WriteLengthDelimitedToUnknown(MessageLite* msg, int number,
899                                             absl::string_view value) {
900     internal::WriteLengthDelimited(
901         number, value,
902         msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>());
903   }
904 
905   template <class MessageBaseT, class UnknownFieldsT>
GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL)906   PROTOBUF_CC static const char* GenericFallbackImpl(PROTOBUF_TC_PARAM_DECL) {
907     if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
908       // This is the ABI used by GetUnknownFieldOps(). Return the vtable.
909       static constexpr UnknownFieldOps kOps = {
910           WriteVarintToUnknown<UnknownFieldsT>,
911           WriteLengthDelimitedToUnknown<UnknownFieldsT>};
912       return reinterpret_cast<const char*>(&kOps);
913     }
914 
915     SyncHasbits(msg, hasbits, table);
916     uint32_t tag = data.tag();
917     if ((tag & 7) == WireFormatLite::WIRETYPE_END_GROUP || tag == 0) {
918       ctx->SetLastTag(tag);
919       return ptr;
920     }
921 
922     if (table->extension_offset != 0) {
923       // We don't need to check the extension ranges. If it is not an extension
924       // it will be handled just like if it was an unknown extension: sent to
925       // the unknown field set.
926       return RefAt<ExtensionSet>(msg, table->extension_offset)
927           .ParseField(
928               tag, ptr,
929               static_cast<const MessageBaseT*>(table->default_instance()),
930               &msg->_internal_metadata_, ctx);
931     } else {
932       // Otherwise, we directly put it on the unknown field set.
933       return UnknownFieldParse(
934           tag,
935           msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
936           ptr, ctx);
937     }
938   }
939 
940   template <class MessageBaseT>
MessageSetWireFormatParseLoopImpl(PROTOBUF_TC_PARAM_NO_DATA_DECL)941   PROTOBUF_CC static const char* MessageSetWireFormatParseLoopImpl(
942       PROTOBUF_TC_PARAM_NO_DATA_DECL) {
943     return RefAt<ExtensionSet>(msg, table->extension_offset)
944         .ParseMessageSet(
945             ptr, static_cast<const MessageBaseT*>(table->default_instance()),
946             &msg->_internal_metadata_, ctx);
947   }
948 
949   // Note: `inline` is needed on template function declarations below to avoid
950   // -Wattributes diagnostic in GCC.
951 
952   // Implementations for fast fixed field parsing functions:
953   template <typename LayoutType, typename TagType>
954   PROTOBUF_CC static inline const char* SingularFixed(PROTOBUF_TC_PARAM_DECL);
955   template <typename LayoutType, typename TagType>
956   PROTOBUF_CC static inline const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL);
957   template <typename LayoutType, typename TagType>
958   PROTOBUF_CC static inline const char* PackedFixed(PROTOBUF_TC_PARAM_DECL);
959 
960   // Implementations for fast varint field parsing functions:
961   template <typename FieldType, typename TagType, bool zigzag = false>
962   PROTOBUF_CC static inline const char* SingularVarint(PROTOBUF_TC_PARAM_DECL);
963   template <typename FieldType, typename TagType, bool zigzag = false>
964   PROTOBUF_CC static inline const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL);
965   template <typename FieldType, typename TagType, bool zigzag = false>
966   PROTOBUF_CC static inline const char* PackedVarint(PROTOBUF_TC_PARAM_DECL);
967 
968   // Helper for ints > 127:
969   template <typename FieldType, typename TagType, bool zigzag = false>
970   PROTOBUF_NOINLINE PROTOBUF_CC static const char* SingularVarBigint(
971       PROTOBUF_TC_PARAM_DECL);
972 
973   // Implementations for fast enum field parsing functions:
974   template <typename TagType, uint16_t xform_val>
975   PROTOBUF_CC static inline const char* SingularEnum(PROTOBUF_TC_PARAM_DECL);
976   template <typename TagType, uint8_t min>
977   PROTOBUF_CC static inline const char* SingularEnumSmallRange(
978       PROTOBUF_TC_PARAM_DECL);
979   template <typename TagType, uint16_t xform_val>
980   PROTOBUF_CC static inline const char* RepeatedEnum(PROTOBUF_TC_PARAM_DECL);
981   template <typename TagType, uint16_t xform_val>
982   PROTOBUF_CC static inline const char* PackedEnum(PROTOBUF_TC_PARAM_DECL);
983   template <typename TagType, uint8_t min>
984   PROTOBUF_CC static inline const char* RepeatedEnumSmallRange(
985       PROTOBUF_TC_PARAM_DECL);
986   template <typename TagType, uint8_t min>
987   PROTOBUF_CC static inline const char* PackedEnumSmallRange(
988       PROTOBUF_TC_PARAM_DECL);
989 
990   // Implementations for fast string field parsing functions:
991   enum Utf8Type { kNoUtf8 = 0, kUtf8 = 1, kUtf8ValidateOnly = 2 };
992   template <typename TagType, typename FieldType, Utf8Type utf8>
993   PROTOBUF_CC static inline const char* SingularString(PROTOBUF_TC_PARAM_DECL);
994   template <typename TagType, typename FieldType, Utf8Type utf8>
995   PROTOBUF_CC static inline const char* RepeatedString(PROTOBUF_TC_PARAM_DECL);
996 
997   static inline const char* ParseRepeatedStringOnce(
998       const char* ptr, SerialArena* serial_arena, ParseContext* ctx,
999       RepeatedPtrField<std::string>& field);
1000 
1001   PROTOBUF_NOINLINE
1002   static void AddUnknownEnum(MessageLite* msg, const TcParseTableBase* table,
1003                              uint32_t tag, int32_t enum_value);
1004 
1005   static void WriteMapEntryAsUnknown(MessageLite* msg,
1006                                      const TcParseTableBase* table,
1007                                      uint32_t tag, NodeBase* node,
1008                                      MapAuxInfo map_info);
1009 
1010   static void InitializeMapNodeEntry(void* obj, MapTypeCard type_card,
1011                                      UntypedMapBase& map,
1012                                      const TcParseTableBase::FieldAux* aux,
1013                                      bool is_key);
1014   PROTOBUF_NOINLINE
1015   static void DestroyMapNode(NodeBase* node, MapAuxInfo map_info,
1016                              UntypedMapBase& map);
1017   static const char* ParseOneMapEntry(NodeBase* node, const char* ptr,
1018                                       ParseContext* ctx,
1019                                       const TcParseTableBase::FieldAux* aux,
1020                                       const TcParseTableBase* table,
1021                                       const TcParseTableBase::FieldEntry& entry,
1022                                       Arena* arena);
1023 
1024   // Mini field lookup:
1025   static const TcParseTableBase::FieldEntry* FindFieldEntry(
1026       const TcParseTableBase* table, uint32_t field_num);
1027   static absl::string_view MessageName(const TcParseTableBase* table);
1028   static absl::string_view FieldName(const TcParseTableBase* table,
1029                                      const TcParseTableBase::FieldEntry*);
1030   static bool ChangeOneof(const TcParseTableBase* table,
1031                           const TcParseTableBase::FieldEntry& entry,
1032                           uint32_t field_num, ParseContext* ctx,
1033                           MessageLite* msg);
1034 
1035   // UTF-8 validation:
1036   static void ReportFastUtf8Error(uint32_t decoded_tag,
1037                                   const TcParseTableBase* table);
1038   static bool MpVerifyUtf8(absl::string_view wire_bytes,
1039                            const TcParseTableBase* table,
1040                            const TcParseTableBase::FieldEntry& entry,
1041                            uint16_t xform_val);
1042   static bool MpVerifyUtf8(const absl::Cord& wire_bytes,
1043                            const TcParseTableBase* table,
1044                            const TcParseTableBase::FieldEntry& entry,
1045                            uint16_t xform_val);
1046 
1047   // For FindFieldEntry tests:
1048   friend class FindFieldEntryTest;
1049   friend struct ParseFunctionGeneratorTestPeer;
1050   friend struct FuzzPeer;
1051   static constexpr const uint32_t kMtSmallScanSize = 4;
1052 
1053   // Mini parsing:
1054   template <bool is_split>
1055   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpVarint(
1056       PROTOBUF_TC_PARAM_DECL);
1057   template <bool is_split>
1058   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpRepeatedVarint(
1059       PROTOBUF_TC_PARAM_DECL);
1060   template <bool is_split, typename FieldType, uint16_t xform_val>
1061   PROTOBUF_CC static const char* MpRepeatedVarintT(PROTOBUF_TC_PARAM_DECL);
1062   template <bool is_split>
1063   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpPackedVarint(
1064       PROTOBUF_TC_PARAM_DECL);
1065   template <bool is_split, typename FieldType, uint16_t xform_val>
1066   PROTOBUF_CC static const char* MpPackedVarintT(PROTOBUF_TC_PARAM_DECL);
1067   template <bool is_split>
1068   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpFixed(
1069       PROTOBUF_TC_PARAM_DECL);
1070   template <bool is_split>
1071   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpRepeatedFixed(
1072       PROTOBUF_TC_PARAM_DECL);
1073   template <bool is_split>
1074   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpPackedFixed(
1075       PROTOBUF_TC_PARAM_DECL);
1076   template <bool is_split>
1077   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpString(
1078       PROTOBUF_TC_PARAM_DECL);
1079   template <bool is_split>
1080   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpRepeatedString(
1081       PROTOBUF_TC_PARAM_DECL);
1082   template <bool is_split>
1083   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpMessage(
1084       PROTOBUF_TC_PARAM_DECL);
1085   template <bool is_split, bool is_group>
1086   PROTOBUF_CC static const char* MpRepeatedMessageOrGroup(
1087       PROTOBUF_TC_PARAM_DECL);
1088   PROTOBUF_CC static const char* MpLazyMessage(PROTOBUF_TC_PARAM_DECL);
1089   PROTOBUF_NOINLINE
1090   PROTOBUF_CC static const char* MpFallback(PROTOBUF_TC_PARAM_DECL);
1091   template <bool is_split>
1092   PROTOBUF_NOINLINE PROTOBUF_CC static const char* MpMap(
1093       PROTOBUF_TC_PARAM_DECL);
1094 };
1095 
1096 // Dispatch to the designated parse function
TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL)1097 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
1098     PROTOBUF_TC_PARAM_NO_DATA_DECL) {
1099   const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
1100   const size_t idx = coded_tag & table->fast_idx_mask;
1101   PROTOBUF_ASSUME((idx & 7) == 0);
1102   auto* fast_entry = table->fast_entry(idx >> 3);
1103   TcFieldData data = fast_entry->bits;
1104   data.data ^= coded_tag;
1105   PROTOBUF_MUSTTAIL return fast_entry->target()(PROTOBUF_TC_PARAM_PASS);
1106 }
1107 
1108 // We can only safely call from field to next field if the call is optimized
1109 // to a proper tail call. Otherwise we blow through stack. Clang and gcc
1110 // reliably do this optimization in opt mode, but do not perform this in debug
1111 // mode. Luckily the structure of the algorithm is such that it's always
1112 // possible to just return and use the enclosing parse loop as a trampoline.
ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL)1113 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
1114     PROTOBUF_TC_PARAM_NO_DATA_DECL) {
1115   constexpr bool always_return = !PROTOBUF_TAILCALL;
1116   if (always_return || !ctx->DataAvailable(ptr)) {
1117     PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
1118   }
1119   PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
1120 }
1121 
ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_DECL)1122 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
1123     PROTOBUF_TC_PARAM_NO_DATA_DECL) {
1124   (void)ctx;
1125   SyncHasbits(msg, hasbits, table);
1126   return ptr;
1127 }
1128 
ParseLoop(MessageLite * msg,const char * ptr,ParseContext * ctx,const TcParseTableBase * table)1129 inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ParseLoop(
1130     MessageLite* msg, const char* ptr, ParseContext* ctx,
1131     const TcParseTableBase* table) {
1132   // Note: TagDispatch uses a dispatch table at "&table->fast_entries".
1133   // For fast dispatch, we'd like to have a pointer to that, but if we use
1134   // that expression, there's no easy way to get back to "table", which we also
1135   // need during dispatch.  It turns out that "table + 1" points exactly to
1136   // fast_entries, so we just increment table by 1 here, to get the register
1137   // holding the value we want.
1138   table += 1;
1139   while (!ctx->Done(&ptr)) {
1140 #if defined(__GNUC__)
1141     // Note: this asm prevents the compiler (clang, specifically) from
1142     // believing (thanks to CSE) that it needs to dedicate a register both
1143     // to "table" and "&table->fast_entries".
1144     // TODO: remove this asm
1145     asm("" : "+r"(table));
1146 #endif
1147     ptr = TagDispatch(msg, ptr, ctx, TcFieldData::DefaultInit(), table - 1, 0);
1148     if (ptr == nullptr) break;
1149     if (ctx->LastTag() != 1) break;  // Ended on terminating tag
1150   }
1151   table -= 1;
1152   if (ABSL_PREDICT_FALSE(table->has_post_loop_handler)) {
1153     return table->post_loop_handler(msg, ptr, ctx);
1154   }
1155   return ptr;
1156 }
1157 
1158 // Prints the type card as or of labels, using known higher level labels.
1159 // Used for code generation, but also useful for debugging.
1160 PROTOBUF_EXPORT std::string TypeCardToString(uint16_t type_card);
1161 
1162 }  // namespace internal
1163 }  // namespace protobuf
1164 }  // namespace google
1165 
1166 #include "google/protobuf/port_undef.inc"
1167 
1168 #endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_IMPL_H__
1169