• 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 #include "google/protobuf/generated_message_tctable_gen.h"
9 
10 #include <algorithm>
11 #include <cstddef>
12 #include <cstdint>
13 #include <cstring>
14 #include <limits>
15 #include <vector>
16 
17 #include "absl/container/fixed_array.h"
18 #include "absl/log/absl_check.h"
19 #include "absl/numeric/bits.h"
20 #include "absl/strings/string_view.h"
21 #include "absl/types/optional.h"
22 #include "absl/types/span.h"
23 #include "google/protobuf/descriptor.h"
24 #include "google/protobuf/descriptor.pb.h"
25 #include "google/protobuf/generated_message_tctable_decl.h"
26 #include "google/protobuf/generated_message_tctable_impl.h"
27 #include "google/protobuf/port.h"
28 #include "google/protobuf/wire_format.h"
29 #include "google/protobuf/wire_format_lite.h"
30 
31 // Must come last:
32 #include "google/protobuf/port_def.inc"
33 
34 namespace google {
35 namespace protobuf {
36 namespace internal {
37 
38 namespace {
39 
TreatEnumAsInt(const FieldDescriptor * field)40 bool TreatEnumAsInt(const FieldDescriptor* field) {
41   return cpp::HasPreservingUnknownEnumSemantics(field) ||
42          // For legacy reasons, MapEntry mapped_type enum fields are handled as
43          // open always. The validation happens elsewhere.
44          (field->enum_type() != nullptr &&
45           field->containing_type() != nullptr &&
46           field->containing_type()->map_value() == field);
47 }
48 
SetEnumValidationRange(int start_value,int64_t size_value,int16_t & start,uint16_t & size)49 bool SetEnumValidationRange(int start_value, int64_t size_value, int16_t& start,
50                             uint16_t& size) {
51   if (static_cast<int16_t>(start_value) != start_value) {
52     return false;
53   }
54 
55   if (static_cast<uint16_t>(size_value) != size_value) {
56     return false;
57   }
58 
59   start = start_value;
60   size = size_value;
61   return true;
62 }
63 
GetEnumValidationRangeSlow(const EnumDescriptor * enum_type,int16_t & start,uint16_t & size)64 bool GetEnumValidationRangeSlow(const EnumDescriptor* enum_type, int16_t& start,
65                                 uint16_t& size) {
66   const auto val = [&](int index) { return enum_type->value(index)->number(); };
67   int min = val(0);
68   int max = min;
69 
70   for (int i = 1, N = static_cast<int>(enum_type->value_count()); i < N; ++i) {
71     min = std::min(min, val(i));
72     max = std::max(max, val(i));
73   }
74 
75   // int64 because max-min can overflow int.
76   int64_t range = static_cast<int64_t>(max) - static_cast<int64_t>(min) + 1;
77 
78   if (enum_type->value_count() < range) {
79     // There are not enough values to fill the range. Exit early.
80     return false;
81   }
82 
83   if (!SetEnumValidationRange(min, range, start, size)) {
84     // Don't even bother on checking for a dense range if we can't represent the
85     // min/max in the output.
86     return false;
87   }
88 
89   absl::FixedArray<uint64_t> array((range + 63) / 64);
90   array.fill(0);
91 
92   int unique_count = 0;
93   for (int i = 0, N = static_cast<int>(enum_type->value_count()); i < N; ++i) {
94     size_t index = val(i) - min;
95     uint64_t& v = array[index / 64];
96     size_t bit_pos = index % 64;
97     unique_count += (v & (uint64_t{1} << bit_pos)) == 0;
98     v |= uint64_t{1} << bit_pos;
99   }
100 
101   return unique_count == range;
102 }
103 
GetEnumValidationRange(const EnumDescriptor * enum_type,int16_t & start,uint16_t & size)104 bool GetEnumValidationRange(const EnumDescriptor* enum_type, int16_t& start,
105                             uint16_t& size) {
106   if (!IsEnumFullySequential(enum_type)) {
107     // Maybe the labels are not sequential in declaration order, but the values
108     // could still be a dense range. Try the slower approach.
109     return GetEnumValidationRangeSlow(enum_type, start, size);
110   }
111 
112   return SetEnumValidationRange(enum_type->value(0)->number(),
113                                 enum_type->value_count(), start, size);
114 }
115 
116 enum class EnumRangeInfo {
117   kNone,         // No contiguous range
118   kContiguous,   // Has a contiguous range
119   kContiguous0,  // Has a small contiguous range starting at 0
120   kContiguous1,  // Has a small contiguous range starting at 1
121 };
122 
123 // Returns enum validation range info, and sets `rmax_value` iff
124 // the returned range is a small range. `rmax_value` is guaranteed
125 // to remain unchanged if the enum range is not small.
GetEnumRangeInfo(const FieldDescriptor * field,uint8_t & rmax_value)126 EnumRangeInfo GetEnumRangeInfo(const FieldDescriptor* field,
127                                uint8_t& rmax_value) {
128   int16_t start;
129   uint16_t size;
130   if (!GetEnumValidationRange(field->enum_type(), start, size)) {
131     return EnumRangeInfo::kNone;
132   }
133   int max_value = start + size - 1;
134   if (max_value <= 127 && (start == 0 || start == 1)) {
135     rmax_value = static_cast<uint8_t>(max_value);
136     return start == 0 ? EnumRangeInfo::kContiguous0
137                       : EnumRangeInfo::kContiguous1;
138   }
139   return EnumRangeInfo::kContiguous;
140 }
141 
142 // options.lazy_opt might be on for fields that don't really support lazy, so we
143 // make sure we only use lazy rep for singular TYPE_MESSAGE fields.
144 // We can't trust the `lazy=true` annotation.
HasLazyRep(const FieldDescriptor * field,const TailCallTableInfo::FieldOptions & options)145 bool HasLazyRep(const FieldDescriptor* field,
146                 const TailCallTableInfo::FieldOptions& options) {
147   return field->type() == field->TYPE_MESSAGE && !field->is_repeated() &&
148          options.lazy_opt != 0;
149 }
150 
MakeFastFieldEntry(const TailCallTableInfo::FieldEntryInfo & entry,const TailCallTableInfo::FieldOptions & options,const TailCallTableInfo::MessageOptions & message_options)151 TailCallTableInfo::FastFieldInfo::Field MakeFastFieldEntry(
152     const TailCallTableInfo::FieldEntryInfo& entry,
153     const TailCallTableInfo::FieldOptions& options,
154     const TailCallTableInfo::MessageOptions& message_options) {
155   TailCallTableInfo::FastFieldInfo::Field info{};
156 #define PROTOBUF_PICK_FUNCTION(fn) \
157   (field->number() < 16 ? TcParseFunction::fn##1 : TcParseFunction::fn##2)
158 
159 #define PROTOBUF_PICK_SINGLE_FUNCTION(fn) PROTOBUF_PICK_FUNCTION(fn##S)
160 
161 #define PROTOBUF_PICK_REPEATABLE_FUNCTION(fn)           \
162   (field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
163                         : PROTOBUF_PICK_FUNCTION(fn##S))
164 
165 #define PROTOBUF_PICK_PACKABLE_FUNCTION(fn)               \
166   (field->is_packed()     ? PROTOBUF_PICK_FUNCTION(fn##P) \
167    : field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
168                           : PROTOBUF_PICK_FUNCTION(fn##S))
169 
170 #define PROTOBUF_PICK_STRING_FUNCTION(fn)                            \
171   (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord \
172        ? PROTOBUF_PICK_FUNCTION(fn##cS)                              \
173    : options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS)      \
174                                : PROTOBUF_PICK_REPEATABLE_FUNCTION(fn))
175 
176   const FieldDescriptor* field = entry.field;
177   info.aux_idx = static_cast<uint8_t>(entry.aux_idx);
178   if (field->type() == FieldDescriptor::TYPE_BYTES ||
179       field->type() == FieldDescriptor::TYPE_STRING) {
180     if (options.is_string_inlined) {
181       ABSL_CHECK(!field->is_repeated());
182       info.aux_idx = static_cast<uint8_t>(entry.inlined_string_idx);
183     }
184   }
185 
186   TcParseFunction picked = TcParseFunction::kNone;
187   switch (field->type()) {
188     case FieldDescriptor::TYPE_BOOL:
189       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV8);
190       break;
191     case FieldDescriptor::TYPE_INT32:
192     case FieldDescriptor::TYPE_UINT32:
193       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
194       break;
195     case FieldDescriptor::TYPE_SINT32:
196       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastZ32);
197       break;
198     case FieldDescriptor::TYPE_INT64:
199     case FieldDescriptor::TYPE_UINT64:
200       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV64);
201       break;
202     case FieldDescriptor::TYPE_SINT64:
203       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastZ64);
204       break;
205     case FieldDescriptor::TYPE_FLOAT:
206     case FieldDescriptor::TYPE_FIXED32:
207     case FieldDescriptor::TYPE_SFIXED32:
208       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastF32);
209       break;
210     case FieldDescriptor::TYPE_DOUBLE:
211     case FieldDescriptor::TYPE_FIXED64:
212     case FieldDescriptor::TYPE_SFIXED64:
213       picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastF64);
214       break;
215     case FieldDescriptor::TYPE_ENUM:
216       if (TreatEnumAsInt(field)) {
217         picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
218       } else {
219         switch (GetEnumRangeInfo(field, info.aux_idx)) {
220           case EnumRangeInfo::kNone:
221             picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv);
222             break;
223           case EnumRangeInfo::kContiguous:
224             picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr);
225             break;
226           case EnumRangeInfo::kContiguous0:
227             picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr0);
228             break;
229           case EnumRangeInfo::kContiguous1:
230             picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr1);
231             break;
232         }
233       }
234       break;
235     case FieldDescriptor::TYPE_BYTES:
236       picked = PROTOBUF_PICK_STRING_FUNCTION(kFastB);
237       break;
238     case FieldDescriptor::TYPE_STRING:
239       switch (entry.utf8_check_mode) {
240         case cpp::Utf8CheckMode::kStrict:
241           picked = PROTOBUF_PICK_STRING_FUNCTION(kFastU);
242           break;
243         case cpp::Utf8CheckMode::kVerify:
244           picked = PROTOBUF_PICK_STRING_FUNCTION(kFastS);
245           break;
246         case cpp::Utf8CheckMode::kNone:
247           picked = PROTOBUF_PICK_STRING_FUNCTION(kFastB);
248           break;
249       }
250       break;
251     case FieldDescriptor::TYPE_MESSAGE:
252       picked =
253           (HasLazyRep(field, options) ? PROTOBUF_PICK_SINGLE_FUNCTION(kFastMl)
254            : options.use_direct_tcparser_table
255                ? PROTOBUF_PICK_REPEATABLE_FUNCTION(kFastMt)
256                : PROTOBUF_PICK_REPEATABLE_FUNCTION(kFastMd));
257       break;
258     case FieldDescriptor::TYPE_GROUP:
259       picked = (options.use_direct_tcparser_table
260                     ? PROTOBUF_PICK_REPEATABLE_FUNCTION(kFastGt)
261                     : PROTOBUF_PICK_REPEATABLE_FUNCTION(kFastGd));
262       break;
263   }
264 
265   ABSL_CHECK(picked != TcParseFunction::kNone);
266   info.func = picked;
267   info.presence_probability = options.presence_probability;
268   return info;
269 
270 #undef PROTOBUF_PICK_FUNCTION
271 #undef PROTOBUF_PICK_SINGLE_FUNCTION
272 #undef PROTOBUF_PICK_REPEATABLE_FUNCTION
273 #undef PROTOBUF_PICK_PACKABLE_FUNCTION
274 #undef PROTOBUF_PICK_STRING_FUNCTION
275 }
276 
IsFieldEligibleForFastParsing(const TailCallTableInfo::FieldEntryInfo & entry,const TailCallTableInfo::FieldOptions & options,const TailCallTableInfo::MessageOptions & message_options)277 bool IsFieldEligibleForFastParsing(
278     const TailCallTableInfo::FieldEntryInfo& entry,
279     const TailCallTableInfo::FieldOptions& options,
280     const TailCallTableInfo::MessageOptions& message_options) {
281   const auto* field = entry.field;
282   // Map, oneof, weak, and split fields are not handled on the fast path.
283   if (field->is_map() || field->real_containing_oneof() ||
284       field->options().weak() || options.is_implicitly_weak ||
285       options.should_split) {
286     return false;
287   }
288 
289   if (HasLazyRep(field, options) && !message_options.uses_codegen) {
290     // Can't use TDP on lazy fields if we can't do codegen.
291     return false;
292   }
293 
294   if (HasLazyRep(field, options) && options.lazy_opt == field_layout::kTvLazy) {
295     // We only support eagerly verified lazy fields in the fast path.
296     return false;
297   }
298 
299   // We will check for a valid auxiliary index range later. However, we might
300   // want to change the value we check for inlined string fields.
301   int aux_idx = entry.aux_idx;
302 
303   switch (field->type()) {
304       // Some bytes fields can be handled on fast path.
305     case FieldDescriptor::TYPE_STRING:
306     case FieldDescriptor::TYPE_BYTES: {
307       auto ctype = field->cpp_string_type();
308       if (ctype == FieldDescriptor::CppStringType::kString ||
309           ctype == FieldDescriptor::CppStringType::kView) {
310         // strings are fine...
311       } else if (ctype == FieldDescriptor::CppStringType::kCord) {
312         // Cords are worth putting into the fast table, if they're not repeated
313         if (field->is_repeated()) return false;
314       } else {
315         return false;
316       }
317       if (options.is_string_inlined) {
318         ABSL_CHECK(!field->is_repeated());
319         // For inlined strings, the donation state index is stored in the
320         // `aux_idx` field of the fast parsing info. We need to check the range
321         // of that value instead of the auxiliary index.
322         aux_idx = entry.inlined_string_idx;
323       }
324       break;
325     }
326 
327     case FieldDescriptor::TYPE_ENUM: {
328       uint8_t rmax_value;
329       if (!message_options.uses_codegen &&
330           GetEnumRangeInfo(field, rmax_value) == EnumRangeInfo::kNone) {
331         // We can't use fast parsing for these entries because we can't specify
332         // the validator.
333         // TODO: Implement a fast parser for these enums.
334         return false;
335       }
336       break;
337     }
338 
339     default:
340       break;
341   }
342 
343   // The tailcall parser can only update the first 32 hasbits. Fields with
344   // has-bits beyond the first 32 are handled by mini parsing/fallback.
345   if (entry.hasbit_idx >= 32) return false;
346 
347   // If the field needs auxiliary data, then the aux index is needed. This
348   // must fit in a uint8_t.
349   if (aux_idx > std::numeric_limits<uint8_t>::max()) {
350     return false;
351   }
352 
353   // The largest tag that can be read by the tailcall parser is two bytes
354   // when varint-coded. This allows 14 bits for the numeric tag value:
355   //   byte 0   byte 1
356   //   1nnnnttt 0nnnnnnn
357   //    ^^^^^^^  ^^^^^^^
358   if (field->number() >= 1 << 11) return false;
359 
360   return true;
361 }
362 
GetEndGroupTag(const Descriptor * descriptor)363 absl::optional<uint32_t> GetEndGroupTag(const Descriptor* descriptor) {
364   auto* parent = descriptor->containing_type();
365   if (parent == nullptr) return absl::nullopt;
366   for (int i = 0; i < parent->field_count(); ++i) {
367     auto* field = parent->field(i);
368     if (field->type() == field->TYPE_GROUP &&
369         field->message_type() == descriptor) {
370       return WireFormatLite::MakeTag(field->number(),
371                                      WireFormatLite::WIRETYPE_END_GROUP);
372     }
373   }
374   return absl::nullopt;
375 }
376 
RecodeTagForFastParsing(uint32_t tag)377 uint32_t RecodeTagForFastParsing(uint32_t tag) {
378   ABSL_DCHECK_LE(tag, 0x3FFFu);
379   // Construct the varint-coded tag. If it is more than 7 bits, we need to
380   // shift the high bits and add a continue bit.
381   if (uint32_t hibits = tag & 0xFFFFFF80) {
382     // hi = tag & ~0x7F
383     // lo = tag & 0x7F
384     // This shifts hi to the left by 1 to the next byte and sets the
385     // continuation bit.
386     tag = tag + hibits + 128;
387   }
388   return tag;
389 }
390 
PopulateFastFields(absl::optional<uint32_t> end_group_tag,const std::vector<TailCallTableInfo::FieldEntryInfo> & field_entries,const TailCallTableInfo::MessageOptions & message_options,absl::Span<const TailCallTableInfo::FieldOptions> fields,absl::Span<TailCallTableInfo::FastFieldInfo> result,uint32_t & important_fields)391 void PopulateFastFields(
392     absl::optional<uint32_t> end_group_tag,
393     const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries,
394     const TailCallTableInfo::MessageOptions& message_options,
395     absl::Span<const TailCallTableInfo::FieldOptions> fields,
396     absl::Span<TailCallTableInfo::FastFieldInfo> result,
397     uint32_t& important_fields) {
398   const uint32_t idx_mask = static_cast<uint32_t>(result.size() - 1);
399   const auto tag_to_idx = [&](uint32_t tag) {
400     // The field index is determined by the low bits of the field number, where
401     // the table size determines the width of the mask. The largest table
402     // supported is 32 entries. The parse loop uses these bits directly, so that
403     // the dispatch does not require arithmetic:
404     //        byte 0   byte 1
405     //   tag: 1nnnnttt 0nnnnnnn
406     //        ^^^^^
407     //         idx (table_size_log2=5)
408     // This means that any field number that does not fit in the lower 4 bits
409     // will always have the top bit of its table index asserted.
410     return (tag >> 3) & idx_mask;
411   };
412 
413   if (end_group_tag.has_value() && (*end_group_tag >> 14) == 0) {
414     // Fits in 1 or 2 varint bytes.
415     const uint32_t tag = RecodeTagForFastParsing(*end_group_tag);
416     const uint32_t fast_idx = tag_to_idx(tag);
417 
418     TailCallTableInfo::FastFieldInfo& info = result[fast_idx];
419     info.data = TailCallTableInfo::FastFieldInfo::NonField{
420         *end_group_tag < 128 ? TcParseFunction::kFastEndG1
421                              : TcParseFunction::kFastEndG2,
422         static_cast<uint16_t>(tag),
423         static_cast<uint16_t>(*end_group_tag),
424     };
425     important_fields |= uint32_t{1} << fast_idx;
426   }
427 
428   for (size_t i = 0; i < field_entries.size(); ++i) {
429     const auto& entry = field_entries[i];
430     const auto& options = fields[i];
431     if (!IsFieldEligibleForFastParsing(entry, options, message_options)) {
432       continue;
433     }
434 
435     const auto* field = entry.field;
436     const uint32_t tag = RecodeTagForFastParsing(WireFormat::MakeTag(field));
437     const uint32_t fast_idx = tag_to_idx(tag);
438 
439     TailCallTableInfo::FastFieldInfo& info = result[fast_idx];
440     if (info.AsNonField() != nullptr) {
441       // Right now non-field means END_GROUP which is guaranteed to be present.
442       continue;
443     }
444     if (auto* as_field = info.AsField()) {
445       // This field entry is already filled. Skip if previous entry is more
446       // likely present.
447       if (as_field->presence_probability >= options.presence_probability) {
448         continue;
449       }
450     }
451 
452     // We reset the entry even if it had a field already.
453     // Fill in this field's entry:
454     auto& fast_field =
455         info.data.emplace<TailCallTableInfo::FastFieldInfo::Field>(
456             MakeFastFieldEntry(entry, options, message_options));
457     fast_field.field = field;
458     fast_field.coded_tag = tag;
459     // If this field does not have presence, then it can set an out-of-bounds
460     // bit (tailcall parsing uses a uint64_t for hasbits, but only stores 32).
461     fast_field.hasbit_idx = entry.hasbit_idx >= 0 ? entry.hasbit_idx : 63;
462     // 0.05 was selected based on load tests where 0.1 and 0.01 were also
463     // evaluated and worse.
464     constexpr float kMinPresence = 0.05f;
465     important_fields |= uint32_t{options.presence_probability >= kMinPresence}
466                         << fast_idx;
467   }
468 }
469 
GenerateFieldNames(const Descriptor * descriptor,const absl::Span<const TailCallTableInfo::FieldEntryInfo> entries,const TailCallTableInfo::MessageOptions & message_options,absl::Span<const TailCallTableInfo::FieldOptions> fields)470 std::vector<uint8_t> GenerateFieldNames(
471     const Descriptor* descriptor,
472     const absl::Span<const TailCallTableInfo::FieldEntryInfo> entries,
473     const TailCallTableInfo::MessageOptions& message_options,
474     absl::Span<const TailCallTableInfo::FieldOptions> fields) {
475   static constexpr size_t kMaxNameLength = 255;
476 
477   size_t field_name_total_size = 0;
478   const auto for_each_field_name = [&](auto with_name, auto no_name) {
479     for (const auto& entry : entries) {
480       // We only need field names for reporting UTF-8 parsing errors, so we only
481       // emit them for string fields with Utf8 transform specified.
482       if (entry.utf8_check_mode != cpp::Utf8CheckMode::kNone) {
483         with_name(absl::string_view(entry.field->name()));
484       } else {
485         no_name();
486       }
487     }
488   };
489 
490   for_each_field_name([&](auto name) { field_name_total_size += name.size(); },
491                       [] {});
492 
493   // No names needed. Omit the whole table.
494   if (field_name_total_size == 0) {
495     return {};
496   }
497 
498   const absl::string_view message_name = descriptor->full_name();
499   uint8_t message_name_size =
500       static_cast<uint8_t>(std::min(message_name.size(), kMaxNameLength));
501   size_t total_byte_size =
502       ((/* message */ 1 + /* fields */ entries.size() + /* round up */ 7) &
503        ~7) +
504       message_name_size + field_name_total_size;
505 
506   std::vector<uint8_t> out_vec(total_byte_size, uint8_t{0});
507   uint8_t* out_it = out_vec.data();
508 
509   // First, we output the size of each string, as an unsigned byte. The first
510   // string is the message name.
511   int count = 1;
512   *out_it++ = message_name_size;
513   for_each_field_name(
514       [&](auto name) {
515         *out_it++ = static_cast<uint8_t>(name.size());
516         ++count;
517       },
518       [&] {
519         ++out_it;
520         ++count;
521       });
522   // align to an 8-byte boundary
523   out_it += -count & 7;
524 
525   const auto append = [&](absl::string_view str) {
526     if (!str.empty()) {
527       memcpy(out_it, str.data(), str.size());
528       out_it += str.size();
529     }
530   };
531 
532   // The message name is stored at the beginning of the string
533   if (message_name.size() > kMaxNameLength) {
534     static constexpr int kNameHalfLength = (kMaxNameLength - 3) / 2;
535     append(message_name.substr(0, kNameHalfLength));
536     append("...");
537     append(message_name.substr(message_name.size() - kNameHalfLength));
538   } else {
539     append(message_name);
540   }
541   // Then we output the actual field names
542   for_each_field_name([&](auto name) { append(name); }, [] {});
543 
544   return out_vec;
545 }
546 
MakeNumToEntryTable(absl::Span<const TailCallTableInfo::FieldOptions> ordered_fields)547 TailCallTableInfo::NumToEntryTable MakeNumToEntryTable(
548     absl::Span<const TailCallTableInfo::FieldOptions> ordered_fields) {
549   TailCallTableInfo::NumToEntryTable num_to_entry_table;
550   num_to_entry_table.skipmap32 = static_cast<uint32_t>(-1);
551 
552   // skip_entry_block is the current block of SkipEntries that we're
553   // appending to.  cur_block_first_fnum is the number of the first
554   // field represented by the block.
555   uint16_t field_entry_index = 0;
556   uint16_t N = ordered_fields.size();
557   // First, handle field numbers 1-32, which affect only the initial
558   // skipmap32 and don't generate additional skip-entry blocks.
559   for (; field_entry_index != N; ++field_entry_index) {
560     auto* field_descriptor = ordered_fields[field_entry_index].field;
561     if (field_descriptor->number() > 32) break;
562     auto skipmap32_index = field_descriptor->number() - 1;
563     num_to_entry_table.skipmap32 -= 1 << skipmap32_index;
564   }
565   // If all the field numbers were less than or equal to 32, we will have
566   // no further entries to process, and we are already done.
567   if (field_entry_index == N) return num_to_entry_table;
568 
569   TailCallTableInfo::SkipEntryBlock* block = nullptr;
570   bool start_new_block = true;
571   // To determine sparseness, track the field number corresponding to
572   // the start of the most recent skip entry.
573   uint32_t last_skip_entry_start = 0;
574   for (; field_entry_index != N; ++field_entry_index) {
575     auto* field_descriptor = ordered_fields[field_entry_index].field;
576     uint32_t fnum = static_cast<uint32_t>(field_descriptor->number());
577     ABSL_CHECK_GT(fnum, last_skip_entry_start);
578     if (start_new_block == false) {
579       // If the next field number is within 15 of the last_skip_entry_start, we
580       // continue writing just to that entry.  If it's between 16 and 31 more,
581       // then we just extend the current block by one. If it's more than 31
582       // more, we have to add empty skip entries in order to continue using the
583       // existing block.  Obviously it's just 32 more, it doesn't make sense to
584       // start a whole new block, since new blocks mean having to write out
585       // their starting field number, which is 32 bits, as well as the size of
586       // the additional block, which is 16... while an empty SkipEntry16 only
587       // costs 32 bits.  So if it was 48 more, it's a slight space win; we save
588       // 16 bits, but probably at the cost of slower run time.  We're choosing
589       // 96 for now.
590       if (fnum - last_skip_entry_start > 96) start_new_block = true;
591     }
592     if (start_new_block) {
593       num_to_entry_table.blocks.push_back({fnum});
594       block = &num_to_entry_table.blocks.back();
595       start_new_block = false;
596     }
597 
598     auto skip_entry_num = (fnum - block->first_fnum) / 16;
599     auto skip_entry_index = (fnum - block->first_fnum) % 16;
600     while (skip_entry_num >= block->entries.size())
601       block->entries.push_back({0xFFFF, field_entry_index});
602     block->entries[skip_entry_num].skipmap -= 1 << (skip_entry_index);
603 
604     last_skip_entry_start = fnum - skip_entry_index;
605   }
606   return num_to_entry_table;
607 }
608 
MakeTypeCardForField(const FieldDescriptor * field,bool has_hasbit,const TailCallTableInfo::FieldOptions & options,cpp::Utf8CheckMode utf8_check_mode)609 uint16_t MakeTypeCardForField(
610     const FieldDescriptor* field, bool has_hasbit,
611     const TailCallTableInfo::FieldOptions& options,
612     cpp::Utf8CheckMode utf8_check_mode) {
613   uint16_t type_card;
614   namespace fl = internal::field_layout;
615   if (has_hasbit) {
616     type_card = fl::kFcOptional;
617   } else if (field->is_repeated()) {
618     type_card = fl::kFcRepeated;
619   } else if (field->real_containing_oneof()) {
620     type_card = fl::kFcOneof;
621   } else {
622     type_card = fl::kFcSingular;
623   }
624 
625   // The rest of the type uses convenience aliases:
626   switch (field->type()) {
627     case FieldDescriptor::TYPE_DOUBLE:
628       type_card |= field->is_repeated() && field->is_packed()
629                        ? fl::kPackedDouble
630                        : fl::kDouble;
631       break;
632     case FieldDescriptor::TYPE_FLOAT:
633       type_card |= field->is_repeated() && field->is_packed() ? fl::kPackedFloat
634                                                               : fl::kFloat;
635       break;
636     case FieldDescriptor::TYPE_FIXED32:
637       type_card |= field->is_repeated() && field->is_packed()
638                        ? fl::kPackedFixed32
639                        : fl::kFixed32;
640       break;
641     case FieldDescriptor::TYPE_SFIXED32:
642       type_card |= field->is_repeated() && field->is_packed()
643                        ? fl::kPackedSFixed32
644                        : fl::kSFixed32;
645       break;
646     case FieldDescriptor::TYPE_FIXED64:
647       type_card |= field->is_repeated() && field->is_packed()
648                        ? fl::kPackedFixed64
649                        : fl::kFixed64;
650       break;
651     case FieldDescriptor::TYPE_SFIXED64:
652       type_card |= field->is_repeated() && field->is_packed()
653                        ? fl::kPackedSFixed64
654                        : fl::kSFixed64;
655       break;
656     case FieldDescriptor::TYPE_BOOL:
657       type_card |= field->is_repeated() && field->is_packed() ? fl::kPackedBool
658                                                               : fl::kBool;
659       break;
660     case FieldDescriptor::TYPE_ENUM:
661       if (TreatEnumAsInt(field)) {
662         // No validation is required.
663         type_card |= field->is_repeated() && field->is_packed()
664                          ? fl::kPackedOpenEnum
665                          : fl::kOpenEnum;
666       } else {
667         int16_t start;
668         uint16_t size;
669         if (GetEnumValidationRange(field->enum_type(), start, size)) {
670           // Validation is done by range check (start/length in FieldAux).
671           type_card |= field->is_repeated() && field->is_packed()
672                            ? fl::kPackedEnumRange
673                            : fl::kEnumRange;
674         } else {
675           // Validation uses the generated _IsValid function.
676           type_card |= field->is_repeated() && field->is_packed()
677                            ? fl::kPackedEnum
678                            : fl::kEnum;
679         }
680       }
681       break;
682     case FieldDescriptor::TYPE_UINT32:
683       type_card |= field->is_repeated() && field->is_packed()
684                        ? fl::kPackedUInt32
685                        : fl::kUInt32;
686       break;
687     case FieldDescriptor::TYPE_SINT32:
688       type_card |= field->is_repeated() && field->is_packed()
689                        ? fl::kPackedSInt32
690                        : fl::kSInt32;
691       break;
692     case FieldDescriptor::TYPE_INT32:
693       type_card |= field->is_repeated() && field->is_packed() ? fl::kPackedInt32
694                                                               : fl::kInt32;
695       break;
696     case FieldDescriptor::TYPE_UINT64:
697       type_card |= field->is_repeated() && field->is_packed()
698                        ? fl::kPackedUInt64
699                        : fl::kUInt64;
700       break;
701     case FieldDescriptor::TYPE_SINT64:
702       type_card |= field->is_repeated() && field->is_packed()
703                        ? fl::kPackedSInt64
704                        : fl::kSInt64;
705       break;
706     case FieldDescriptor::TYPE_INT64:
707       type_card |= field->is_repeated() && field->is_packed() ? fl::kPackedInt64
708                                                               : fl::kInt64;
709       break;
710 
711     case FieldDescriptor::TYPE_BYTES:
712       type_card |= fl::kBytes;
713       break;
714     case FieldDescriptor::TYPE_STRING: {
715       switch (utf8_check_mode) {
716         case cpp::Utf8CheckMode::kStrict:
717           type_card |= fl::kUtf8String;
718           break;
719         case cpp::Utf8CheckMode::kVerify:
720           type_card |= fl::kRawString;
721           break;
722         case cpp::Utf8CheckMode::kNone:
723           type_card |= fl::kBytes;
724           break;
725       }
726       break;
727     }
728 
729     case FieldDescriptor::TYPE_GROUP:
730       type_card |= 0 | fl::kMessage | fl::kRepGroup;
731       if (options.is_implicitly_weak) {
732         type_card |= fl::kTvWeakPtr;
733       } else if (options.use_direct_tcparser_table) {
734         type_card |= fl::kTvTable;
735       } else {
736         type_card |= fl::kTvDefault;
737       }
738       break;
739     case FieldDescriptor::TYPE_MESSAGE:
740       if (field->is_map()) {
741         type_card |= fl::kMap;
742       } else {
743         type_card |= fl::kMessage;
744         if (HasLazyRep(field, options)) {
745           ABSL_CHECK(options.lazy_opt == field_layout::kTvEager ||
746                      options.lazy_opt == field_layout::kTvLazy);
747           type_card |= +fl::kRepLazy | options.lazy_opt;
748         } else {
749           if (options.is_implicitly_weak) {
750             type_card |= fl::kTvWeakPtr;
751           } else if (options.use_direct_tcparser_table) {
752             type_card |= fl::kTvTable;
753           } else {
754             type_card |= fl::kTvDefault;
755           }
756         }
757       }
758       break;
759   }
760 
761   // Fill in extra information about string and bytes field representations.
762   if (field->type() == FieldDescriptor::TYPE_BYTES ||
763       field->type() == FieldDescriptor::TYPE_STRING) {
764     switch (field->cpp_string_type()) {
765       case FieldDescriptor::CppStringType::kCord:
766         // `Cord` is always used, even for repeated fields.
767         type_card |= fl::kRepCord;
768         break;
769       case FieldDescriptor::CppStringType::kView:
770       case FieldDescriptor::CppStringType::kString:
771         if (field->is_repeated()) {
772           // A repeated string field uses RepeatedPtrField<std::string>
773           // (unless it has a ctype option; see above).
774           type_card |= fl::kRepSString;
775         } else {
776           // Otherwise, non-repeated string fields use ArenaStringPtr.
777           type_card |= fl::kRepAString;
778         }
779         break;
780     }
781   }
782 
783   if (options.should_split) {
784     type_card |= fl::kSplitTrue;
785   }
786 
787   return type_card;
788 }
789 
HasWeakFields(const Descriptor * descriptor)790 bool HasWeakFields(const Descriptor* descriptor) {
791   for (int i = 0; i < descriptor->field_count(); i++) {
792     if (descriptor->field(i)->options().weak()) {
793       return true;
794     }
795   }
796   return false;
797 }
798 
799 }  // namespace
800 
TailCallTableInfo(const Descriptor * descriptor,const MessageOptions & message_options,absl::Span<const FieldOptions> ordered_fields)801 TailCallTableInfo::TailCallTableInfo(
802     const Descriptor* descriptor, const MessageOptions& message_options,
803     absl::Span<const FieldOptions> ordered_fields) {
804   fallback_function =
805       // Map entries discard unknown data
806       descriptor->options().map_entry()
807           ? TcParseFunction::kDiscardEverythingFallback
808       // Reflection and weak messages have the reflection fallback
809       : !message_options.uses_codegen || HasWeakFields(descriptor)
810           ? TcParseFunction::kReflectionFallback
811       // Codegen messages have lite and non-lite version
812       : message_options.is_lite ? TcParseFunction::kGenericFallbackLite
813                                 : TcParseFunction::kGenericFallback;
814 
815   if (descriptor->options().message_set_wire_format()) {
816     ABSL_DCHECK(ordered_fields.empty());
817     if (message_options.uses_codegen) {
818       fast_path_fields = {{TailCallTableInfo::FastFieldInfo::NonField{
819           message_options.is_lite
820               ? TcParseFunction::kMessageSetWireFormatParseLoopLite
821               : TcParseFunction::kMessageSetWireFormatParseLoop,
822           0, 0}}};
823 
824       aux_entries = {{kSelfVerifyFunc}};
825     } else {
826       ABSL_DCHECK(!message_options.is_lite);
827       // The message set parser loop only handles codegen because it hardcodes
828       // the generated extension registry. For reflection, use the reflection
829       // loop which can handle arbitrary message factories.
830       fast_path_fields = {{TailCallTableInfo::FastFieldInfo::NonField{
831           TcParseFunction::kReflectionParseLoop, 0, 0}}};
832     }
833 
834     table_size_log2 = 0;
835     num_to_entry_table = MakeNumToEntryTable(ordered_fields);
836     field_name_data = GenerateFieldNames(descriptor, field_entries,
837                                          message_options, ordered_fields);
838 
839     return;
840   }
841 
842   ABSL_DCHECK(std::is_sorted(ordered_fields.begin(), ordered_fields.end(),
843                              [](const auto& lhs, const auto& rhs) {
844                                return lhs.field->number() < rhs.field->number();
845                              }));
846   // If this message has any inlined string fields, store the donation state
847   // offset in the first auxiliary entry, which is kInlinedStringAuxIdx.
848   if (std::any_of(ordered_fields.begin(), ordered_fields.end(),
849                   [](auto& f) { return f.is_string_inlined; })) {
850     aux_entries.resize(kInlinedStringAuxIdx + 1);  // Allocate our slot
851     aux_entries[kInlinedStringAuxIdx] = {kInlinedStringDonatedOffset};
852   }
853 
854   // If this message is split, store the split pointer offset in the second
855   // and third auxiliary entries, which are kSplitOffsetAuxIdx and
856   // kSplitSizeAuxIdx.
857   if (std::any_of(ordered_fields.begin(), ordered_fields.end(),
858                   [](auto& f) { return f.should_split; })) {
859     static_assert(kSplitOffsetAuxIdx + 1 == kSplitSizeAuxIdx, "");
860     aux_entries.resize(kSplitSizeAuxIdx + 1);  // Allocate our 2 slots
861     aux_entries[kSplitOffsetAuxIdx] = {kSplitOffset};
862     aux_entries[kSplitSizeAuxIdx] = {kSplitSizeof};
863   }
864 
865   const auto is_non_cold = [](const FieldOptions& options) {
866     return options.presence_probability >= 0.005;
867   };
868   size_t num_non_cold_subtables = 0;
869   if (message_options.should_profile_driven_cluster_aux_subtable) {
870     // We found that clustering non-cold subtables to the top of aux_entries
871     // achieves the best load tests results than other strategies (e.g.,
872     // clustering all non-cold entries).
873     const auto is_non_cold_subtable = [&](const FieldOptions& options) {
874       auto* field = options.field;
875       // In the following code where we assign kSubTable to aux entries, only
876       // the following typed fields are supported.
877       return (field->type() == FieldDescriptor::TYPE_MESSAGE ||
878               field->type() == FieldDescriptor::TYPE_GROUP) &&
879              !field->is_map() && !field->options().weak() &&
880              !HasLazyRep(field, options) && !options.is_implicitly_weak &&
881              options.use_direct_tcparser_table && is_non_cold(options);
882     };
883     for (const FieldOptions& options : ordered_fields) {
884       if (is_non_cold_subtable(options)) {
885         num_non_cold_subtables++;
886       }
887     }
888   }
889 
890   size_t subtable_aux_idx_begin = aux_entries.size();
891   size_t subtable_aux_idx = aux_entries.size();
892   aux_entries.resize(aux_entries.size() + num_non_cold_subtables);
893 
894   // Fill in mini table entries.
895   for (const auto& options : ordered_fields) {
896     auto* field = options.field;
897     field_entries.push_back({field, options.has_bit_index});
898     auto& entry = field_entries.back();
899     entry.utf8_check_mode =
900         cpp::GetUtf8CheckMode(field, message_options.is_lite);
901     entry.type_card = MakeTypeCardForField(field, entry.hasbit_idx >= 0,
902                                            options, entry.utf8_check_mode);
903 
904     if (field->type() == FieldDescriptor::TYPE_MESSAGE ||
905         field->type() == FieldDescriptor::TYPE_GROUP) {
906       // Message-typed fields have a FieldAux with the default instance pointer.
907       if (field->is_map()) {
908         entry.aux_idx = aux_entries.size();
909         aux_entries.push_back({kMapAuxInfo, {field}});
910         if (message_options.uses_codegen) {
911           // If we don't use codegen we can't add these.
912           auto* map_value = field->message_type()->map_value();
913           if (map_value->message_type() != nullptr) {
914             aux_entries.push_back({kSubTable, {map_value}});
915           } else if (map_value->type() == FieldDescriptor::TYPE_ENUM &&
916                      !cpp::HasPreservingUnknownEnumSemantics(map_value)) {
917             aux_entries.push_back({kEnumValidator, {map_value}});
918           }
919         }
920       } else if (field->options().weak()) {
921         // Disable the type card for this entry to force the fallback.
922         entry.type_card = 0;
923       } else if (HasLazyRep(field, options)) {
924         if (message_options.uses_codegen) {
925           entry.aux_idx = aux_entries.size();
926           aux_entries.push_back({kSubMessage, {field}});
927           if (options.lazy_opt == field_layout::kTvEager) {
928             aux_entries.push_back({kMessageVerifyFunc, {field}});
929           } else {
930             aux_entries.push_back({kNothing});
931           }
932         } else {
933           entry.aux_idx = TcParseTableBase::FieldEntry::kNoAuxIdx;
934         }
935       } else {
936         AuxType type = options.is_implicitly_weak          ? kSubMessageWeak
937                        : options.use_direct_tcparser_table ? kSubTable
938                                                            : kSubMessage;
939         if (message_options.should_profile_driven_cluster_aux_subtable &&
940             type == kSubTable && is_non_cold(options)) {
941           aux_entries[subtable_aux_idx] = {type, {field}};
942           entry.aux_idx = subtable_aux_idx;
943           ++subtable_aux_idx;
944         } else {
945           entry.aux_idx = aux_entries.size();
946           aux_entries.push_back({type, {field}});
947         }
948       }
949     } else if (field->type() == FieldDescriptor::TYPE_ENUM &&
950                !TreatEnumAsInt(field)) {
951       // Enum fields which preserve unknown values (proto3 behavior) are
952       // effectively int32 fields with respect to parsing -- i.e., the value
953       // does not need to be validated at parse time.
954       //
955       // Enum fields which do not preserve unknown values (proto2 behavior) use
956       // a FieldAux to store validation information. If the enum values are
957       // sequential (and within a range we can represent), then the FieldAux
958       // entry represents the range using the minimum value (which must fit in
959       // an int16_t) and count (a uint16_t). Otherwise, the entry holds a
960       // pointer to the generated Name_IsValid function.
961 
962       entry.aux_idx = aux_entries.size();
963       aux_entries.push_back({});
964       auto& aux_entry = aux_entries.back();
965 
966       if (GetEnumValidationRange(field->enum_type(), aux_entry.enum_range.start,
967                                  aux_entry.enum_range.size)) {
968         aux_entry.type = kEnumRange;
969       } else {
970         aux_entry.type = kEnumValidator;
971         aux_entry.field = field;
972       }
973 
974     } else if ((field->type() == FieldDescriptor::TYPE_STRING ||
975                 field->type() == FieldDescriptor::TYPE_BYTES) &&
976                options.is_string_inlined) {
977       ABSL_CHECK(!field->is_repeated());
978       // Inlined strings have an extra marker to represent their donation state.
979       int idx = options.inlined_string_index;
980       // For mini parsing, the donation state index is stored as an `offset`
981       // auxiliary entry.
982       entry.aux_idx = aux_entries.size();
983       aux_entries.push_back({kNumericOffset});
984       aux_entries.back().offset = idx;
985       // For fast table parsing, the donation state index is stored instead of
986       // the aux_idx (this will limit the range to 8 bits).
987       entry.inlined_string_idx = idx;
988     }
989   }
990   ABSL_CHECK_EQ(subtable_aux_idx - subtable_aux_idx_begin,
991                 num_non_cold_subtables);
992 
993   auto end_group_tag = GetEndGroupTag(descriptor);
994 
995   constexpr size_t kMaxFastFields = 32;
996   FastFieldInfo fast_fields[kMaxFastFields];
997   // Bit mask for the fields that are "important". Unimportant fields might be
998   // set but it's ok if we lose them from the fast table. For example, cold
999   // fields.
1000   uint32_t important_fields = 0;
1001   static_assert(sizeof(important_fields) * 8 >= kMaxFastFields, "");
1002   // The largest table we allow has the same number of entries as the
1003   // message has fields, rounded up to the next power of 2 (e.g., a message
1004   // with 5 fields can have a fast table of size 8). A larger table *might*
1005   // cover more fields in certain cases, but a larger table in that case
1006   // would have mostly empty entries; so, we cap the size to avoid
1007   // pathologically sparse tables.
1008   // However, if this message uses group encoding, the tables are sometimes very
1009   // sparse because the fields in the group avoid using the same field
1010   // numbering as the parent message (even though currently, the proto
1011   // compiler allows the overlap, and there is no possible conflict.)
1012   // NOTE: The +1 is to maintain the existing behavior that does not match the
1013   // documented one. When the number of fields is exactly a power of two we
1014   // allow double that.
1015   size_t num_fast_fields =
1016       end_group_tag.has_value()
1017           ? kMaxFastFields
1018           : std::max(size_t{1},
1019                      std::min(kMaxFastFields,
1020                               absl::bit_ceil(ordered_fields.size() + 1)));
1021   PopulateFastFields(
1022       end_group_tag, field_entries, message_options, ordered_fields,
1023       absl::MakeSpan(fast_fields, num_fast_fields), important_fields);
1024   // If we can halve the table without dropping important fields, do it.
1025   while (num_fast_fields > 1 &&
1026          (important_fields & (important_fields >> num_fast_fields / 2)) == 0) {
1027     // Half the table by merging fields.
1028     num_fast_fields /= 2;
1029     for (size_t i = 0; i < num_fast_fields; ++i) {
1030       if ((important_fields >> i) & 1) continue;
1031       fast_fields[i] = fast_fields[i + num_fast_fields];
1032     }
1033     important_fields |= important_fields >> num_fast_fields;
1034   }
1035 
1036   fast_path_fields.assign(fast_fields, fast_fields + num_fast_fields);
1037   table_size_log2 = absl::bit_width(num_fast_fields) - 1;
1038 
1039   num_to_entry_table = MakeNumToEntryTable(ordered_fields);
1040   ABSL_CHECK_EQ(field_entries.size(), ordered_fields.size());
1041   field_name_data = GenerateFieldNames(descriptor, field_entries,
1042                                        message_options, ordered_fields);
1043 }
1044 
1045 }  // namespace internal
1046 }  // namespace protobuf
1047 }  // namespace google
1048 
1049 #include "google/protobuf/port_undef.inc"
1050