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