xref: /llvm-project/clang/lib/APINotes/APINotesWriter.cpp (revision 48f7f63ac723a5001b74627493d360ff3d8d1186)
1 //===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/APINotes/APINotesWriter.h"
10 #include "APINotesFormat.h"
11 #include "clang/APINotes/Types.h"
12 #include "clang/Basic/FileManager.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/Bitstream/BitstreamWriter.h"
16 #include "llvm/Support/DJB.h"
17 #include "llvm/Support/OnDiskHashTable.h"
18 #include "llvm/Support/VersionTuple.h"
19 
20 namespace clang {
21 namespace api_notes {
22 class APINotesWriter::Implementation {
23   friend class APINotesWriter;
24 
25   template <typename T>
26   using VersionedSmallVector =
27       llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
28 
29   std::string ModuleName;
30   const FileEntry *SourceFile;
31 
32   /// Scratch space for bitstream writing.
33   llvm::SmallVector<uint64_t, 64> Scratch;
34 
35   /// Mapping from strings to identifier IDs.
36   llvm::StringMap<IdentifierID> IdentifierIDs;
37 
38   /// Information about contexts (Objective-C classes or protocols or C++
39   /// namespaces).
40   ///
41   /// Indexed by the parent context ID, context kind and the identifier ID of
42   /// this context and provides both the context ID and information describing
43   /// the context within that module.
44   llvm::DenseMap<ContextTableKey,
45                  std::pair<unsigned, VersionedSmallVector<ContextInfo>>>
46       Contexts;
47 
48   /// Information about parent contexts for each context.
49   ///
50   /// Indexed by context ID, provides the parent context ID.
51   llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
52 
53   /// Mapping from context IDs to the identifier ID holding the name.
54   llvm::DenseMap<unsigned, unsigned> ContextNames;
55 
56   /// Information about Objective-C properties.
57   ///
58   /// Indexed by the context ID, property name, and whether this is an
59   /// instance property.
60   llvm::DenseMap<
61       std::tuple<unsigned, unsigned, char>,
62       llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>
63       ObjCProperties;
64 
65   /// Information about C record fields.
66   ///
67   /// Indexed by the context ID and name ID.
68   llvm::DenseMap<SingleDeclTableKey,
69                  llvm::SmallVector<std::pair<VersionTuple, FieldInfo>, 1>>
70       Fields;
71 
72   /// Information about Objective-C methods.
73   ///
74   /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
75   /// indicating whether this is a class or instance method.
76   llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
77                  llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
78       ObjCMethods;
79 
80   /// Information about C++ methods.
81   ///
82   /// Indexed by the context ID and name ID.
83   llvm::DenseMap<SingleDeclTableKey,
84                  llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
85       CXXMethods;
86 
87   /// Mapping from selectors to selector ID.
88   llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
89 
90   /// Information about global variables.
91   ///
92   /// Indexed by the context ID, identifier ID.
93   llvm::DenseMap<
94       SingleDeclTableKey,
95       llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
96       GlobalVariables;
97 
98   /// Information about global functions.
99   ///
100   /// Indexed by the context ID, identifier ID.
101   llvm::DenseMap<
102       SingleDeclTableKey,
103       llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
104       GlobalFunctions;
105 
106   /// Information about enumerators.
107   ///
108   /// Indexed by the identifier ID.
109   llvm::DenseMap<
110       unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
111       EnumConstants;
112 
113   /// Information about tags.
114   ///
115   /// Indexed by the context ID, identifier ID.
116   llvm::DenseMap<SingleDeclTableKey,
117                  llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
118       Tags;
119 
120   /// Information about typedefs.
121   ///
122   /// Indexed by the context ID, identifier ID.
123   llvm::DenseMap<SingleDeclTableKey,
124                  llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
125       Typedefs;
126 
127   /// Retrieve the ID for the given identifier.
128   IdentifierID getIdentifier(StringRef Identifier) {
129     if (Identifier.empty())
130       return 0;
131 
132     // Add to the identifier table if missing.
133     return IdentifierIDs.try_emplace(Identifier, IdentifierIDs.size() + 1)
134         .first->second;
135   }
136 
137   /// Retrieve the ID for the given selector.
138   SelectorID getSelector(ObjCSelectorRef SelectorRef) {
139     // Translate the selector reference into a stored selector.
140     StoredObjCSelector Selector;
141     Selector.NumArgs = SelectorRef.NumArgs;
142     Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
143     for (auto piece : SelectorRef.Identifiers)
144       Selector.Identifiers.push_back(getIdentifier(piece));
145 
146     // Look for the stored selector.  Add to the selector table if missing.
147     return SelectorIDs.try_emplace(Selector, SelectorIDs.size()).first->second;
148   }
149 
150 private:
151   void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
152   void writeControlBlock(llvm::BitstreamWriter &Stream);
153   void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
154   void writeContextBlock(llvm::BitstreamWriter &Stream);
155   void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
156   void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
157   void writeCXXMethodBlock(llvm::BitstreamWriter &Stream);
158   void writeFieldBlock(llvm::BitstreamWriter &Stream);
159   void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
160   void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
161   void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
162   void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
163   void writeTagBlock(llvm::BitstreamWriter &Stream);
164   void writeTypedefBlock(llvm::BitstreamWriter &Stream);
165 
166 public:
167   Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
168       : ModuleName(std::string(ModuleName)), SourceFile(SF) {}
169 
170   void writeToStream(llvm::raw_ostream &OS);
171 };
172 
173 void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
174   llvm::SmallVector<char, 0> Buffer;
175 
176   {
177     llvm::BitstreamWriter Stream(Buffer);
178 
179     // Emit the signature.
180     for (unsigned char Byte : API_NOTES_SIGNATURE)
181       Stream.Emit(Byte, 8);
182 
183     // Emit the blocks.
184     writeBlockInfoBlock(Stream);
185     writeControlBlock(Stream);
186     writeIdentifierBlock(Stream);
187     writeContextBlock(Stream);
188     writeObjCPropertyBlock(Stream);
189     writeObjCMethodBlock(Stream);
190     writeCXXMethodBlock(Stream);
191     writeFieldBlock(Stream);
192     writeObjCSelectorBlock(Stream);
193     writeGlobalVariableBlock(Stream);
194     writeGlobalFunctionBlock(Stream);
195     writeEnumConstantBlock(Stream);
196     writeTagBlock(Stream);
197     writeTypedefBlock(Stream);
198   }
199 
200   OS.write(Buffer.data(), Buffer.size());
201   OS.flush();
202 }
203 
204 namespace {
205 /// Record the name of a block.
206 void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
207                  llvm::StringRef Name) {
208   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
209                     llvm::ArrayRef<unsigned>{ID});
210 
211   // Emit the block name if present.
212   if (Name.empty())
213     return;
214   Stream.EmitRecord(
215       llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
216       llvm::ArrayRef<unsigned char>(
217           const_cast<unsigned char *>(
218               reinterpret_cast<const unsigned char *>(Name.data())),
219           Name.size()));
220 }
221 
222 /// Record the name of a record within a block.
223 void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
224                   llvm::StringRef Name) {
225   assert(ID < 256 && "can't fit record ID in next to name");
226 
227   llvm::SmallVector<unsigned char, 64> Buffer;
228   Buffer.resize(Name.size() + 1);
229   Buffer[0] = ID;
230   memcpy(Buffer.data() + 1, Name.data(), Name.size());
231 
232   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
233 }
234 } // namespace
235 
236 void APINotesWriter::Implementation::writeBlockInfoBlock(
237     llvm::BitstreamWriter &Stream) {
238   llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
239 
240 #define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
241 #define BLOCK_RECORD(NameSpace, Block)                                         \
242   emitRecordID(Stream, NameSpace::Block, #Block)
243   BLOCK(CONTROL_BLOCK);
244   BLOCK_RECORD(control_block, METADATA);
245   BLOCK_RECORD(control_block, MODULE_NAME);
246 
247   BLOCK(IDENTIFIER_BLOCK);
248   BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
249 
250   BLOCK(OBJC_CONTEXT_BLOCK);
251   BLOCK_RECORD(context_block, CONTEXT_ID_DATA);
252 
253   BLOCK(OBJC_PROPERTY_BLOCK);
254   BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
255 
256   BLOCK(OBJC_METHOD_BLOCK);
257   BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
258 
259   BLOCK(OBJC_SELECTOR_BLOCK);
260   BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
261 
262   BLOCK(GLOBAL_VARIABLE_BLOCK);
263   BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
264 
265   BLOCK(GLOBAL_FUNCTION_BLOCK);
266   BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
267 #undef BLOCK_RECORD
268 #undef BLOCK
269 }
270 
271 void APINotesWriter::Implementation::writeControlBlock(
272     llvm::BitstreamWriter &Stream) {
273   llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);
274 
275   control_block::MetadataLayout Metadata(Stream);
276   Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);
277 
278   control_block::ModuleNameLayout ModuleName(Stream);
279   ModuleName.emit(Scratch, this->ModuleName);
280 
281   if (SourceFile) {
282     control_block::SourceFileLayout SourceFile(Stream);
283     SourceFile.emit(Scratch, this->SourceFile->getSize(),
284                     this->SourceFile->getModificationTime());
285   }
286 }
287 
288 namespace {
289 /// Used to serialize the on-disk identifier table.
290 class IdentifierTableInfo {
291 public:
292   using key_type = StringRef;
293   using key_type_ref = key_type;
294   using data_type = IdentifierID;
295   using data_type_ref = const data_type &;
296   using hash_value_type = uint32_t;
297   using offset_type = unsigned;
298 
299   hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
300 
301   std::pair<unsigned, unsigned>
302   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
303     uint32_t KeyLength = Key.size();
304     uint32_t DataLength = sizeof(uint32_t);
305 
306     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
307     writer.write<uint16_t>(KeyLength);
308     writer.write<uint16_t>(DataLength);
309     return {KeyLength, DataLength};
310   }
311 
312   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
313 
314   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
315     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
316     writer.write<uint32_t>(Data);
317   }
318 };
319 } // namespace
320 
321 void APINotesWriter::Implementation::writeIdentifierBlock(
322     llvm::BitstreamWriter &Stream) {
323   llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);
324 
325   if (IdentifierIDs.empty())
326     return;
327 
328   llvm::SmallString<4096> HashTableBlob;
329   uint32_t Offset;
330   {
331     llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
332     for (auto &II : IdentifierIDs)
333       Generator.insert(II.first(), II.second);
334 
335     llvm::raw_svector_ostream BlobStream(HashTableBlob);
336     // Make sure that no bucket is at offset 0
337     llvm::support::endian::write<uint32_t>(BlobStream, 0,
338                                            llvm::endianness::little);
339     Offset = Generator.Emit(BlobStream);
340   }
341 
342   identifier_block::IdentifierDataLayout IdentifierData(Stream);
343   IdentifierData.emit(Scratch, Offset, HashTableBlob);
344 }
345 
346 namespace {
347 /// Used to serialize the on-disk Objective-C context table.
348 class ContextIDTableInfo {
349 public:
350   using key_type = ContextTableKey;
351   using key_type_ref = key_type;
352   using data_type = unsigned;
353   using data_type_ref = const data_type &;
354   using hash_value_type = size_t;
355   using offset_type = unsigned;
356 
357   hash_value_type ComputeHash(key_type_ref Key) {
358     return static_cast<size_t>(Key.hashValue());
359   }
360 
361   std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
362                                                   data_type_ref) {
363     uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
364     uint32_t DataLength = sizeof(uint32_t);
365 
366     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
367     writer.write<uint16_t>(KeyLength);
368     writer.write<uint16_t>(DataLength);
369     return {KeyLength, DataLength};
370   }
371 
372   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
373     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
374     writer.write<uint32_t>(Key.parentContextID);
375     writer.write<uint8_t>(Key.contextKind);
376     writer.write<uint32_t>(Key.contextID);
377   }
378 
379   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
380     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
381     writer.write<uint32_t>(Data);
382   }
383 };
384 
385 /// Localized helper to make a type dependent, thwarting template argument
386 /// deduction.
387 template <typename T> struct MakeDependent { typedef T Type; };
388 
389 /// Retrieve the serialized size of the given VersionTuple, for use in
390 /// on-disk hash tables.
391 unsigned getVersionTupleSize(const VersionTuple &VT) {
392   unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
393   if (VT.getMinor())
394     size += sizeof(uint32_t);
395   if (VT.getSubminor())
396     size += sizeof(uint32_t);
397   if (VT.getBuild())
398     size += sizeof(uint32_t);
399   return size;
400 }
401 
402 /// Determine the size of an array of versioned information,
403 template <typename T>
404 unsigned getVersionedInfoSize(
405     const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
406     llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
407         getInfoSize) {
408   unsigned result = sizeof(uint16_t); // # of elements
409   for (const auto &E : VI) {
410     result += getVersionTupleSize(E.first);
411     result += getInfoSize(E.second);
412   }
413   return result;
414 }
415 
416 /// Emit a serialized representation of a version tuple.
417 void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
418   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
419 
420   // First byte contains the number of components beyond the 'major' component.
421   uint8_t descriptor;
422   if (VT.getBuild())
423     descriptor = 3;
424   else if (VT.getSubminor())
425     descriptor = 2;
426   else if (VT.getMinor())
427     descriptor = 1;
428   else
429     descriptor = 0;
430   writer.write<uint8_t>(descriptor);
431 
432   // Write the components.
433   writer.write<uint32_t>(VT.getMajor());
434   if (auto minor = VT.getMinor())
435     writer.write<uint32_t>(*minor);
436   if (auto subminor = VT.getSubminor())
437     writer.write<uint32_t>(*subminor);
438   if (auto build = VT.getBuild())
439     writer.write<uint32_t>(*build);
440 }
441 
442 /// Emit versioned information.
443 template <typename T>
444 void emitVersionedInfo(
445     raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
446     llvm::function_ref<void(raw_ostream &,
447                             const typename MakeDependent<T>::Type &)>
448         emitInfo) {
449   std::sort(VI.begin(), VI.end(),
450             [](const std::pair<VersionTuple, T> &LHS,
451                const std::pair<VersionTuple, T> &RHS) -> bool {
452               assert((&LHS == &RHS || LHS.first != RHS.first) &&
453                      "two entries for the same version");
454               return LHS.first < RHS.first;
455             });
456 
457   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
458   writer.write<uint16_t>(VI.size());
459   for (const auto &E : VI) {
460     emitVersionTuple(OS, E.first);
461     emitInfo(OS, E.second);
462   }
463 }
464 
465 /// On-disk hash table info key base for handling versioned data.
466 template <typename Derived, typename KeyType, typename UnversionedDataType>
467 class VersionedTableInfo {
468   Derived &asDerived() { return *static_cast<Derived *>(this); }
469 
470   const Derived &asDerived() const {
471     return *static_cast<const Derived *>(this);
472   }
473 
474 public:
475   using key_type = KeyType;
476   using key_type_ref = key_type;
477   using data_type =
478       llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
479   using data_type_ref = data_type &;
480   using hash_value_type = size_t;
481   using offset_type = unsigned;
482 
483   std::pair<unsigned, unsigned>
484   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
485     uint32_t KeyLength = asDerived().getKeyLength(Key);
486     uint32_t DataLength =
487         getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
488           return asDerived().getUnversionedInfoSize(UI);
489         });
490 
491     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
492     writer.write<uint16_t>(KeyLength);
493     writer.write<uint16_t>(DataLength);
494     return {KeyLength, DataLength};
495   }
496 
497   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
498     emitVersionedInfo(
499         OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
500           asDerived().emitUnversionedInfo(OS, UI);
501         });
502   }
503 };
504 
505 /// Emit a serialized representation of the common entity information.
506 void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
507   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
508 
509   uint8_t payload = 0;
510   if (auto swiftPrivate = CEI.isSwiftPrivate()) {
511     payload |= 0x01;
512     if (*swiftPrivate)
513       payload |= 0x02;
514   }
515   payload <<= 1;
516   payload |= CEI.Unavailable;
517   payload <<= 1;
518   payload |= CEI.UnavailableInSwift;
519 
520   writer.write<uint8_t>(payload);
521 
522   writer.write<uint16_t>(CEI.UnavailableMsg.size());
523   OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
524 
525   writer.write<uint16_t>(CEI.SwiftName.size());
526   OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
527 }
528 
529 /// Retrieve the serialized size of the given CommonEntityInfo, for use in
530 /// on-disk hash tables.
531 unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
532   return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
533 }
534 
535 // Retrieve the serialized size of the given CommonTypeInfo, for use
536 // in on-disk hash tables.
537 unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
538   return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
539          (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
540          getCommonEntityInfoSize(CTI);
541 }
542 
543 /// Emit a serialized representation of the common type information.
544 void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
545   emitCommonEntityInfo(OS, CTI);
546 
547   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
548   if (auto swiftBridge = CTI.getSwiftBridge()) {
549     writer.write<uint16_t>(swiftBridge->size() + 1);
550     OS.write(swiftBridge->c_str(), swiftBridge->size());
551   } else {
552     writer.write<uint16_t>(0);
553   }
554   if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
555     writer.write<uint16_t>(nsErrorDomain->size() + 1);
556     OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
557   } else {
558     writer.write<uint16_t>(0);
559   }
560 }
561 
562 /// Used to serialize the on-disk Objective-C property table.
563 class ContextInfoTableInfo
564     : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
565 public:
566   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
567 
568   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
569     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
570     writer.write<uint32_t>(Key);
571   }
572 
573   hash_value_type ComputeHash(key_type_ref Key) {
574     return static_cast<size_t>(llvm::hash_value(Key));
575   }
576 
577   unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
578     return getCommonTypeInfoSize(OCI) + 1;
579   }
580 
581   void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
582     emitCommonTypeInfo(OS, OCI);
583 
584     uint8_t payload = 0;
585     if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
586       payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
587     payload <<= 2;
588     if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
589       payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
590     payload <<= 3;
591     if (auto nullable = OCI.getDefaultNullability())
592       payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
593     payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
594 
595     OS << payload;
596   }
597 };
598 } // namespace
599 
600 void APINotesWriter::Implementation::writeContextBlock(
601     llvm::BitstreamWriter &Stream) {
602   llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
603 
604   if (Contexts.empty())
605     return;
606 
607   {
608     llvm::SmallString<4096> HashTableBlob;
609     uint32_t Offset;
610     {
611       llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
612       for (auto &OC : Contexts)
613         Generator.insert(OC.first, OC.second.first);
614 
615       llvm::raw_svector_ostream BlobStream(HashTableBlob);
616       // Make sure that no bucket is at offset 0
617       llvm::support::endian::write<uint32_t>(BlobStream, 0,
618                                              llvm::endianness::little);
619       Offset = Generator.Emit(BlobStream);
620     }
621 
622     context_block::ContextIDLayout ContextID(Stream);
623     ContextID.emit(Scratch, Offset, HashTableBlob);
624   }
625 
626   {
627     llvm::SmallString<4096> HashTableBlob;
628     uint32_t Offset;
629     {
630       llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
631       for (auto &OC : Contexts)
632         Generator.insert(OC.second.first, OC.second.second);
633 
634       llvm::raw_svector_ostream BlobStream(HashTableBlob);
635       // Make sure that no bucket is at offset 0
636       llvm::support::endian::write<uint32_t>(BlobStream, 0,
637                                              llvm::endianness::little);
638       Offset = Generator.Emit(BlobStream);
639     }
640 
641     context_block::ContextInfoLayout ContextInfo(Stream);
642     ContextInfo.emit(Scratch, Offset, HashTableBlob);
643   }
644 }
645 
646 namespace {
647 /// Retrieve the serialized size of the given VariableInfo, for use in
648 /// on-disk hash tables.
649 unsigned getVariableInfoSize(const VariableInfo &VI) {
650   return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
651 }
652 unsigned getParamInfoSize(const ParamInfo &PI);
653 
654 /// Emit a serialized representation of the variable information.
655 void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
656   emitCommonEntityInfo(OS, VI);
657 
658   uint8_t bytes[2] = {0, 0};
659   if (auto nullable = VI.getNullability()) {
660     bytes[0] = 1;
661     bytes[1] = static_cast<uint8_t>(*nullable);
662   } else {
663     // Nothing to do.
664   }
665 
666   OS.write(reinterpret_cast<const char *>(bytes), 2);
667 
668   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
669   writer.write<uint16_t>(VI.getType().size());
670   OS.write(VI.getType().data(), VI.getType().size());
671 }
672 
673 /// Used to serialize the on-disk Objective-C property table.
674 class ObjCPropertyTableInfo
675     : public VersionedTableInfo<ObjCPropertyTableInfo,
676                                 std::tuple<unsigned, unsigned, char>,
677                                 ObjCPropertyInfo> {
678 public:
679   unsigned getKeyLength(key_type_ref) {
680     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
681   }
682 
683   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
684     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
685     writer.write<uint32_t>(std::get<0>(Key));
686     writer.write<uint32_t>(std::get<1>(Key));
687     writer.write<uint8_t>(std::get<2>(Key));
688   }
689 
690   hash_value_type ComputeHash(key_type_ref Key) {
691     return static_cast<size_t>(llvm::hash_value(Key));
692   }
693 
694   unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
695     return getVariableInfoSize(OPI) + 1;
696   }
697 
698   void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
699     emitVariableInfo(OS, OPI);
700 
701     uint8_t flags = 0;
702     if (auto value = OPI.getSwiftImportAsAccessors()) {
703       flags |= 1 << 0;
704       flags |= value.value() << 1;
705     }
706     OS << flags;
707   }
708 };
709 } // namespace
710 
711 void APINotesWriter::Implementation::writeObjCPropertyBlock(
712     llvm::BitstreamWriter &Stream) {
713   llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
714 
715   if (ObjCProperties.empty())
716     return;
717 
718   {
719     llvm::SmallString<4096> HashTableBlob;
720     uint32_t Offset;
721     {
722       llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
723       for (auto &OP : ObjCProperties)
724         Generator.insert(OP.first, OP.second);
725 
726       llvm::raw_svector_ostream BlobStream(HashTableBlob);
727       // Make sure that no bucket is at offset 0
728       llvm::support::endian::write<uint32_t>(BlobStream, 0,
729                                              llvm::endianness::little);
730       Offset = Generator.Emit(BlobStream);
731     }
732 
733     objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
734     ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
735   }
736 }
737 
738 namespace {
739 unsigned getFunctionInfoSize(const FunctionInfo &);
740 void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
741 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);
742 
743 /// Used to serialize the on-disk Objective-C method table.
744 class ObjCMethodTableInfo
745     : public VersionedTableInfo<ObjCMethodTableInfo,
746                                 std::tuple<unsigned, unsigned, char>,
747                                 ObjCMethodInfo> {
748 public:
749   unsigned getKeyLength(key_type_ref) {
750     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
751   }
752 
753   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
754     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
755     writer.write<uint32_t>(std::get<0>(Key));
756     writer.write<uint32_t>(std::get<1>(Key));
757     writer.write<uint8_t>(std::get<2>(Key));
758   }
759 
760   hash_value_type ComputeHash(key_type_ref key) {
761     return static_cast<size_t>(llvm::hash_value(key));
762   }
763 
764   unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
765     auto size = getFunctionInfoSize(OMI) + 1;
766     if (OMI.Self)
767       size += getParamInfoSize(*OMI.Self);
768     return size;
769   }
770 
771   void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
772     uint8_t flags = 0;
773     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
774     flags = (flags << 1) | OMI.DesignatedInit;
775     flags = (flags << 1) | OMI.RequiredInit;
776     flags = (flags << 1) | static_cast<bool>(OMI.Self);
777     writer.write<uint8_t>(flags);
778 
779     emitFunctionInfo(OS, OMI);
780 
781     if (OMI.Self)
782       emitParamInfo(OS, *OMI.Self);
783   }
784 };
785 
786 /// Used to serialize the on-disk C++ method table.
787 class CXXMethodTableInfo
788     : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
789                                 CXXMethodInfo> {
790 public:
791   unsigned getKeyLength(key_type_ref) {
792     return sizeof(uint32_t) + sizeof(uint32_t);
793   }
794 
795   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
796     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
797     writer.write<uint32_t>(Key.parentContextID);
798     writer.write<uint32_t>(Key.nameID);
799   }
800 
801   hash_value_type ComputeHash(key_type_ref key) {
802     return static_cast<size_t>(key.hashValue());
803   }
804 
805   unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {
806     auto size = getFunctionInfoSize(MI) + 1;
807     if (MI.This)
808       size += getParamInfoSize(*MI.This);
809     return size;
810   }
811 
812   void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {
813     uint8_t flags = 0;
814     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
815     flags = (flags << 1) | static_cast<bool>(MI.This);
816     writer.write<uint8_t>(flags);
817 
818     emitFunctionInfo(OS, MI);
819     if (MI.This)
820       emitParamInfo(OS, *MI.This);
821   }
822 };
823 } // namespace
824 
825 void APINotesWriter::Implementation::writeObjCMethodBlock(
826     llvm::BitstreamWriter &Stream) {
827   llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
828 
829   if (ObjCMethods.empty())
830     return;
831 
832   {
833     llvm::SmallString<4096> HashTableBlob;
834     uint32_t Offset;
835     {
836       llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
837       for (auto &OM : ObjCMethods)
838         Generator.insert(OM.first, OM.second);
839 
840       llvm::raw_svector_ostream BlobStream(HashTableBlob);
841       // Make sure that no bucket is at offset 0
842       llvm::support::endian::write<uint32_t>(BlobStream, 0,
843                                              llvm::endianness::little);
844       Offset = Generator.Emit(BlobStream);
845     }
846 
847     objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
848     ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
849   }
850 }
851 
852 void APINotesWriter::Implementation::writeCXXMethodBlock(
853     llvm::BitstreamWriter &Stream) {
854   llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
855 
856   if (CXXMethods.empty())
857     return;
858 
859   {
860     llvm::SmallString<4096> HashTableBlob;
861     uint32_t Offset;
862     {
863       llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
864       for (auto &MD : CXXMethods)
865         Generator.insert(MD.first, MD.second);
866 
867       llvm::raw_svector_ostream BlobStream(HashTableBlob);
868       // Make sure that no bucket is at offset 0
869       llvm::support::endian::write<uint32_t>(BlobStream, 0,
870                                              llvm::endianness::little);
871       Offset = Generator.Emit(BlobStream);
872     }
873 
874     cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
875     CXXMethodData.emit(Scratch, Offset, HashTableBlob);
876   }
877 }
878 
879 namespace {
880 /// Used to serialize the on-disk C field table.
881 class FieldTableInfo
882     : public VersionedTableInfo<FieldTableInfo, SingleDeclTableKey, FieldInfo> {
883 public:
884   unsigned getKeyLength(key_type_ref) {
885     return sizeof(uint32_t) + sizeof(uint32_t);
886   }
887 
888   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
889     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
890     writer.write<uint32_t>(Key.parentContextID);
891     writer.write<uint32_t>(Key.nameID);
892   }
893 
894   hash_value_type ComputeHash(key_type_ref key) {
895     return static_cast<size_t>(key.hashValue());
896   }
897 
898   unsigned getUnversionedInfoSize(const FieldInfo &FI) {
899     return getVariableInfoSize(FI);
900   }
901 
902   void emitUnversionedInfo(raw_ostream &OS, const FieldInfo &FI) {
903     emitVariableInfo(OS, FI);
904   }
905 };
906 } // namespace
907 
908 void APINotesWriter::Implementation::writeFieldBlock(
909     llvm::BitstreamWriter &Stream) {
910   llvm::BCBlockRAII Scope(Stream, FIELD_BLOCK_ID, 3);
911 
912   if (Fields.empty())
913     return;
914 
915   {
916     llvm::SmallString<4096> HashTableBlob;
917     uint32_t Offset;
918     {
919       llvm::OnDiskChainedHashTableGenerator<FieldTableInfo> Generator;
920       for (auto &FD : Fields)
921         Generator.insert(FD.first, FD.second);
922 
923       llvm::raw_svector_ostream BlobStream(HashTableBlob);
924       // Make sure that no bucket is at offset 0
925       llvm::support::endian::write<uint32_t>(BlobStream, 0,
926                                              llvm::endianness::little);
927       Offset = Generator.Emit(BlobStream);
928     }
929 
930     field_block::FieldDataLayout FieldData(Stream);
931     FieldData.emit(Scratch, Offset, HashTableBlob);
932   }
933 }
934 
935 namespace {
936 /// Used to serialize the on-disk Objective-C selector table.
937 class ObjCSelectorTableInfo {
938 public:
939   using key_type = StoredObjCSelector;
940   using key_type_ref = const key_type &;
941   using data_type = SelectorID;
942   using data_type_ref = data_type;
943   using hash_value_type = unsigned;
944   using offset_type = unsigned;
945 
946   hash_value_type ComputeHash(key_type_ref Key) {
947     return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
948   }
949 
950   std::pair<unsigned, unsigned>
951   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
952     uint32_t KeyLength =
953         sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
954     uint32_t DataLength = sizeof(uint32_t);
955 
956     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
957     writer.write<uint16_t>(KeyLength);
958     writer.write<uint16_t>(DataLength);
959     return {KeyLength, DataLength};
960   }
961 
962   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
963     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
964     writer.write<uint16_t>(Key.NumArgs);
965     for (auto Identifier : Key.Identifiers)
966       writer.write<uint32_t>(Identifier);
967   }
968 
969   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
970     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
971     writer.write<uint32_t>(Data);
972   }
973 };
974 } // namespace
975 
976 void APINotesWriter::Implementation::writeObjCSelectorBlock(
977     llvm::BitstreamWriter &Stream) {
978   llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
979 
980   if (SelectorIDs.empty())
981     return;
982 
983   {
984     llvm::SmallString<4096> HashTableBlob;
985     uint32_t Offset;
986     {
987       llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
988       for (auto &S : SelectorIDs)
989         Generator.insert(S.first, S.second);
990 
991       llvm::raw_svector_ostream BlobStream(HashTableBlob);
992       // Make sure that no bucket is at offset 0
993       llvm::support::endian::write<uint32_t>(BlobStream, 0,
994                                              llvm::endianness::little);
995       Offset = Generator.Emit(BlobStream);
996     }
997 
998     objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
999     ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
1000   }
1001 }
1002 
1003 namespace {
1004 /// Used to serialize the on-disk global variable table.
1005 class GlobalVariableTableInfo
1006     : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,
1007                                 GlobalVariableInfo> {
1008 public:
1009   unsigned getKeyLength(key_type_ref) {
1010     return sizeof(uint32_t) + sizeof(uint32_t);
1011   }
1012 
1013   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1014     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1015     writer.write<uint32_t>(Key.parentContextID);
1016     writer.write<uint32_t>(Key.nameID);
1017   }
1018 
1019   hash_value_type ComputeHash(key_type_ref Key) {
1020     return static_cast<size_t>(Key.hashValue());
1021   }
1022 
1023   unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
1024     return getVariableInfoSize(GVI);
1025   }
1026 
1027   void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
1028     emitVariableInfo(OS, GVI);
1029   }
1030 };
1031 } // namespace
1032 
1033 void APINotesWriter::Implementation::writeGlobalVariableBlock(
1034     llvm::BitstreamWriter &Stream) {
1035   llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
1036 
1037   if (GlobalVariables.empty())
1038     return;
1039 
1040   {
1041     llvm::SmallString<4096> HashTableBlob;
1042     uint32_t Offset;
1043     {
1044       llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
1045       for (auto &GV : GlobalVariables)
1046         Generator.insert(GV.first, GV.second);
1047 
1048       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1049       // Make sure that no bucket is at offset 0
1050       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1051                                              llvm::endianness::little);
1052       Offset = Generator.Emit(BlobStream);
1053     }
1054 
1055     global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
1056     GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
1057   }
1058 }
1059 
1060 namespace {
1061 unsigned getParamInfoSize(const ParamInfo &PI) {
1062   return getVariableInfoSize(PI) + 1;
1063 }
1064 
1065 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
1066   emitVariableInfo(OS, PI);
1067 
1068   uint8_t flags = 0;
1069   if (auto noescape = PI.isNoEscape()) {
1070     flags |= 0x01;
1071     if (*noescape)
1072       flags |= 0x02;
1073   }
1074   flags <<= 2;
1075   if (auto lifetimebound = PI.isLifetimebound()) {
1076     flags |= 0x01;
1077     if (*lifetimebound)
1078       flags |= 0x02;
1079   }
1080   flags <<= 3;
1081   if (auto RCC = PI.getRetainCountConvention())
1082     flags |= static_cast<uint8_t>(RCC.value()) + 1;
1083 
1084   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1085   writer.write<uint8_t>(flags);
1086 }
1087 
1088 /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
1089 /// hash tables.
1090 unsigned getFunctionInfoSize(const FunctionInfo &FI) {
1091   unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
1092   size += sizeof(uint16_t);
1093   for (const auto &P : FI.Params)
1094     size += getParamInfoSize(P);
1095   size += sizeof(uint16_t) + FI.ResultType.size();
1096   size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();
1097   return size;
1098 }
1099 
1100 /// Emit a serialized representation of the function information.
1101 void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
1102   emitCommonEntityInfo(OS, FI);
1103 
1104   uint8_t flags = 0;
1105   flags |= FI.NullabilityAudited;
1106   flags <<= 3;
1107   if (auto RCC = FI.getRetainCountConvention())
1108     flags |= static_cast<uint8_t>(RCC.value()) + 1;
1109 
1110   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1111 
1112   writer.write<uint8_t>(flags);
1113   writer.write<uint8_t>(FI.NumAdjustedNullable);
1114   writer.write<uint64_t>(FI.NullabilityPayload);
1115 
1116   writer.write<uint16_t>(FI.Params.size());
1117   for (const auto &PI : FI.Params)
1118     emitParamInfo(OS, PI);
1119 
1120   writer.write<uint16_t>(FI.ResultType.size());
1121   writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
1122   writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
1123   writer.write(ArrayRef<char>{FI.SwiftReturnOwnership.data(),
1124                               FI.SwiftReturnOwnership.size()});
1125 }
1126 
1127 /// Used to serialize the on-disk global function table.
1128 class GlobalFunctionTableInfo
1129     : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
1130                                 GlobalFunctionInfo> {
1131 public:
1132   unsigned getKeyLength(key_type_ref) {
1133     return sizeof(uint32_t) + sizeof(uint32_t);
1134   }
1135 
1136   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1137     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1138     writer.write<uint32_t>(Key.parentContextID);
1139     writer.write<uint32_t>(Key.nameID);
1140   }
1141 
1142   hash_value_type ComputeHash(key_type_ref Key) {
1143     return static_cast<size_t>(Key.hashValue());
1144   }
1145 
1146   unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1147     return getFunctionInfoSize(GFI);
1148   }
1149 
1150   void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1151     emitFunctionInfo(OS, GFI);
1152   }
1153 };
1154 } // namespace
1155 
1156 void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1157     llvm::BitstreamWriter &Stream) {
1158   llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1159 
1160   if (GlobalFunctions.empty())
1161     return;
1162 
1163   {
1164     llvm::SmallString<4096> HashTableBlob;
1165     uint32_t Offset;
1166     {
1167       llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1168       for (auto &F : GlobalFunctions)
1169         Generator.insert(F.first, F.second);
1170 
1171       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1172       // Make sure that no bucket is at offset 0
1173       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1174                                              llvm::endianness::little);
1175       Offset = Generator.Emit(BlobStream);
1176     }
1177 
1178     global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1179     GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1180   }
1181 }
1182 
1183 namespace {
1184 /// Used to serialize the on-disk global enum constant.
1185 class EnumConstantTableInfo
1186     : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1187                                 EnumConstantInfo> {
1188 public:
1189   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1190 
1191   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1192     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1193     writer.write<uint32_t>(Key);
1194   }
1195 
1196   hash_value_type ComputeHash(key_type_ref Key) {
1197     return static_cast<size_t>(llvm::hash_value(Key));
1198   }
1199 
1200   unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1201     return getCommonEntityInfoSize(ECI);
1202   }
1203 
1204   void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1205     emitCommonEntityInfo(OS, ECI);
1206   }
1207 };
1208 } // namespace
1209 
1210 void APINotesWriter::Implementation::writeEnumConstantBlock(
1211     llvm::BitstreamWriter &Stream) {
1212   llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1213 
1214   if (EnumConstants.empty())
1215     return;
1216 
1217   {
1218     llvm::SmallString<4096> HashTableBlob;
1219     uint32_t Offset;
1220     {
1221       llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1222       for (auto &EC : EnumConstants)
1223         Generator.insert(EC.first, EC.second);
1224 
1225       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1226       // Make sure that no bucket is at offset 0
1227       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1228                                              llvm::endianness::little);
1229       Offset = Generator.Emit(BlobStream);
1230     }
1231 
1232     enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1233     EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1234   }
1235 }
1236 
1237 namespace {
1238 template <typename Derived, typename UnversionedDataType>
1239 class CommonTypeTableInfo
1240     : public VersionedTableInfo<Derived, SingleDeclTableKey,
1241                                 UnversionedDataType> {
1242 public:
1243   using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1244   using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1245 
1246   unsigned getKeyLength(key_type_ref) {
1247     return sizeof(uint32_t) + sizeof(IdentifierID);
1248   }
1249 
1250   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1251     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1252     writer.write<uint32_t>(Key.parentContextID);
1253     writer.write<IdentifierID>(Key.nameID);
1254   }
1255 
1256   hash_value_type ComputeHash(key_type_ref Key) {
1257     return static_cast<size_t>(Key.hashValue());
1258   }
1259 
1260   unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1261     return getCommonTypeInfoSize(UDT);
1262   }
1263 
1264   void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1265     emitCommonTypeInfo(OS, UDT);
1266   }
1267 };
1268 
1269 /// Used to serialize the on-disk tag table.
1270 class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1271 public:
1272   unsigned getUnversionedInfoSize(const TagInfo &TI) {
1273     // clang-format off
1274     return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1275            2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1276            2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1277            2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) +
1278            3 + getCommonTypeInfoSize(TI);
1279     // clang-format on
1280   }
1281 
1282   void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1283     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1284 
1285     uint8_t Flags = 0;
1286     if (auto extensibility = TI.EnumExtensibility) {
1287       Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
1288       assert((Flags < (1 << 2)) && "must fit in two bits");
1289     }
1290 
1291     Flags <<= 2;
1292     if (auto value = TI.isFlagEnum())
1293       Flags |= (value.value() << 1 | 1 << 0);
1294 
1295     writer.write<uint8_t>(Flags);
1296 
1297     if (auto Copyable = TI.isSwiftCopyable())
1298       writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);
1299     else
1300       writer.write<uint8_t>(0);
1301 
1302     if (auto Escapable = TI.isSwiftEscapable())
1303       writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);
1304     else
1305       writer.write<uint8_t>(0);
1306 
1307     if (auto ImportAs = TI.SwiftImportAs) {
1308       writer.write<uint16_t>(ImportAs->size() + 1);
1309       OS.write(ImportAs->c_str(), ImportAs->size());
1310     } else {
1311       writer.write<uint16_t>(0);
1312     }
1313     if (auto RetainOp = TI.SwiftRetainOp) {
1314       writer.write<uint16_t>(RetainOp->size() + 1);
1315       OS.write(RetainOp->c_str(), RetainOp->size());
1316     } else {
1317       writer.write<uint16_t>(0);
1318     }
1319     if (auto ReleaseOp = TI.SwiftReleaseOp) {
1320       writer.write<uint16_t>(ReleaseOp->size() + 1);
1321       OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1322     } else {
1323       writer.write<uint16_t>(0);
1324     }
1325     if (auto Conformance = TI.SwiftConformance) {
1326       writer.write<uint16_t>(Conformance->size() + 1);
1327       OS.write(Conformance->c_str(), Conformance->size());
1328     } else {
1329       writer.write<uint16_t>(0);
1330     }
1331 
1332     emitCommonTypeInfo(OS, TI);
1333   }
1334 };
1335 } // namespace
1336 
1337 void APINotesWriter::Implementation::writeTagBlock(
1338     llvm::BitstreamWriter &Stream) {
1339   llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1340 
1341   if (Tags.empty())
1342     return;
1343 
1344   {
1345     llvm::SmallString<4096> HashTableBlob;
1346     uint32_t Offset;
1347     {
1348       llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1349       for (auto &T : Tags)
1350         Generator.insert(T.first, T.second);
1351 
1352       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1353       // Make sure that no bucket is at offset 0
1354       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1355                                              llvm::endianness::little);
1356       Offset = Generator.Emit(BlobStream);
1357     }
1358 
1359     tag_block::TagDataLayout TagData(Stream);
1360     TagData.emit(Scratch, Offset, HashTableBlob);
1361   }
1362 }
1363 
1364 namespace {
1365 /// Used to serialize the on-disk typedef table.
1366 class TypedefTableInfo
1367     : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1368 public:
1369   unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1370     return 1 + getCommonTypeInfoSize(TI);
1371   }
1372 
1373   void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1374     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1375 
1376     uint8_t Flags = 0;
1377     if (auto swiftWrapper = TI.SwiftWrapper)
1378       Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1379 
1380     writer.write<uint8_t>(Flags);
1381 
1382     emitCommonTypeInfo(OS, TI);
1383   }
1384 };
1385 } // namespace
1386 
1387 void APINotesWriter::Implementation::writeTypedefBlock(
1388     llvm::BitstreamWriter &Stream) {
1389   llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1390 
1391   if (Typedefs.empty())
1392     return;
1393 
1394   {
1395     llvm::SmallString<4096> HashTableBlob;
1396     uint32_t Offset;
1397     {
1398       llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1399       for (auto &T : Typedefs)
1400         Generator.insert(T.first, T.second);
1401 
1402       llvm::raw_svector_ostream BlobStream(HashTableBlob);
1403       // Make sure that no bucket is at offset 0
1404       llvm::support::endian::write<uint32_t>(BlobStream, 0,
1405                                              llvm::endianness::little);
1406       Offset = Generator.Emit(BlobStream);
1407     }
1408 
1409     typedef_block::TypedefDataLayout TypedefData(Stream);
1410     TypedefData.emit(Scratch, Offset, HashTableBlob);
1411   }
1412 }
1413 
1414 // APINotesWriter
1415 
1416 APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1417     : Implementation(new class Implementation(ModuleName, SF)) {}
1418 
1419 APINotesWriter::~APINotesWriter() = default;
1420 
1421 void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1422   Implementation->writeToStream(OS);
1423 }
1424 
1425 ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1426                                      llvm::StringRef Name, ContextKind Kind,
1427                                      const ContextInfo &Info,
1428                                      llvm::VersionTuple SwiftVersion) {
1429   IdentifierID NameID = Implementation->getIdentifier(Name);
1430 
1431   uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1432   ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1433   auto Known = Implementation->Contexts.find(Key);
1434   if (Known == Implementation->Contexts.end()) {
1435     unsigned NextID = Implementation->Contexts.size() + 1;
1436 
1437     Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;
1438     Known = Implementation->Contexts
1439                 .insert(std::make_pair(
1440                     Key, std::make_pair(NextID, EmptyVersionedInfo)))
1441                 .first;
1442 
1443     Implementation->ContextNames[NextID] = NameID;
1444     Implementation->ParentContexts[NextID] = RawParentCtxID;
1445   }
1446 
1447   // Add this version information.
1448   auto &VersionedVec = Known->second.second;
1449   bool Found = false;
1450   for (auto &Versioned : VersionedVec) {
1451     if (Versioned.first == SwiftVersion) {
1452       Versioned.second |= Info;
1453       Found = true;
1454       break;
1455     }
1456   }
1457 
1458   if (!Found)
1459     VersionedVec.push_back({SwiftVersion, Info});
1460 
1461   return ContextID(Known->second.first);
1462 }
1463 
1464 void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
1465                                      bool IsInstanceProperty,
1466                                      const ObjCPropertyInfo &Info,
1467                                      VersionTuple SwiftVersion) {
1468   IdentifierID NameID = Implementation->getIdentifier(Name);
1469   Implementation
1470       ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1471       .push_back({SwiftVersion, Info});
1472 }
1473 
1474 void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
1475                                    bool IsInstanceMethod,
1476                                    const ObjCMethodInfo &Info,
1477                                    VersionTuple SwiftVersion) {
1478   SelectorID SelID = Implementation->getSelector(Selector);
1479   auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1480                                                   IsInstanceMethod};
1481   Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1482 
1483   // If this method is a designated initializer, update the class to note that
1484   // it has designated initializers.
1485   if (Info.DesignatedInit) {
1486     assert(Implementation->ParentContexts.contains(CtxID.Value));
1487     uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1488     ContextTableKey CtxKey(ParentCtxID,
1489                            static_cast<uint8_t>(ContextKind::ObjCClass),
1490                            Implementation->ContextNames[CtxID.Value]);
1491     assert(Implementation->Contexts.contains(CtxKey));
1492     auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1493     bool Found = false;
1494     for (auto &Versioned : VersionedVec) {
1495       if (Versioned.first == SwiftVersion) {
1496         Versioned.second.setHasDesignatedInits(true);
1497         Found = true;
1498         break;
1499       }
1500     }
1501 
1502     if (!Found) {
1503       VersionedVec.push_back({SwiftVersion, ContextInfo()});
1504       VersionedVec.back().second.setHasDesignatedInits(true);
1505     }
1506   }
1507 }
1508 
1509 void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1510                                   const CXXMethodInfo &Info,
1511                                   VersionTuple SwiftVersion) {
1512   IdentifierID NameID = Implementation->getIdentifier(Name);
1513   SingleDeclTableKey Key(CtxID.Value, NameID);
1514   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
1515 }
1516 
1517 void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,
1518                               const FieldInfo &Info,
1519                               VersionTuple SwiftVersion) {
1520   IdentifierID NameID = Implementation->getIdentifier(Name);
1521   SingleDeclTableKey Key(CtxID.Value, NameID);
1522   Implementation->Fields[Key].push_back({SwiftVersion, Info});
1523 }
1524 
1525 void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1526                                        llvm::StringRef Name,
1527                                        const GlobalVariableInfo &Info,
1528                                        VersionTuple SwiftVersion) {
1529   IdentifierID VariableID = Implementation->getIdentifier(Name);
1530   SingleDeclTableKey Key(Ctx, VariableID);
1531   Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1532 }
1533 
1534 void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1535                                        llvm::StringRef Name,
1536                                        const GlobalFunctionInfo &Info,
1537                                        VersionTuple SwiftVersion) {
1538   IdentifierID NameID = Implementation->getIdentifier(Name);
1539   SingleDeclTableKey Key(Ctx, NameID);
1540   Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1541 }
1542 
1543 void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1544                                      const EnumConstantInfo &Info,
1545                                      VersionTuple SwiftVersion) {
1546   IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1547   Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1548 }
1549 
1550 void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1551                             const TagInfo &Info, VersionTuple SwiftVersion) {
1552   IdentifierID TagID = Implementation->getIdentifier(Name);
1553   SingleDeclTableKey Key(Ctx, TagID);
1554   Implementation->Tags[Key].push_back({SwiftVersion, Info});
1555 }
1556 
1557 void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1558                                 llvm::StringRef Name, const TypedefInfo &Info,
1559                                 VersionTuple SwiftVersion) {
1560   IdentifierID TypedefID = Implementation->getIdentifier(Name);
1561   SingleDeclTableKey Key(Ctx, TypedefID);
1562   Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1563 }
1564 } // namespace api_notes
1565 } // namespace clang
1566