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