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