1 // Copyright (c) 2009-2021, Google LLC
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above copyright
9 //       notice, this list of conditions and the following disclaimer in the
10 //       documentation and/or other materials provided with the distribution.
11 //     * Neither the name of Google LLC nor the
12 //       names of its contributors may be used to endorse or promote products
13 //       derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
19 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include <algorithm>
27 #include <cmath>
28 #include <cstddef>
29 #include <cstdint>
30 #include <cstdio>
31 #include <cstdlib>
32 #include <limits>
33 #include <map>
34 #include <memory>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 #include "absl/container/flat_hash_map.h"
40 #include "absl/container/flat_hash_set.h"
41 #include "absl/log/absl_check.h"
42 #include "absl/log/absl_log.h"
43 #include "absl/strings/escaping.h"
44 #include "absl/strings/string_view.h"
45 #include "absl/strings/substitute.h"
46 #include "upb/base/descriptor_constants.h"
47 #include "upb/base/string_view.h"
48 #include "upb/reflection/def.hpp"
49 #include "upb/wire/types.h"
50 #include "upbc/common.h"
51 #include "upbc/file_layout.h"
52 #include "upbc/names.h"
53 #include "upbc/plugin.h"
54 
55 // Must be last.
56 #include "upb/port/def.inc"
57 
58 namespace upbc {
59 namespace {
60 
61 struct Options {
62   bool bootstrap = false;
63 };
64 
65 // Returns fields in order of "hotness", eg. how frequently they appear in
66 // serialized payloads. Ideally this will use a profile. When we don't have
67 // that, we assume that fields with smaller numbers are used more frequently.
FieldHotnessOrder(upb::MessageDefPtr message)68 inline std::vector<upb::FieldDefPtr> FieldHotnessOrder(
69     upb::MessageDefPtr message) {
70   std::vector<upb::FieldDefPtr> fields;
71   size_t field_count = message.field_count();
72   fields.reserve(field_count);
73   for (size_t i = 0; i < field_count; i++) {
74     fields.push_back(message.field(i));
75   }
76   std::sort(fields.begin(), fields.end(),
77             [](upb::FieldDefPtr a, upb::FieldDefPtr b) {
78               return std::make_pair(!a.is_required(), a.number()) <
79                      std::make_pair(!b.is_required(), b.number());
80             });
81   return fields;
82 }
83 
SourceFilename(upb::FileDefPtr file)84 std::string SourceFilename(upb::FileDefPtr file) {
85   return StripExtension(file.name()) + ".upb.c";
86 }
87 
MessageInitName(upb::MessageDefPtr descriptor)88 std::string MessageInitName(upb::MessageDefPtr descriptor) {
89   return absl::StrCat(MessageName(descriptor), "_msg_init");
90 }
91 
MessageMiniTableRef(upb::MessageDefPtr descriptor,const Options & options)92 std::string MessageMiniTableRef(upb::MessageDefPtr descriptor,
93                                 const Options& options) {
94   if (options.bootstrap) {
95     return absl::StrCat(MessageInitName(descriptor), "()");
96   } else {
97     return absl::StrCat("&", MessageInitName(descriptor));
98   }
99 }
100 
EnumInitName(upb::EnumDefPtr descriptor)101 std::string EnumInitName(upb::EnumDefPtr descriptor) {
102   return ToCIdent(descriptor.full_name()) + "_enum_init";
103 }
104 
EnumMiniTableRef(upb::EnumDefPtr descriptor,const Options & options)105 std::string EnumMiniTableRef(upb::EnumDefPtr descriptor,
106                              const Options& options) {
107   if (options.bootstrap) {
108     return absl::StrCat(EnumInitName(descriptor), "()");
109   } else {
110     return absl::StrCat("&", EnumInitName(descriptor));
111   }
112 }
113 
ExtensionIdentBase(upb::FieldDefPtr ext)114 std::string ExtensionIdentBase(upb::FieldDefPtr ext) {
115   assert(ext.is_extension());
116   std::string ext_scope;
117   if (ext.extension_scope()) {
118     return MessageName(ext.extension_scope());
119   } else {
120     return ToCIdent(ext.file().package());
121   }
122 }
123 
ExtensionLayout(upb::FieldDefPtr ext)124 std::string ExtensionLayout(upb::FieldDefPtr ext) {
125   return absl::StrCat(ExtensionIdentBase(ext), "_", ext.name(), "_ext");
126 }
127 
128 const char* kEnumsInit = "enums_layout";
129 const char* kExtensionsInit = "extensions_layout";
130 const char* kMessagesInit = "messages_layout";
131 
EnumValueSymbol(upb::EnumValDefPtr value)132 std::string EnumValueSymbol(upb::EnumValDefPtr value) {
133   return ToCIdent(value.full_name());
134 }
135 
CTypeInternal(upb::FieldDefPtr field,bool is_const)136 std::string CTypeInternal(upb::FieldDefPtr field, bool is_const) {
137   std::string maybe_const = is_const ? "const " : "";
138   switch (field.ctype()) {
139     case kUpb_CType_Message: {
140       std::string maybe_struct =
141           field.file() != field.message_type().file() ? "struct " : "";
142       return maybe_const + maybe_struct + MessageName(field.message_type()) +
143              "*";
144     }
145     case kUpb_CType_Bool:
146       return "bool";
147     case kUpb_CType_Float:
148       return "float";
149     case kUpb_CType_Int32:
150     case kUpb_CType_Enum:
151       return "int32_t";
152     case kUpb_CType_UInt32:
153       return "uint32_t";
154     case kUpb_CType_Double:
155       return "double";
156     case kUpb_CType_Int64:
157       return "int64_t";
158     case kUpb_CType_UInt64:
159       return "uint64_t";
160     case kUpb_CType_String:
161     case kUpb_CType_Bytes:
162       return "upb_StringView";
163     default:
164       abort();
165   }
166 }
167 
FloatToCLiteral(float value)168 std::string FloatToCLiteral(float value) {
169   if (value == std::numeric_limits<float>::infinity()) {
170     return "kUpb_FltInfinity";
171   } else if (value == -std::numeric_limits<float>::infinity()) {
172     return "-kUpb_FltInfinity";
173   } else if (std::isnan(value)) {
174     return "kUpb_NaN";
175   } else {
176     return absl::StrCat(value);
177   }
178 }
179 
DoubleToCLiteral(double value)180 std::string DoubleToCLiteral(double value) {
181   if (value == std::numeric_limits<double>::infinity()) {
182     return "kUpb_Infinity";
183   } else if (value == -std::numeric_limits<double>::infinity()) {
184     return "-kUpb_Infinity";
185   } else if (std::isnan(value)) {
186     return "kUpb_NaN";
187   } else {
188     return absl::StrCat(value);
189   }
190 }
191 
FieldDefault(upb::FieldDefPtr field)192 std::string FieldDefault(upb::FieldDefPtr field) {
193   switch (field.ctype()) {
194     case kUpb_CType_Message:
195       return "NULL";
196     case kUpb_CType_Bytes:
197     case kUpb_CType_String: {
198       upb_StringView str = field.default_value().str_val;
199       return absl::Substitute(
200           "upb_StringView_FromString(\"$0\")",
201           absl::CEscape(absl::string_view(str.data, str.size)));
202     }
203     case kUpb_CType_Int32:
204       return absl::Substitute("(int32_t)$0", field.default_value().int32_val);
205     case kUpb_CType_Int64:
206       if (field.default_value().int64_val == INT64_MIN) {
207         // Special-case to avoid:
208         //   integer literal is too large to be represented in a signed integer
209         //   type, interpreting as unsigned
210         //   [-Werror,-Wimplicitly-unsigned-literal]
211         //   int64_t default_val = (int64_t)-9223372036854775808ll;
212         //
213         // More info here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661
214         return "INT64_MIN";
215       } else {
216         return absl::Substitute("(int64_t)$0ll",
217                                 field.default_value().int64_val);
218       }
219     case kUpb_CType_UInt32:
220       return absl::Substitute("(uint32_t)$0u",
221                               field.default_value().uint32_val);
222     case kUpb_CType_UInt64:
223       return absl::Substitute("(uint64_t)$0ull",
224                               field.default_value().uint64_val);
225     case kUpb_CType_Float:
226       return FloatToCLiteral(field.default_value().float_val);
227     case kUpb_CType_Double:
228       return DoubleToCLiteral(field.default_value().double_val);
229     case kUpb_CType_Bool:
230       return field.default_value().bool_val ? "true" : "false";
231     case kUpb_CType_Enum:
232       // Use a number instead of a symbolic name so that we don't require
233       // this enum's header to be included.
234       return absl::StrCat(field.default_value().int32_val);
235   }
236   ABSL_ASSERT(false);
237   return "XXX";
238 }
239 
CType(upb::FieldDefPtr field)240 std::string CType(upb::FieldDefPtr field) {
241   return CTypeInternal(field, false);
242 }
243 
CTypeConst(upb::FieldDefPtr field)244 std::string CTypeConst(upb::FieldDefPtr field) {
245   return CTypeInternal(field, true);
246 }
247 
MapKeyCType(upb::FieldDefPtr map_field)248 std::string MapKeyCType(upb::FieldDefPtr map_field) {
249   return CType(map_field.message_type().map_key());
250 }
251 
MapValueCType(upb::FieldDefPtr map_field)252 std::string MapValueCType(upb::FieldDefPtr map_field) {
253   return CType(map_field.message_type().map_value());
254 }
255 
MapKeySize(upb::FieldDefPtr map_field,absl::string_view expr)256 std::string MapKeySize(upb::FieldDefPtr map_field, absl::string_view expr) {
257   return map_field.message_type().map_key().ctype() == kUpb_CType_String
258              ? "0"
259              : absl::StrCat("sizeof(", expr, ")");
260 }
261 
MapValueSize(upb::FieldDefPtr map_field,absl::string_view expr)262 std::string MapValueSize(upb::FieldDefPtr map_field, absl::string_view expr) {
263   return map_field.message_type().map_value().ctype() == kUpb_CType_String
264              ? "0"
265              : absl::StrCat("sizeof(", expr, ")");
266 }
267 
268 std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
269                              const Options& options);
270 
DumpEnumValues(upb::EnumDefPtr desc,Output & output)271 void DumpEnumValues(upb::EnumDefPtr desc, Output& output) {
272   std::vector<upb::EnumValDefPtr> values;
273   values.reserve(desc.value_count());
274   for (int i = 0; i < desc.value_count(); i++) {
275     values.push_back(desc.value(i));
276   }
277   std::sort(values.begin(), values.end(),
278             [](upb::EnumValDefPtr a, upb::EnumValDefPtr b) {
279               return a.number() < b.number();
280             });
281 
282   for (size_t i = 0; i < values.size(); i++) {
283     auto value = values[i];
284     output("  $0 = $1", EnumValueSymbol(value), value.number());
285     if (i != values.size() - 1) {
286       output(",");
287     }
288     output("\n");
289   }
290 }
291 
292 std::string GetFieldRep(const DefPoolPair& pools, upb::FieldDefPtr field);
293 
GenerateExtensionInHeader(const DefPoolPair & pools,upb::FieldDefPtr ext,Output & output)294 void GenerateExtensionInHeader(const DefPoolPair& pools, upb::FieldDefPtr ext,
295                                Output& output) {
296   output(
297       R"cc(
298         UPB_INLINE bool $0_has_$1(const struct $2* msg) {
299           return _upb_Message_HasExtensionField(msg, &$3);
300         }
301       )cc",
302       ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()),
303       ExtensionLayout(ext));
304 
305   output(
306       R"cc(
307         UPB_INLINE void $0_clear_$1(struct $2* msg) {
308           _upb_Message_ClearExtensionField(msg, &$3);
309         }
310       )cc",
311       ExtensionIdentBase(ext), ext.name(), MessageName(ext.containing_type()),
312       ExtensionLayout(ext));
313 
314   if (ext.IsSequence()) {
315     // TODO(b/259861668): We need generated accessors for repeated extensions.
316   } else {
317     output(
318         R"cc(
319           UPB_INLINE $0 $1_$2(const struct $3* msg) {
320             const upb_MiniTableExtension* ext = &$4;
321             UPB_ASSUME(!upb_IsRepeatedOrMap(&ext->field));
322             UPB_ASSUME(_upb_MiniTableField_GetRep(&ext->field) == $5);
323             $0 default_val = $6;
324             $0 ret;
325             _upb_Message_GetExtensionField(msg, ext, &default_val, &ret);
326             return ret;
327           }
328         )cc",
329         CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
330         MessageName(ext.containing_type()), ExtensionLayout(ext),
331         GetFieldRep(pools, ext), FieldDefault(ext));
332     output(
333         R"cc(
334           UPB_INLINE void $1_set_$2(struct $3* msg, $0 val, upb_Arena* arena) {
335             const upb_MiniTableExtension* ext = &$4;
336             UPB_ASSUME(!upb_IsRepeatedOrMap(&ext->field));
337             UPB_ASSUME(_upb_MiniTableField_GetRep(&ext->field) == $5);
338             bool ok = _upb_Message_SetExtensionField(msg, ext, &val, arena);
339             UPB_ASSERT(ok);
340           }
341         )cc",
342         CTypeConst(ext), ExtensionIdentBase(ext), ext.name(),
343         MessageName(ext.containing_type()), ExtensionLayout(ext),
344         GetFieldRep(pools, ext));
345   }
346 }
347 
GenerateMessageFunctionsInHeader(upb::MessageDefPtr message,const Options & options,Output & output)348 void GenerateMessageFunctionsInHeader(upb::MessageDefPtr message,
349                                       const Options& options, Output& output) {
350   // TODO(b/235839510): The generated code here does not check the return values
351   // from upb_Encode(). How can we even fix this without breaking other things?
352   output(
353       R"cc(
354         UPB_INLINE $0* $0_new(upb_Arena* arena) {
355           return ($0*)_upb_Message_New($1, arena);
356         }
357         UPB_INLINE $0* $0_parse(const char* buf, size_t size, upb_Arena* arena) {
358           $0* ret = $0_new(arena);
359           if (!ret) return NULL;
360           if (upb_Decode(buf, size, ret, $1, NULL, 0, arena) != kUpb_DecodeStatus_Ok) {
361             return NULL;
362           }
363           return ret;
364         }
365         UPB_INLINE $0* $0_parse_ex(const char* buf, size_t size,
366                                    const upb_ExtensionRegistry* extreg,
367                                    int options, upb_Arena* arena) {
368           $0* ret = $0_new(arena);
369           if (!ret) return NULL;
370           if (upb_Decode(buf, size, ret, $1, extreg, options, arena) !=
371               kUpb_DecodeStatus_Ok) {
372             return NULL;
373           }
374           return ret;
375         }
376         UPB_INLINE char* $0_serialize(const $0* msg, upb_Arena* arena, size_t* len) {
377           char* ptr;
378           (void)upb_Encode(msg, $1, 0, arena, &ptr, len);
379           return ptr;
380         }
381         UPB_INLINE char* $0_serialize_ex(const $0* msg, int options,
382                                          upb_Arena* arena, size_t* len) {
383           char* ptr;
384           (void)upb_Encode(msg, $1, options, arena, &ptr, len);
385           return ptr;
386         }
387       )cc",
388       MessageName(message), MessageMiniTableRef(message, options));
389 }
390 
GenerateOneofInHeader(upb::OneofDefPtr oneof,const DefPoolPair & pools,absl::string_view msg_name,const Options & options,Output & output)391 void GenerateOneofInHeader(upb::OneofDefPtr oneof, const DefPoolPair& pools,
392                            absl::string_view msg_name, const Options& options,
393                            Output& output) {
394   std::string fullname = ToCIdent(oneof.full_name());
395   output("typedef enum {\n");
396   for (int j = 0; j < oneof.field_count(); j++) {
397     upb::FieldDefPtr field = oneof.field(j);
398     output("  $0_$1 = $2,\n", fullname, field.name(), field.number());
399   }
400   output(
401       "  $0_NOT_SET = 0\n"
402       "} $0_oneofcases;\n",
403       fullname);
404   output(
405       R"cc(
406         UPB_INLINE $0_oneofcases $1_$2_case(const $1* msg) {
407           const upb_MiniTableField field = $3;
408           return ($0_oneofcases)upb_Message_WhichOneofFieldNumber(msg, &field);
409         }
410       )cc",
411       fullname, msg_name, oneof.name(),
412       FieldInitializer(pools, oneof.field(0), options));
413 }
414 
GenerateHazzer(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)415 void GenerateHazzer(upb::FieldDefPtr field, const DefPoolPair& pools,
416                     absl::string_view msg_name,
417                     const NameToFieldDefMap& field_names,
418                     const Options& options, Output& output) {
419   std::string resolved_name = ResolveFieldName(field, field_names);
420   if (field.has_presence()) {
421     output(
422         R"cc(
423           UPB_INLINE bool $0_has_$1(const $0* msg) {
424             const upb_MiniTableField field = $2;
425             return _upb_Message_HasNonExtensionField(msg, &field);
426           }
427         )cc",
428         msg_name, resolved_name, FieldInitializer(pools, field, options));
429   } else if (field.IsMap()) {
430     // Do nothing.
431   } else if (field.IsSequence()) {
432     // TODO(b/259616267): remove.
433     output(
434         R"cc(
435           UPB_INLINE bool $0_has_$1(const $0* msg) {
436             size_t size;
437             $0_$1(msg, &size);
438             return size != 0;
439           }
440         )cc",
441         msg_name, resolved_name);
442   }
443 }
444 
GenerateClear(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)445 void GenerateClear(upb::FieldDefPtr field, const DefPoolPair& pools,
446                    absl::string_view msg_name,
447                    const NameToFieldDefMap& field_names, const Options& options,
448                    Output& output) {
449   if (field == field.containing_type().map_key() ||
450       field == field.containing_type().map_value()) {
451     // Cannot be cleared.
452     return;
453   }
454   std::string resolved_name = ResolveFieldName(field, field_names);
455   output(
456       R"cc(
457         UPB_INLINE void $0_clear_$1($0* msg) {
458           const upb_MiniTableField field = $2;
459           _upb_Message_ClearNonExtensionField(msg, &field);
460         }
461       )cc",
462       msg_name, resolved_name, FieldInitializer(pools, field, options));
463 }
464 
GenerateMapGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)465 void GenerateMapGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
466                         absl::string_view msg_name,
467                         const NameToFieldDefMap& field_names,
468                         const Options& options, Output& output) {
469   std::string resolved_name = ResolveFieldName(field, field_names);
470   output(
471       R"cc(
472         UPB_INLINE size_t $0_$1_size(const $0* msg) {
473           const upb_MiniTableField field = $2;
474           const upb_Map* map = upb_Message_GetMap(msg, &field);
475           return map ? _upb_Map_Size(map) : 0;
476         }
477       )cc",
478       msg_name, resolved_name, FieldInitializer(pools, field, options));
479   output(
480       R"cc(
481         UPB_INLINE bool $0_$1_get(const $0* msg, $2 key, $3* val) {
482           const upb_MiniTableField field = $4;
483           const upb_Map* map = upb_Message_GetMap(msg, &field);
484           if (!map) return false;
485           return _upb_Map_Get(map, &key, $5, val, $6);
486         }
487       )cc",
488       msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
489       FieldInitializer(pools, field, options), MapKeySize(field, "key"),
490       MapValueSize(field, "*val"));
491   output(
492       R"cc(
493         UPB_INLINE $0 $1_$2_next(const $1* msg, size_t* iter) {
494           const upb_MiniTableField field = $3;
495           const upb_Map* map = upb_Message_GetMap(msg, &field);
496           if (!map) return NULL;
497           return ($0)_upb_map_next(map, iter);
498         }
499       )cc",
500       CTypeConst(field), msg_name, resolved_name,
501       FieldInitializer(pools, field, options));
502 }
503 
GenerateMapEntryGetters(upb::FieldDefPtr field,absl::string_view msg_name,Output & output)504 void GenerateMapEntryGetters(upb::FieldDefPtr field, absl::string_view msg_name,
505                              Output& output) {
506   output(
507       R"cc(
508         UPB_INLINE $0 $1_$2(const $1* msg) {
509           $3 ret;
510           _upb_msg_map_$2(msg, &ret, $4);
511           return ret;
512         }
513       )cc",
514       CTypeConst(field), msg_name, field.name(), CType(field),
515       field.ctype() == kUpb_CType_String ? "0" : "sizeof(ret)");
516 }
517 
GenerateRepeatedGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)518 void GenerateRepeatedGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
519                              absl::string_view msg_name,
520                              const NameToFieldDefMap& field_names,
521                              const Options& options, Output& output) {
522   // Generate getter returning first item and size.
523   //
524   // Example:
525   //   UPB_INLINE const struct Bar* const* name(const Foo* msg, size_t* size)
526   output(
527       R"cc(
528         UPB_INLINE $0 const* $1_$2(const $1* msg, size_t* size) {
529           const upb_MiniTableField field = $3;
530           const upb_Array* arr = upb_Message_GetArray(msg, &field);
531           if (arr) {
532             if (size) *size = arr->size;
533             return ($0 const*)_upb_array_constptr(arr);
534           } else {
535             if (size) *size = 0;
536             return NULL;
537           }
538         }
539       )cc",
540       CTypeConst(field),                       // $0
541       msg_name,                                // $1
542       ResolveFieldName(field, field_names),    // $2
543       FieldInitializer(pools, field, options)  // #3
544   );
545   // Generate private getter returning array or NULL for immutable and upb_Array
546   // for mutable.
547   //
548   // Example:
549   //   UPB_INLINE const upb_Array* _name_upbarray(size_t* size)
550   //   UPB_INLINE upb_Array* _name_mutable_upbarray(size_t* size)
551   output(
552       R"cc(
553         UPB_INLINE const upb_Array* _$1_$2_$4(const $1* msg, size_t* size) {
554           const upb_MiniTableField field = $3;
555           const upb_Array* arr = upb_Message_GetArray(msg, &field);
556           if (size) {
557             *size = arr ? arr->size : 0;
558           }
559           return arr;
560         }
561         UPB_INLINE upb_Array* _$1_$2_$5(const $1* msg, size_t* size, upb_Arena* arena) {
562           const upb_MiniTableField field = $3;
563           upb_Array* arr = upb_Message_GetOrCreateMutableArray(
564               (upb_Message*)msg, &field, arena);
565           if (size) {
566             *size = arr ? arr->size : 0;
567           }
568           return arr;
569         }
570       )cc",
571       CTypeConst(field),                        // $0
572       msg_name,                                 // $1
573       ResolveFieldName(field, field_names),     // $2
574       FieldInitializer(pools, field, options),  // $3
575       kRepeatedFieldArrayGetterPostfix,         // $4
576       kRepeatedFieldMutableArrayGetterPostfix   // $5
577   );
578 }
579 
GenerateScalarGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & Options,Output & output)580 void GenerateScalarGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
581                            absl::string_view msg_name,
582                            const NameToFieldDefMap& field_names,
583                            const Options& Options, Output& output) {
584   std::string field_name = ResolveFieldName(field, field_names);
585   output(
586       R"cc(
587         UPB_INLINE $0 $1_$2(const $1* msg) {
588           $0 default_val = $3;
589           $0 ret;
590           const upb_MiniTableField field = $4;
591           _upb_Message_GetNonExtensionField(msg, &field, &default_val, &ret);
592           return ret;
593         }
594       )cc",
595       CTypeConst(field), msg_name, field_name, FieldDefault(field),
596       FieldInitializer(pools, field, Options));
597 }
598 
GenerateGetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)599 void GenerateGetters(upb::FieldDefPtr field, const DefPoolPair& pools,
600                      absl::string_view msg_name,
601                      const NameToFieldDefMap& field_names,
602                      const Options& options, Output& output) {
603   if (field.IsMap()) {
604     GenerateMapGetters(field, pools, msg_name, field_names, options, output);
605   } else if (UPB_DESC(MessageOptions_map_entry)(
606                  field.containing_type().options())) {
607     GenerateMapEntryGetters(field, msg_name, output);
608   } else if (field.IsSequence()) {
609     GenerateRepeatedGetters(field, pools, msg_name, field_names, options,
610                             output);
611   } else {
612     GenerateScalarGetters(field, pools, msg_name, field_names, options, output);
613   }
614 }
615 
GenerateMapSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)616 void GenerateMapSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
617                         absl::string_view msg_name,
618                         const NameToFieldDefMap& field_names,
619                         const Options& options, Output& output) {
620   std::string resolved_name = ResolveFieldName(field, field_names);
621   output(
622       R"cc(
623         UPB_INLINE void $0_$1_clear($0* msg) {
624           const upb_MiniTableField field = $2;
625           upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
626           if (!map) return;
627           _upb_Map_Clear(map);
628         }
629       )cc",
630       msg_name, resolved_name, FieldInitializer(pools, field, options));
631   output(
632       R"cc(
633         UPB_INLINE bool $0_$1_set($0* msg, $2 key, $3 val, upb_Arena* a) {
634           const upb_MiniTableField field = $4;
635           upb_Map* map = _upb_Message_GetOrCreateMutableMap(msg, &field, $5, $6, a);
636           return _upb_Map_Insert(map, &key, $5, &val, $6, a) !=
637                  kUpb_MapInsertStatus_OutOfMemory;
638         }
639       )cc",
640       msg_name, resolved_name, MapKeyCType(field), MapValueCType(field),
641       FieldInitializer(pools, field, options), MapKeySize(field, "key"),
642       MapValueSize(field, "val"));
643   output(
644       R"cc(
645         UPB_INLINE bool $0_$1_delete($0* msg, $2 key) {
646           const upb_MiniTableField field = $3;
647           upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
648           if (!map) return false;
649           return _upb_Map_Delete(map, &key, $4, NULL);
650         }
651       )cc",
652       msg_name, resolved_name, MapKeyCType(field),
653       FieldInitializer(pools, field, options), MapKeySize(field, "key"));
654   output(
655       R"cc(
656         UPB_INLINE $0 $1_$2_nextmutable($1* msg, size_t* iter) {
657           const upb_MiniTableField field = $3;
658           upb_Map* map = (upb_Map*)upb_Message_GetMap(msg, &field);
659           if (!map) return NULL;
660           return ($0)_upb_map_next(map, iter);
661         }
662       )cc",
663       CType(field), msg_name, resolved_name,
664       FieldInitializer(pools, field, options));
665 }
666 
GenerateRepeatedSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)667 void GenerateRepeatedSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
668                              absl::string_view msg_name,
669                              const NameToFieldDefMap& field_names,
670                              const Options& options, Output& output) {
671   std::string resolved_name = ResolveFieldName(field, field_names);
672   output(
673       R"cc(
674         UPB_INLINE $0* $1_mutable_$2($1* msg, size_t* size) {
675           upb_MiniTableField field = $3;
676           upb_Array* arr = upb_Message_GetMutableArray(msg, &field);
677           if (arr) {
678             if (size) *size = arr->size;
679             return ($0*)_upb_array_ptr(arr);
680           } else {
681             if (size) *size = 0;
682             return NULL;
683           }
684         }
685       )cc",
686       CType(field), msg_name, resolved_name,
687       FieldInitializer(pools, field, options));
688   output(
689       R"cc(
690         UPB_INLINE $0* $1_resize_$2($1* msg, size_t size, upb_Arena* arena) {
691           upb_MiniTableField field = $3;
692           return ($0*)upb_Message_ResizeArray(msg, &field, size, arena);
693         }
694       )cc",
695       CType(field), msg_name, resolved_name,
696       FieldInitializer(pools, field, options));
697   if (field.ctype() == kUpb_CType_Message) {
698     output(
699         R"cc(
700           UPB_INLINE struct $0* $1_add_$2($1* msg, upb_Arena* arena) {
701             upb_MiniTableField field = $4;
702             upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena);
703             if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) {
704               return NULL;
705             }
706             struct $0* sub = (struct $0*)_upb_Message_New($3, arena);
707             if (!arr || !sub) return NULL;
708             _upb_Array_Set(arr, arr->size - 1, &sub, sizeof(sub));
709             return sub;
710           }
711         )cc",
712         MessageName(field.message_type()), msg_name, resolved_name,
713         MessageMiniTableRef(field.message_type(), options),
714         FieldInitializer(pools, field, options));
715   } else {
716     output(
717         R"cc(
718           UPB_INLINE bool $1_add_$2($1* msg, $0 val, upb_Arena* arena) {
719             upb_MiniTableField field = $3;
720             upb_Array* arr = upb_Message_GetOrCreateMutableArray(msg, &field, arena);
721             if (!arr || !_upb_Array_ResizeUninitialized(arr, arr->size + 1, arena)) {
722               return false;
723             }
724             _upb_Array_Set(arr, arr->size - 1, &val, sizeof(val));
725             return true;
726           }
727         )cc",
728         CType(field), msg_name, resolved_name,
729         FieldInitializer(pools, field, options));
730   }
731 }
732 
GenerateNonRepeatedSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)733 void GenerateNonRepeatedSetters(upb::FieldDefPtr field,
734                                 const DefPoolPair& pools,
735                                 absl::string_view msg_name,
736                                 const NameToFieldDefMap& field_names,
737                                 const Options& options, Output& output) {
738   if (field == field.containing_type().map_key()) {
739     // Key cannot be mutated.
740     return;
741   }
742 
743   std::string field_name = ResolveFieldName(field, field_names);
744 
745   if (field == field.containing_type().map_value()) {
746     output(R"cc(
747              UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
748                _upb_msg_map_set_value(msg, &value, $3);
749              }
750            )cc",
751            msg_name, field_name, CType(field),
752            field.ctype() == kUpb_CType_String ? "0"
753                                               : "sizeof(" + CType(field) + ")");
754   } else {
755     output(R"cc(
756              UPB_INLINE void $0_set_$1($0 *msg, $2 value) {
757                const upb_MiniTableField field = $3;
758                _upb_Message_SetNonExtensionField(msg, &field, &value);
759              }
760            )cc",
761            msg_name, field_name, CType(field),
762            FieldInitializer(pools, field, options));
763   }
764 
765   // Message fields also have a Msg_mutable_foo() accessor that will create
766   // the sub-message if it doesn't already exist.
767   if (field.ctype() == kUpb_CType_Message &&
768       !UPB_DESC(MessageOptions_map_entry)(field.containing_type().options())) {
769     output(
770         R"cc(
771           UPB_INLINE struct $0* $1_mutable_$2($1* msg, upb_Arena* arena) {
772             struct $0* sub = (struct $0*)$1_$2(msg);
773             if (sub == NULL) {
774               sub = (struct $0*)_upb_Message_New($3, arena);
775               if (sub) $1_set_$2(msg, sub);
776             }
777             return sub;
778           }
779         )cc",
780         MessageName(field.message_type()), msg_name, field_name,
781         MessageMiniTableRef(field.message_type(), options));
782   }
783 }
784 
GenerateSetters(upb::FieldDefPtr field,const DefPoolPair & pools,absl::string_view msg_name,const NameToFieldDefMap & field_names,const Options & options,Output & output)785 void GenerateSetters(upb::FieldDefPtr field, const DefPoolPair& pools,
786                      absl::string_view msg_name,
787                      const NameToFieldDefMap& field_names,
788                      const Options& options, Output& output) {
789   if (field.IsMap()) {
790     GenerateMapSetters(field, pools, msg_name, field_names, options, output);
791   } else if (field.IsSequence()) {
792     GenerateRepeatedSetters(field, pools, msg_name, field_names, options,
793                             output);
794   } else {
795     GenerateNonRepeatedSetters(field, pools, msg_name, field_names, options,
796                                output);
797   }
798 }
799 
GenerateMessageInHeader(upb::MessageDefPtr message,const DefPoolPair & pools,const Options & options,Output & output)800 void GenerateMessageInHeader(upb::MessageDefPtr message,
801                              const DefPoolPair& pools, const Options& options,
802                              Output& output) {
803   output("/* $0 */\n\n", message.full_name());
804   std::string msg_name = ToCIdent(message.full_name());
805   if (!UPB_DESC(MessageOptions_map_entry)(message.options())) {
806     GenerateMessageFunctionsInHeader(message, options, output);
807   }
808 
809   for (int i = 0; i < message.real_oneof_count(); i++) {
810     GenerateOneofInHeader(message.oneof(i), pools, msg_name, options, output);
811   }
812 
813   auto field_names = CreateFieldNameMap(message);
814   for (auto field : FieldNumberOrder(message)) {
815     GenerateClear(field, pools, msg_name, field_names, options, output);
816     GenerateGetters(field, pools, msg_name, field_names, options, output);
817     GenerateHazzer(field, pools, msg_name, field_names, options, output);
818   }
819 
820   output("\n");
821 
822   for (auto field : FieldNumberOrder(message)) {
823     GenerateSetters(field, pools, msg_name, field_names, options, output);
824   }
825 
826   output("\n");
827 }
828 
ForwardDeclareMiniTableInit(upb::MessageDefPtr message,const Options & options,Output & output)829 void ForwardDeclareMiniTableInit(upb::MessageDefPtr message,
830                                  const Options& options, Output& output) {
831   if (options.bootstrap) {
832     output("extern const upb_MiniTable* $0();\n", MessageInitName(message));
833   } else {
834     output("extern const upb_MiniTable $0;\n", MessageInitName(message));
835   }
836 }
837 
WriteHeader(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)838 void WriteHeader(const DefPoolPair& pools, upb::FileDefPtr file,
839                  const Options& options, Output& output) {
840   EmitFileWarning(file.name(), output);
841   output(
842       "#ifndef $0_UPB_H_\n"
843       "#define $0_UPB_H_\n\n"
844       "#include \"upb/collections/array_internal.h\"\n"
845       "#include \"upb/collections/map_gencode_util.h\"\n"
846       "#include \"upb/message/accessors.h\"\n"
847       "#include \"upb/message/internal.h\"\n"
848       "#include \"upb/mini_table/enum_internal.h\"\n"
849       "#include \"upb/wire/decode.h\"\n"
850       "#include \"upb/wire/decode_fast.h\"\n"
851       "#include \"upb/wire/encode.h\"\n\n",
852       ToPreproc(file.name()));
853 
854   for (int i = 0; i < file.public_dependency_count(); i++) {
855     if (i == 0) {
856       output("/* Public Imports. */\n");
857     }
858     output("#include \"$0\"\n", HeaderFilename(file.public_dependency(i)));
859     if (i == file.public_dependency_count() - 1) {
860       output("\n");
861     }
862   }
863 
864   output(
865       "// Must be last. \n"
866       "#include \"upb/port/def.inc\"\n"
867       "\n"
868       "#ifdef __cplusplus\n"
869       "extern \"C\" {\n"
870       "#endif\n"
871       "\n");
872 
873   const std::vector<upb::MessageDefPtr> this_file_messages =
874       SortedMessages(file);
875   const std::vector<upb::FieldDefPtr> this_file_exts = SortedExtensions(file);
876 
877   // Forward-declare types defined in this file.
878   for (auto message : this_file_messages) {
879     output("typedef struct $0 $0;\n", ToCIdent(message.full_name()));
880   }
881   for (auto message : this_file_messages) {
882     ForwardDeclareMiniTableInit(message, options, output);
883   }
884   for (auto ext : this_file_exts) {
885     output("extern const upb_MiniTableExtension $0;\n", ExtensionLayout(ext));
886   }
887 
888   // Forward-declare types not in this file, but used as submessages.
889   // Order by full name for consistent ordering.
890   std::map<std::string, upb::MessageDefPtr> forward_messages;
891 
892   for (auto message : this_file_messages) {
893     for (int i = 0; i < message.field_count(); i++) {
894       upb::FieldDefPtr field = message.field(i);
895       if (field.ctype() == kUpb_CType_Message &&
896           field.file() != field.message_type().file()) {
897         forward_messages[field.message_type().full_name()] =
898             field.message_type();
899       }
900     }
901   }
902   for (auto ext : this_file_exts) {
903     if (ext.file() != ext.containing_type().file()) {
904       forward_messages[ext.containing_type().full_name()] =
905           ext.containing_type();
906     }
907   }
908   for (const auto& pair : forward_messages) {
909     output("struct $0;\n", MessageName(pair.second));
910   }
911   for (const auto& pair : forward_messages) {
912     ForwardDeclareMiniTableInit(pair.second, options, output);
913   }
914 
915   if (!this_file_messages.empty()) {
916     output("\n");
917   }
918 
919   std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file);
920 
921   for (auto enumdesc : this_file_enums) {
922     output("typedef enum {\n");
923     DumpEnumValues(enumdesc, output);
924     output("} $0;\n\n", ToCIdent(enumdesc.full_name()));
925   }
926 
927   output("\n");
928 
929   if (file.syntax() == kUpb_Syntax_Proto2) {
930     for (const auto enumdesc : this_file_enums) {
931       if (options.bootstrap) {
932         output("extern const upb_MiniTableEnum* $0();\n", EnumInit(enumdesc));
933       } else {
934         output("extern const upb_MiniTableEnum $0;\n", EnumInit(enumdesc));
935       }
936     }
937   }
938 
939   output("\n");
940   for (auto message : this_file_messages) {
941     GenerateMessageInHeader(message, pools, options, output);
942   }
943 
944   for (auto ext : this_file_exts) {
945     GenerateExtensionInHeader(pools, ext, output);
946   }
947 
948   output("extern const upb_MiniTableFile $0;\n\n", FileLayoutName(file));
949 
950   if (absl::string_view(file.name()) == "google/protobuf/descriptor.proto" ||
951       absl::string_view(file.name()) == "net/proto2/proto/descriptor.proto") {
952     // This is gratuitously inefficient with how many times it rebuilds
953     // MessageLayout objects for the same message. But we only do this for one
954     // proto (descriptor.proto) so we don't worry about it.
955     upb::MessageDefPtr max32_message;
956     upb::MessageDefPtr max64_message;
957     size_t max32 = 0;
958     size_t max64 = 0;
959     for (const auto message : this_file_messages) {
960       if (absl::EndsWith(message.name(), "Options")) {
961         size_t size32 = pools.GetMiniTable32(message)->size;
962         size_t size64 = pools.GetMiniTable64(message)->size;
963         if (size32 > max32) {
964           max32 = size32;
965           max32_message = message;
966         }
967         if (size64 > max64) {
968           max64 = size64;
969           max64_message = message;
970         }
971       }
972     }
973 
974     output("/* Max size 32 is $0 */\n", max32_message.full_name());
975     output("/* Max size 64 is $0 */\n", max64_message.full_name());
976     output("#define _UPB_MAXOPT_SIZE UPB_SIZE($0, $1)\n\n", max32, max64);
977   }
978 
979   output(
980       "#ifdef __cplusplus\n"
981       "}  /* extern \"C\" */\n"
982       "#endif\n"
983       "\n"
984       "#include \"upb/port/undef.inc\"\n"
985       "\n"
986       "#endif  /* $0_UPB_H_ */\n",
987       ToPreproc(file.name()));
988 }
989 
990 typedef std::pair<std::string, uint64_t> TableEntry;
991 
GetWireTypeForField(upb::FieldDefPtr field)992 uint32_t GetWireTypeForField(upb::FieldDefPtr field) {
993   if (field.packed()) return kUpb_WireType_Delimited;
994   switch (field.type()) {
995     case kUpb_FieldType_Double:
996     case kUpb_FieldType_Fixed64:
997     case kUpb_FieldType_SFixed64:
998       return kUpb_WireType_64Bit;
999     case kUpb_FieldType_Float:
1000     case kUpb_FieldType_Fixed32:
1001     case kUpb_FieldType_SFixed32:
1002       return kUpb_WireType_32Bit;
1003     case kUpb_FieldType_Int64:
1004     case kUpb_FieldType_UInt64:
1005     case kUpb_FieldType_Int32:
1006     case kUpb_FieldType_Bool:
1007     case kUpb_FieldType_UInt32:
1008     case kUpb_FieldType_Enum:
1009     case kUpb_FieldType_SInt32:
1010     case kUpb_FieldType_SInt64:
1011       return kUpb_WireType_Varint;
1012     case kUpb_FieldType_Group:
1013       return kUpb_WireType_StartGroup;
1014     case kUpb_FieldType_Message:
1015     case kUpb_FieldType_String:
1016     case kUpb_FieldType_Bytes:
1017       return kUpb_WireType_Delimited;
1018   }
1019   UPB_UNREACHABLE();
1020 }
1021 
MakeTag(uint32_t field_number,uint32_t wire_type)1022 uint32_t MakeTag(uint32_t field_number, uint32_t wire_type) {
1023   return field_number << 3 | wire_type;
1024 }
1025 
WriteVarint32ToArray(uint64_t val,char * buf)1026 size_t WriteVarint32ToArray(uint64_t val, char* buf) {
1027   size_t i = 0;
1028   do {
1029     uint8_t byte = val & 0x7fU;
1030     val >>= 7;
1031     if (val) byte |= 0x80U;
1032     buf[i++] = byte;
1033   } while (val);
1034   return i;
1035 }
1036 
GetEncodedTag(upb::FieldDefPtr field)1037 uint64_t GetEncodedTag(upb::FieldDefPtr field) {
1038   uint32_t wire_type = GetWireTypeForField(field);
1039   uint32_t unencoded_tag = MakeTag(field.number(), wire_type);
1040   char tag_bytes[10] = {0};
1041   WriteVarint32ToArray(unencoded_tag, tag_bytes);
1042   uint64_t encoded_tag = 0;
1043   memcpy(&encoded_tag, tag_bytes, sizeof(encoded_tag));
1044   // TODO: byte-swap for big endian.
1045   return encoded_tag;
1046 }
1047 
GetTableSlot(upb::FieldDefPtr field)1048 int GetTableSlot(upb::FieldDefPtr field) {
1049   uint64_t tag = GetEncodedTag(field);
1050   if (tag > 0x7fff) {
1051     // Tag must fit within a two-byte varint.
1052     return -1;
1053   }
1054   return (tag & 0xf8) >> 3;
1055 }
1056 
TryFillTableEntry(const DefPoolPair & pools,upb::FieldDefPtr field,TableEntry & ent)1057 bool TryFillTableEntry(const DefPoolPair& pools, upb::FieldDefPtr field,
1058                        TableEntry& ent) {
1059   const upb_MiniTable* mt = pools.GetMiniTable64(field.containing_type());
1060   const upb_MiniTableField* mt_f =
1061       upb_MiniTable_FindFieldByNumber(mt, field.number());
1062   std::string type = "";
1063   std::string cardinality = "";
1064   switch (upb_MiniTableField_Type(mt_f)) {
1065     case kUpb_FieldType_Bool:
1066       type = "b1";
1067       break;
1068     case kUpb_FieldType_Enum:
1069       if (upb_MiniTableField_IsClosedEnum(mt_f)) {
1070         // We don't have the means to test proto2 enum fields for valid values.
1071         return false;
1072       }
1073       [[fallthrough]];
1074     case kUpb_FieldType_Int32:
1075     case kUpb_FieldType_UInt32:
1076       type = "v4";
1077       break;
1078     case kUpb_FieldType_Int64:
1079     case kUpb_FieldType_UInt64:
1080       type = "v8";
1081       break;
1082     case kUpb_FieldType_Fixed32:
1083     case kUpb_FieldType_SFixed32:
1084     case kUpb_FieldType_Float:
1085       type = "f4";
1086       break;
1087     case kUpb_FieldType_Fixed64:
1088     case kUpb_FieldType_SFixed64:
1089     case kUpb_FieldType_Double:
1090       type = "f8";
1091       break;
1092     case kUpb_FieldType_SInt32:
1093       type = "z4";
1094       break;
1095     case kUpb_FieldType_SInt64:
1096       type = "z8";
1097       break;
1098     case kUpb_FieldType_String:
1099       type = "s";
1100       break;
1101     case kUpb_FieldType_Bytes:
1102       type = "b";
1103       break;
1104     case kUpb_FieldType_Message:
1105       type = "m";
1106       break;
1107     default:
1108       return false;  // Not supported yet.
1109   }
1110 
1111   switch (upb_FieldMode_Get(mt_f)) {
1112     case kUpb_FieldMode_Map:
1113       return false;  // Not supported yet (ever?).
1114     case kUpb_FieldMode_Array:
1115       if (mt_f->mode & kUpb_LabelFlags_IsPacked) {
1116         cardinality = "p";
1117       } else {
1118         cardinality = "r";
1119       }
1120       break;
1121     case kUpb_FieldMode_Scalar:
1122       if (mt_f->presence < 0) {
1123         cardinality = "o";
1124       } else {
1125         cardinality = "s";
1126       }
1127       break;
1128   }
1129 
1130   uint64_t expected_tag = GetEncodedTag(field);
1131 
1132   // Data is:
1133   //
1134   //                  48                32                16                 0
1135   // |--------|--------|--------|--------|--------|--------|--------|--------|
1136   // |   offset (16)   |case offset (16) |presence| submsg |  exp. tag (16)  |
1137   // |--------|--------|--------|--------|--------|--------|--------|--------|
1138   //
1139   // - |presence| is either hasbit index or field number for oneofs.
1140 
1141   uint64_t data = static_cast<uint64_t>(mt_f->offset) << 48 | expected_tag;
1142 
1143   if (field.IsSequence()) {
1144     // No hasbit/oneof-related fields.
1145   }
1146   if (field.real_containing_oneof()) {
1147     uint64_t case_offset = ~mt_f->presence;
1148     if (case_offset > 0xffff || field.number() > 0xff) return false;
1149     data |= field.number() << 24;
1150     data |= case_offset << 32;
1151   } else {
1152     uint64_t hasbit_index = 63;  // No hasbit (set a high, unused bit).
1153     if (mt_f->presence) {
1154       hasbit_index = mt_f->presence;
1155       if (hasbit_index > 31) return false;
1156     }
1157     data |= hasbit_index << 24;
1158   }
1159 
1160   if (field.ctype() == kUpb_CType_Message) {
1161     uint64_t idx = mt_f->UPB_PRIVATE(submsg_index);
1162     if (idx > 255) return false;
1163     data |= idx << 16;
1164 
1165     std::string size_ceil = "max";
1166     size_t size = SIZE_MAX;
1167     if (field.message_type().file() == field.file()) {
1168       // We can only be guaranteed the size of the sub-message if it is in the
1169       // same file as us.  We could relax this to increase the speed of
1170       // cross-file sub-message parsing if we are comfortable requiring that
1171       // users compile all messages at the same time.
1172       const upb_MiniTable* sub_mt = pools.GetMiniTable64(field.message_type());
1173       size = sub_mt->size + 8;
1174     }
1175     std::vector<size_t> breaks = {64, 128, 192, 256};
1176     for (auto brk : breaks) {
1177       if (size <= brk) {
1178         size_ceil = std::to_string(brk);
1179         break;
1180       }
1181     }
1182     ent.first = absl::Substitute("upb_p$0$1_$2bt_max$3b", cardinality, type,
1183                                  expected_tag > 0xff ? "2" : "1", size_ceil);
1184 
1185   } else {
1186     ent.first = absl::Substitute("upb_p$0$1_$2bt", cardinality, type,
1187                                  expected_tag > 0xff ? "2" : "1");
1188   }
1189   ent.second = data;
1190   return true;
1191 }
1192 
FastDecodeTable(upb::MessageDefPtr message,const DefPoolPair & pools)1193 std::vector<TableEntry> FastDecodeTable(upb::MessageDefPtr message,
1194                                         const DefPoolPair& pools) {
1195   std::vector<TableEntry> table;
1196   for (const auto field : FieldHotnessOrder(message)) {
1197     TableEntry ent;
1198     int slot = GetTableSlot(field);
1199     // std::cerr << "table slot: " << field->number() << ": " << slot << "\n";
1200     if (slot < 0) {
1201       // Tag can't fit in the table.
1202       continue;
1203     }
1204     if (!TryFillTableEntry(pools, field, ent)) {
1205       // Unsupported field type or offset, hasbit index, etc. doesn't fit.
1206       continue;
1207     }
1208     while ((size_t)slot >= table.size()) {
1209       size_t size = std::max(static_cast<size_t>(1), table.size() * 2);
1210       table.resize(size, TableEntry{"_upb_FastDecoder_DecodeGeneric", 0});
1211     }
1212     if (table[slot].first != "_upb_FastDecoder_DecodeGeneric") {
1213       // A hotter field already filled this slot.
1214       continue;
1215     }
1216     table[slot] = ent;
1217   }
1218   return table;
1219 }
1220 
ArchDependentSize(int64_t size32,int64_t size64)1221 std::string ArchDependentSize(int64_t size32, int64_t size64) {
1222   if (size32 == size64) return absl::StrCat(size32);
1223   return absl::Substitute("UPB_SIZE($0, $1)", size32, size64);
1224 }
1225 
GetFieldRep(const upb_MiniTableField * field32,const upb_MiniTableField * field64)1226 std::string GetFieldRep(const upb_MiniTableField* field32,
1227                         const upb_MiniTableField* field64) {
1228   switch (_upb_MiniTableField_GetRep(field32)) {
1229     case kUpb_FieldRep_1Byte:
1230       return "kUpb_FieldRep_1Byte";
1231       break;
1232     case kUpb_FieldRep_4Byte: {
1233       if (_upb_MiniTableField_GetRep(field64) == kUpb_FieldRep_4Byte) {
1234         return "kUpb_FieldRep_4Byte";
1235       } else {
1236         assert(_upb_MiniTableField_GetRep(field64) == kUpb_FieldRep_8Byte);
1237         return "UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte)";
1238       }
1239       break;
1240     }
1241     case kUpb_FieldRep_StringView:
1242       return "kUpb_FieldRep_StringView";
1243       break;
1244     case kUpb_FieldRep_8Byte:
1245       return "kUpb_FieldRep_8Byte";
1246       break;
1247   }
1248   UPB_UNREACHABLE();
1249 }
1250 
GetFieldRep(const DefPoolPair & pools,upb::FieldDefPtr field)1251 std::string GetFieldRep(const DefPoolPair& pools, upb::FieldDefPtr field) {
1252   return GetFieldRep(pools.GetField32(field), pools.GetField64(field));
1253 }
1254 
1255 // Returns the field mode as a string initializer.
1256 //
1257 // We could just emit this as a number (and we may yet go in that direction) but
1258 // for now emitting symbolic constants gives this better readability and
1259 // debuggability.
GetModeInit(const upb_MiniTableField * field32,const upb_MiniTableField * field64)1260 std::string GetModeInit(const upb_MiniTableField* field32,
1261                         const upb_MiniTableField* field64) {
1262   std::string ret;
1263   uint8_t mode32 = field32->mode;
1264   switch (mode32 & kUpb_FieldMode_Mask) {
1265     case kUpb_FieldMode_Map:
1266       ret = "kUpb_FieldMode_Map";
1267       break;
1268     case kUpb_FieldMode_Array:
1269       ret = "kUpb_FieldMode_Array";
1270       break;
1271     case kUpb_FieldMode_Scalar:
1272       ret = "kUpb_FieldMode_Scalar";
1273       break;
1274     default:
1275       break;
1276   }
1277 
1278   if (mode32 & kUpb_LabelFlags_IsPacked) {
1279     absl::StrAppend(&ret, " | kUpb_LabelFlags_IsPacked");
1280   }
1281 
1282   if (mode32 & kUpb_LabelFlags_IsExtension) {
1283     absl::StrAppend(&ret, " | kUpb_LabelFlags_IsExtension");
1284   }
1285 
1286   if (mode32 & kUpb_LabelFlags_IsAlternate) {
1287     absl::StrAppend(&ret, " | kUpb_LabelFlags_IsAlternate");
1288   }
1289 
1290   absl::StrAppend(&ret, " | (", GetFieldRep(field32, field64),
1291                   " << kUpb_FieldRep_Shift)");
1292   return ret;
1293 }
1294 
FieldInitializer(upb::FieldDefPtr field,const upb_MiniTableField * field64,const upb_MiniTableField * field32,const Options & options)1295 std::string FieldInitializer(upb::FieldDefPtr field,
1296                              const upb_MiniTableField* field64,
1297                              const upb_MiniTableField* field32,
1298                              const Options& options) {
1299   if (options.bootstrap) {
1300     ABSL_CHECK(!field.is_extension());
1301     return absl::Substitute(
1302         "*upb_MiniTable_FindFieldByNumber($0, $1)",
1303         MessageMiniTableRef(field.containing_type(), options), field.number());
1304   } else {
1305     return absl::Substitute(
1306         "{$0, $1, $2, $3, $4, $5}", field64->number,
1307         ArchDependentSize(field32->offset, field64->offset),
1308         ArchDependentSize(field32->presence, field64->presence),
1309         field64->UPB_PRIVATE(submsg_index) == kUpb_NoSub
1310             ? "kUpb_NoSub"
1311             : absl::StrCat(field64->UPB_PRIVATE(submsg_index)).c_str(),
1312         field64->UPB_PRIVATE(descriptortype), GetModeInit(field32, field64));
1313   }
1314 }
1315 
FieldInitializer(const DefPoolPair & pools,upb::FieldDefPtr field,const Options & options)1316 std::string FieldInitializer(const DefPoolPair& pools, upb::FieldDefPtr field,
1317                              const Options& options) {
1318   return FieldInitializer(field, pools.GetField64(field),
1319                           pools.GetField32(field), options);
1320 }
1321 
1322 // Writes a single field into a .upb.c source file.
WriteMessageField(upb::FieldDefPtr field,const upb_MiniTableField * field64,const upb_MiniTableField * field32,const Options & options,Output & output)1323 void WriteMessageField(upb::FieldDefPtr field,
1324                        const upb_MiniTableField* field64,
1325                        const upb_MiniTableField* field32,
1326                        const Options& options, Output& output) {
1327   output("  $0,\n", FieldInitializer(field, field64, field32, options));
1328 }
1329 
GetSub(upb::FieldDefPtr field)1330 std::string GetSub(upb::FieldDefPtr field) {
1331   if (auto message_def = field.message_type()) {
1332     return absl::Substitute("{.submsg = &$0}", MessageInitName(message_def));
1333   }
1334 
1335   if (auto enum_def = field.enum_subdef()) {
1336     if (enum_def.is_closed()) {
1337       return absl::Substitute("{.subenum = &$0}", EnumInit(enum_def));
1338     }
1339   }
1340 
1341   return std::string("{.submsg = NULL}");
1342 }
1343 
1344 // Writes a single message into a .upb.c source file.
WriteMessage(upb::MessageDefPtr message,const DefPoolPair & pools,const Options & options,Output & output)1345 void WriteMessage(upb::MessageDefPtr message, const DefPoolPair& pools,
1346                   const Options& options, Output& output) {
1347   std::string msg_name = ToCIdent(message.full_name());
1348   std::string fields_array_ref = "NULL";
1349   std::string submsgs_array_ref = "NULL";
1350   std::string subenums_array_ref = "NULL";
1351   const upb_MiniTable* mt_32 = pools.GetMiniTable32(message);
1352   const upb_MiniTable* mt_64 = pools.GetMiniTable64(message);
1353   std::vector<std::string> subs;
1354 
1355   for (int i = 0; i < mt_64->field_count; i++) {
1356     const upb_MiniTableField* f = &mt_64->fields[i];
1357     if (f->UPB_PRIVATE(submsg_index) != kUpb_NoSub) {
1358       subs.push_back(GetSub(message.FindFieldByNumber(f->number)));
1359     }
1360   }
1361 
1362   if (!subs.empty()) {
1363     std::string submsgs_array_name = msg_name + "_submsgs";
1364     submsgs_array_ref = "&" + submsgs_array_name + "[0]";
1365     output("static const upb_MiniTableSub $0[$1] = {\n", submsgs_array_name,
1366            subs.size());
1367 
1368     for (const auto& sub : subs) {
1369       output("  $0,\n", sub);
1370     }
1371 
1372     output("};\n\n");
1373   }
1374 
1375   if (mt_64->field_count > 0) {
1376     std::string fields_array_name = msg_name + "__fields";
1377     fields_array_ref = "&" + fields_array_name + "[0]";
1378     output("static const upb_MiniTableField $0[$1] = {\n", fields_array_name,
1379            mt_64->field_count);
1380     for (int i = 0; i < mt_64->field_count; i++) {
1381       WriteMessageField(message.FindFieldByNumber(mt_64->fields[i].number),
1382                         &mt_64->fields[i], &mt_32->fields[i], options, output);
1383     }
1384     output("};\n\n");
1385   }
1386 
1387   std::vector<TableEntry> table;
1388   uint8_t table_mask = -1;
1389 
1390   table = FastDecodeTable(message, pools);
1391 
1392   if (table.size() > 1) {
1393     assert((table.size() & (table.size() - 1)) == 0);
1394     table_mask = (table.size() - 1) << 3;
1395   }
1396 
1397   std::string msgext = "kUpb_ExtMode_NonExtendable";
1398 
1399   if (message.extension_range_count()) {
1400     if (UPB_DESC(MessageOptions_message_set_wire_format)(message.options())) {
1401       msgext = "kUpb_ExtMode_IsMessageSet";
1402     } else {
1403       msgext = "kUpb_ExtMode_Extendable";
1404     }
1405   }
1406 
1407   output("const upb_MiniTable $0 = {\n", MessageInitName(message));
1408   output("  $0,\n", submsgs_array_ref);
1409   output("  $0,\n", fields_array_ref);
1410   output("  $0, $1, $2, $3, UPB_FASTTABLE_MASK($4), $5,\n",
1411          ArchDependentSize(mt_32->size, mt_64->size), mt_64->field_count,
1412          msgext, mt_64->dense_below, table_mask, mt_64->required_count);
1413   if (!table.empty()) {
1414     output("  UPB_FASTTABLE_INIT({\n");
1415     for (const auto& ent : table) {
1416       output("    {0x$1, &$0},\n", ent.first,
1417              absl::StrCat(absl::Hex(ent.second, absl::kZeroPad16)));
1418     }
1419     output("  })\n");
1420   }
1421   output("};\n\n");
1422 }
1423 
WriteEnum(upb::EnumDefPtr e,Output & output)1424 void WriteEnum(upb::EnumDefPtr e, Output& output) {
1425   std::string values_init = "{\n";
1426   const upb_MiniTableEnum* mt = e.mini_table();
1427   uint32_t value_count = (mt->mask_limit / 32) + mt->value_count;
1428   for (uint32_t i = 0; i < value_count; i++) {
1429     absl::StrAppend(&values_init, "                0x", absl::Hex(mt->data[i]),
1430                     ",\n");
1431   }
1432   values_init += "    }";
1433 
1434   output(
1435       R"cc(
1436         const upb_MiniTableEnum $0 = {
1437             $1,
1438             $2,
1439             $3,
1440         };
1441       )cc",
1442       EnumInit(e), mt->mask_limit, mt->value_count, values_init);
1443   output("\n");
1444 }
1445 
WriteEnums(const DefPoolPair & pools,upb::FileDefPtr file,Output & output)1446 int WriteEnums(const DefPoolPair& pools, upb::FileDefPtr file, Output& output) {
1447   if (file.syntax() != kUpb_Syntax_Proto2) return 0;
1448 
1449   std::vector<upb::EnumDefPtr> this_file_enums = SortedEnums(file);
1450 
1451   for (const auto e : this_file_enums) {
1452     WriteEnum(e, output);
1453   }
1454 
1455   if (!this_file_enums.empty()) {
1456     output("static const upb_MiniTableEnum *$0[$1] = {\n", kEnumsInit,
1457            this_file_enums.size());
1458     for (const auto e : this_file_enums) {
1459       output("  &$0,\n", EnumInit(e));
1460     }
1461     output("};\n");
1462     output("\n");
1463   }
1464 
1465   return this_file_enums.size();
1466 }
1467 
WriteMessages(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1468 int WriteMessages(const DefPoolPair& pools, upb::FileDefPtr file,
1469                   const Options& options, Output& output) {
1470   std::vector<upb::MessageDefPtr> file_messages = SortedMessages(file);
1471 
1472   if (file_messages.empty()) return 0;
1473 
1474   for (auto message : file_messages) {
1475     WriteMessage(message, pools, options, output);
1476   }
1477 
1478   output("static const upb_MiniTable *$0[$1] = {\n", kMessagesInit,
1479          file_messages.size());
1480   for (auto message : file_messages) {
1481     output("  &$0,\n", MessageInitName(message));
1482   }
1483   output("};\n");
1484   output("\n");
1485   return file_messages.size();
1486 }
1487 
WriteExtension(upb::FieldDefPtr ext,const DefPoolPair & pools,const Options & options,Output & output)1488 void WriteExtension(upb::FieldDefPtr ext, const DefPoolPair& pools,
1489                     const Options& options, Output& output) {
1490   output("$0,\n", FieldInitializer(pools, ext, options));
1491   output("  &$0,\n", MessageInitName(ext.containing_type()));
1492   output("  $0,\n", GetSub(ext));
1493 }
1494 
WriteExtensions(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1495 int WriteExtensions(const DefPoolPair& pools, upb::FileDefPtr file,
1496                     const Options& options, Output& output) {
1497   auto exts = SortedExtensions(file);
1498 
1499   if (exts.empty()) return 0;
1500 
1501   // Order by full name for consistent ordering.
1502   std::map<std::string, upb::MessageDefPtr> forward_messages;
1503 
1504   for (auto ext : exts) {
1505     forward_messages[ext.containing_type().full_name()] = ext.containing_type();
1506     if (ext.message_type()) {
1507       forward_messages[ext.message_type().full_name()] = ext.message_type();
1508     }
1509   }
1510 
1511   for (const auto& decl : forward_messages) {
1512     ForwardDeclareMiniTableInit(decl.second, options, output);
1513   }
1514 
1515   for (auto ext : exts) {
1516     output("const upb_MiniTableExtension $0 = {\n  ", ExtensionLayout(ext));
1517     WriteExtension(ext, pools, options, output);
1518     output("\n};\n");
1519   }
1520 
1521   output(
1522       "\n"
1523       "static const upb_MiniTableExtension *$0[$1] = {\n",
1524       kExtensionsInit, exts.size());
1525 
1526   for (auto ext : exts) {
1527     output("  &$0,\n", ExtensionLayout(ext));
1528   }
1529 
1530   output(
1531       "};\n"
1532       "\n");
1533   return exts.size();
1534 }
1535 
WriteMiniTableSource(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1536 void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
1537                           const Options& options, Output& output) {
1538   EmitFileWarning(file.name(), output);
1539 
1540   output(
1541       "#include <stddef.h>\n"
1542       "#include \"upb/collections/array_internal.h\"\n"
1543       "#include \"upb/message/internal.h\"\n"
1544       "#include \"upb/mini_table/enum_internal.h\"\n"
1545       "#include \"$0\"\n",
1546       HeaderFilename(file));
1547 
1548   for (int i = 0; i < file.dependency_count(); i++) {
1549     output("#include \"$0\"\n", HeaderFilename(file.dependency(i)));
1550   }
1551 
1552   output(
1553       "\n"
1554       "// Must be last.\n"
1555       "#include \"upb/port/def.inc\"\n"
1556       "\n");
1557 
1558   int msg_count = WriteMessages(pools, file, options, output);
1559   int ext_count = WriteExtensions(pools, file, options, output);
1560   int enum_count = WriteEnums(pools, file, output);
1561 
1562   output("const upb_MiniTableFile $0 = {\n", FileLayoutName(file));
1563   output("  $0,\n", msg_count ? kMessagesInit : "NULL");
1564   output("  $0,\n", enum_count ? kEnumsInit : "NULL");
1565   output("  $0,\n", ext_count ? kExtensionsInit : "NULL");
1566   output("  $0,\n", msg_count);
1567   output("  $0,\n", enum_count);
1568   output("  $0,\n", ext_count);
1569   output("};\n\n");
1570 
1571   output("#include \"upb/port/undef.inc\"\n");
1572   output("\n");
1573 }
1574 
WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg,const Options & options,Output & output)1575 void WriteMessageMiniDescriptorInitializer(upb::MessageDefPtr msg,
1576                                            const Options& options,
1577                                            Output& output) {
1578   Output resolve_calls;
1579   for (int i = 0; i < msg.field_count(); i++) {
1580     upb::FieldDefPtr field = msg.field(i);
1581     if (!field.message_type() && !field.enum_subdef()) continue;
1582     if (field.message_type()) {
1583       resolve_calls(
1584           "upb_MiniTable_SetSubMessage(mini_table, "
1585           "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
1586           "$0), $1);\n  ",
1587           field.number(), MessageMiniTableRef(field.message_type(), options));
1588     } else if (field.enum_subdef() && field.enum_subdef().is_closed()) {
1589       resolve_calls(
1590           "upb_MiniTable_SetSubEnum(mini_table, "
1591           "(upb_MiniTableField*)upb_MiniTable_FindFieldByNumber(mini_table, "
1592           "$0), $1);\n  ",
1593           field.number(), EnumMiniTableRef(field.enum_subdef(), options));
1594     }
1595   }
1596 
1597   output(
1598       R"cc(
1599         const upb_MiniTable* $0() {
1600           static upb_MiniTable* mini_table = NULL;
1601           static const char* mini_descriptor = "$1";
1602           if (mini_table) return mini_table;
1603           mini_table =
1604               upb_MiniTable_Build(mini_descriptor, strlen(mini_descriptor),
1605                                   upb_BootstrapArena(), NULL);
1606           $2return mini_table;
1607         }
1608       )cc",
1609       MessageInitName(msg), msg.MiniDescriptorEncode(), resolve_calls.output());
1610   output("\n");
1611 }
1612 
WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def,const Options & options,Output & output)1613 void WriteEnumMiniDescriptorInitializer(upb::EnumDefPtr enum_def,
1614                                         const Options& options,
1615                                         Output& output) {
1616   output(
1617       R"cc(
1618         const upb_MiniTableEnum* $0() {
1619           static const upb_MiniTableEnum* mini_table = NULL;
1620           static const char* mini_descriptor = "$1";
1621           if (mini_table) return mini_table;
1622           mini_table =
1623               upb_MiniTableEnum_Build(mini_descriptor, strlen(mini_descriptor),
1624                                       upb_BootstrapArena(), NULL);
1625           return mini_table;
1626         }
1627       )cc",
1628       EnumInitName(enum_def), enum_def.MiniDescriptorEncode());
1629   output("\n");
1630 }
1631 
WriteMiniDescriptorSource(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1632 void WriteMiniDescriptorSource(const DefPoolPair& pools, upb::FileDefPtr file,
1633                                const Options& options, Output& output) {
1634   output(
1635       "#include <stddef.h>\n"
1636       "#include \"upb/collections/array_internal.h\"\n"
1637       "#include \"upb/message/internal.h\"\n"
1638       "#include \"upb/mini_table/decode.h\"\n"
1639       "#include \"upb/mini_table/enum_internal.h\"\n"
1640       "#include \"$0\"\n\n",
1641       HeaderFilename(file));
1642 
1643   for (int i = 0; i < file.dependency_count(); i++) {
1644     output("#include \"$0\"\n", HeaderFilename(file.dependency(i)));
1645   }
1646 
1647   output(
1648       R"cc(
1649         static upb_Arena* upb_BootstrapArena() {
1650           static upb_Arena* arena = NULL;
1651           if (!arena) arena = upb_Arena_New();
1652           return arena;
1653         }
1654       )cc");
1655 
1656   output("\n");
1657 
1658   for (const auto msg : SortedMessages(file)) {
1659     WriteMessageMiniDescriptorInitializer(msg, options, output);
1660   }
1661 
1662   for (const auto msg : SortedEnums(file)) {
1663     WriteEnumMiniDescriptorInitializer(msg, options, output);
1664   }
1665 }
1666 
WriteSource(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Output & output)1667 void WriteSource(const DefPoolPair& pools, upb::FileDefPtr file,
1668                  const Options& options, Output& output) {
1669   if (options.bootstrap) {
1670     WriteMiniDescriptorSource(pools, file, options, output);
1671   } else {
1672     WriteMiniTableSource(pools, file, options, output);
1673   }
1674 }
1675 
GenerateFile(const DefPoolPair & pools,upb::FileDefPtr file,const Options & options,Plugin * plugin)1676 void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file,
1677                   const Options& options, Plugin* plugin) {
1678   Output h_output;
1679   WriteHeader(pools, file, options, h_output);
1680   plugin->AddOutputFile(HeaderFilename(file), h_output.output());
1681 
1682   Output c_output;
1683   WriteSource(pools, file, options, c_output);
1684   plugin->AddOutputFile(SourceFilename(file), c_output.output());
1685 }
1686 
ParseOptions(Plugin * plugin,Options * options)1687 bool ParseOptions(Plugin* plugin, Options* options) {
1688   for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) {
1689     if (pair.first == "bootstrap_upb") {
1690       options->bootstrap = true;
1691     } else {
1692       plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first));
1693       return false;
1694     }
1695   }
1696 
1697   return true;
1698 }
1699 
ToStringView(upb_StringView str)1700 absl::string_view ToStringView(upb_StringView str) {
1701   return absl::string_view(str.data, str.size);
1702 }
1703 
1704 }  // namespace
1705 
1706 }  // namespace upbc
1707 
main(int argc,char ** argv)1708 int main(int argc, char** argv) {
1709   upbc::DefPoolPair pools;
1710   upbc::Plugin plugin;
1711   upbc::Options options;
1712   if (!ParseOptions(&plugin, &options)) return 0;
1713   plugin.GenerateFilesRaw([&](const UPB_DESC(FileDescriptorProto) * file_proto,
1714                               bool generate) {
1715     upb::Status status;
1716     upb::FileDefPtr file = pools.AddFile(file_proto, &status);
1717     if (!file) {
1718       absl::string_view name =
1719           upbc::ToStringView(UPB_DESC(FileDescriptorProto_name)(file_proto));
1720       ABSL_LOG(FATAL) << "Couldn't add file " << name
1721                       << " to DefPool: " << status.error_message();
1722     }
1723     if (generate) GenerateFile(pools, file, options, &plugin);
1724   });
1725   return 0;
1726 }
1727