xref: /freebsd-src/contrib/llvm-project/clang/lib/APINotes/APINotesWriter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "clang/APINotes/APINotesWriter.h"
105f757f3fSDimitry Andric #include "APINotesFormat.h"
115f757f3fSDimitry Andric #include "clang/APINotes/Types.h"
125f757f3fSDimitry Andric #include "clang/Basic/FileManager.h"
135f757f3fSDimitry Andric #include "llvm/ADT/DenseMap.h"
145f757f3fSDimitry Andric #include "llvm/ADT/StringMap.h"
155f757f3fSDimitry Andric #include "llvm/Bitstream/BitstreamWriter.h"
165f757f3fSDimitry Andric #include "llvm/Support/DJB.h"
175f757f3fSDimitry Andric #include "llvm/Support/OnDiskHashTable.h"
185f757f3fSDimitry Andric #include "llvm/Support/VersionTuple.h"
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric namespace clang {
215f757f3fSDimitry Andric namespace api_notes {
225f757f3fSDimitry Andric class APINotesWriter::Implementation {
235f757f3fSDimitry Andric   friend class APINotesWriter;
245f757f3fSDimitry Andric 
255f757f3fSDimitry Andric   template <typename T>
265f757f3fSDimitry Andric   using VersionedSmallVector =
275f757f3fSDimitry Andric       llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
285f757f3fSDimitry Andric 
295f757f3fSDimitry Andric   std::string ModuleName;
305f757f3fSDimitry Andric   const FileEntry *SourceFile;
315f757f3fSDimitry Andric 
325f757f3fSDimitry Andric   /// Scratch space for bitstream writing.
335f757f3fSDimitry Andric   llvm::SmallVector<uint64_t, 64> Scratch;
345f757f3fSDimitry Andric 
355f757f3fSDimitry Andric   /// Mapping from strings to identifier IDs.
365f757f3fSDimitry Andric   llvm::StringMap<IdentifierID> IdentifierIDs;
375f757f3fSDimitry Andric 
385f757f3fSDimitry Andric   /// Information about contexts (Objective-C classes or protocols or C++
395f757f3fSDimitry Andric   /// namespaces).
405f757f3fSDimitry Andric   ///
415f757f3fSDimitry Andric   /// Indexed by the parent context ID, context kind and the identifier ID of
425f757f3fSDimitry Andric   /// this context and provides both the context ID and information describing
435f757f3fSDimitry Andric   /// the context within that module.
445f757f3fSDimitry Andric   llvm::DenseMap<ContextTableKey,
45*0fca6ea1SDimitry Andric                  std::pair<unsigned, VersionedSmallVector<ContextInfo>>>
46*0fca6ea1SDimitry Andric       Contexts;
475f757f3fSDimitry Andric 
485f757f3fSDimitry Andric   /// Information about parent contexts for each context.
495f757f3fSDimitry Andric   ///
505f757f3fSDimitry Andric   /// Indexed by context ID, provides the parent context ID.
515f757f3fSDimitry Andric   llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
525f757f3fSDimitry Andric 
535f757f3fSDimitry Andric   /// Mapping from context IDs to the identifier ID holding the name.
54*0fca6ea1SDimitry Andric   llvm::DenseMap<unsigned, unsigned> ContextNames;
555f757f3fSDimitry Andric 
565f757f3fSDimitry Andric   /// Information about Objective-C properties.
575f757f3fSDimitry Andric   ///
585f757f3fSDimitry Andric   /// Indexed by the context ID, property name, and whether this is an
595f757f3fSDimitry Andric   /// instance property.
605f757f3fSDimitry Andric   llvm::DenseMap<
615f757f3fSDimitry Andric       std::tuple<unsigned, unsigned, char>,
625f757f3fSDimitry Andric       llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>
635f757f3fSDimitry Andric       ObjCProperties;
645f757f3fSDimitry Andric 
655f757f3fSDimitry Andric   /// Information about Objective-C methods.
665f757f3fSDimitry Andric   ///
675f757f3fSDimitry Andric   /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
685f757f3fSDimitry Andric   /// indicating whether this is a class or instance method.
695f757f3fSDimitry Andric   llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
705f757f3fSDimitry Andric                  llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
715f757f3fSDimitry Andric       ObjCMethods;
725f757f3fSDimitry Andric 
73*0fca6ea1SDimitry Andric   /// Information about C++ methods.
74*0fca6ea1SDimitry Andric   ///
75*0fca6ea1SDimitry Andric   /// Indexed by the context ID and name ID.
76*0fca6ea1SDimitry Andric   llvm::DenseMap<SingleDeclTableKey,
77*0fca6ea1SDimitry Andric                  llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
78*0fca6ea1SDimitry Andric       CXXMethods;
79*0fca6ea1SDimitry Andric 
805f757f3fSDimitry Andric   /// Mapping from selectors to selector ID.
815f757f3fSDimitry Andric   llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
825f757f3fSDimitry Andric 
835f757f3fSDimitry Andric   /// Information about global variables.
845f757f3fSDimitry Andric   ///
85*0fca6ea1SDimitry Andric   /// Indexed by the context ID, identifier ID.
865f757f3fSDimitry Andric   llvm::DenseMap<
87*0fca6ea1SDimitry Andric       SingleDeclTableKey,
885f757f3fSDimitry Andric       llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
895f757f3fSDimitry Andric       GlobalVariables;
905f757f3fSDimitry Andric 
915f757f3fSDimitry Andric   /// Information about global functions.
925f757f3fSDimitry Andric   ///
93*0fca6ea1SDimitry Andric   /// Indexed by the context ID, identifier ID.
945f757f3fSDimitry Andric   llvm::DenseMap<
95*0fca6ea1SDimitry Andric       SingleDeclTableKey,
965f757f3fSDimitry Andric       llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
975f757f3fSDimitry Andric       GlobalFunctions;
985f757f3fSDimitry Andric 
995f757f3fSDimitry Andric   /// Information about enumerators.
1005f757f3fSDimitry Andric   ///
1015f757f3fSDimitry Andric   /// Indexed by the identifier ID.
1025f757f3fSDimitry Andric   llvm::DenseMap<
1035f757f3fSDimitry Andric       unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
1045f757f3fSDimitry Andric       EnumConstants;
1055f757f3fSDimitry Andric 
1065f757f3fSDimitry Andric   /// Information about tags.
1075f757f3fSDimitry Andric   ///
108*0fca6ea1SDimitry Andric   /// Indexed by the context ID, identifier ID.
109*0fca6ea1SDimitry Andric   llvm::DenseMap<SingleDeclTableKey,
1105f757f3fSDimitry Andric                  llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
1115f757f3fSDimitry Andric       Tags;
1125f757f3fSDimitry Andric 
1135f757f3fSDimitry Andric   /// Information about typedefs.
1145f757f3fSDimitry Andric   ///
115*0fca6ea1SDimitry Andric   /// Indexed by the context ID, identifier ID.
116*0fca6ea1SDimitry Andric   llvm::DenseMap<SingleDeclTableKey,
1175f757f3fSDimitry Andric                  llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
1185f757f3fSDimitry Andric       Typedefs;
1195f757f3fSDimitry Andric 
1205f757f3fSDimitry Andric   /// Retrieve the ID for the given identifier.
1215f757f3fSDimitry Andric   IdentifierID getIdentifier(StringRef Identifier) {
1225f757f3fSDimitry Andric     if (Identifier.empty())
1235f757f3fSDimitry Andric       return 0;
1245f757f3fSDimitry Andric 
1255f757f3fSDimitry Andric     auto Known = IdentifierIDs.find(Identifier);
1265f757f3fSDimitry Andric     if (Known != IdentifierIDs.end())
1275f757f3fSDimitry Andric       return Known->second;
1285f757f3fSDimitry Andric 
1295f757f3fSDimitry Andric     // Add to the identifier table.
1305f757f3fSDimitry Andric     Known = IdentifierIDs.insert({Identifier, IdentifierIDs.size() + 1}).first;
1315f757f3fSDimitry Andric     return Known->second;
1325f757f3fSDimitry Andric   }
1335f757f3fSDimitry Andric 
1345f757f3fSDimitry Andric   /// Retrieve the ID for the given selector.
1355f757f3fSDimitry Andric   SelectorID getSelector(ObjCSelectorRef SelectorRef) {
1365f757f3fSDimitry Andric     // Translate the selector reference into a stored selector.
1375f757f3fSDimitry Andric     StoredObjCSelector Selector;
138*0fca6ea1SDimitry Andric     Selector.NumArgs = SelectorRef.NumArgs;
1395f757f3fSDimitry Andric     Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
1405f757f3fSDimitry Andric     for (auto piece : SelectorRef.Identifiers)
1415f757f3fSDimitry Andric       Selector.Identifiers.push_back(getIdentifier(piece));
1425f757f3fSDimitry Andric 
1435f757f3fSDimitry Andric     // Look for the stored selector.
1445f757f3fSDimitry Andric     auto Known = SelectorIDs.find(Selector);
1455f757f3fSDimitry Andric     if (Known != SelectorIDs.end())
1465f757f3fSDimitry Andric       return Known->second;
1475f757f3fSDimitry Andric 
1485f757f3fSDimitry Andric     // Add to the selector table.
1495f757f3fSDimitry Andric     Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first;
1505f757f3fSDimitry Andric     return Known->second;
1515f757f3fSDimitry Andric   }
1525f757f3fSDimitry Andric 
1535f757f3fSDimitry Andric private:
1545f757f3fSDimitry Andric   void writeBlockInfoBlock(llvm::BitstreamWriter &Stream);
1555f757f3fSDimitry Andric   void writeControlBlock(llvm::BitstreamWriter &Stream);
1565f757f3fSDimitry Andric   void writeIdentifierBlock(llvm::BitstreamWriter &Stream);
157*0fca6ea1SDimitry Andric   void writeContextBlock(llvm::BitstreamWriter &Stream);
1585f757f3fSDimitry Andric   void writeObjCPropertyBlock(llvm::BitstreamWriter &Stream);
1595f757f3fSDimitry Andric   void writeObjCMethodBlock(llvm::BitstreamWriter &Stream);
160*0fca6ea1SDimitry Andric   void writeCXXMethodBlock(llvm::BitstreamWriter &Stream);
1615f757f3fSDimitry Andric   void writeObjCSelectorBlock(llvm::BitstreamWriter &Stream);
1625f757f3fSDimitry Andric   void writeGlobalVariableBlock(llvm::BitstreamWriter &Stream);
1635f757f3fSDimitry Andric   void writeGlobalFunctionBlock(llvm::BitstreamWriter &Stream);
1645f757f3fSDimitry Andric   void writeEnumConstantBlock(llvm::BitstreamWriter &Stream);
1655f757f3fSDimitry Andric   void writeTagBlock(llvm::BitstreamWriter &Stream);
1665f757f3fSDimitry Andric   void writeTypedefBlock(llvm::BitstreamWriter &Stream);
1675f757f3fSDimitry Andric 
1685f757f3fSDimitry Andric public:
1695f757f3fSDimitry Andric   Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
1705f757f3fSDimitry Andric       : ModuleName(std::string(ModuleName)), SourceFile(SF) {}
1715f757f3fSDimitry Andric 
1725f757f3fSDimitry Andric   void writeToStream(llvm::raw_ostream &OS);
1735f757f3fSDimitry Andric };
1745f757f3fSDimitry Andric 
1755f757f3fSDimitry Andric void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
1765f757f3fSDimitry Andric   llvm::SmallVector<char, 0> Buffer;
1775f757f3fSDimitry Andric 
1785f757f3fSDimitry Andric   {
1795f757f3fSDimitry Andric     llvm::BitstreamWriter Stream(Buffer);
1805f757f3fSDimitry Andric 
1815f757f3fSDimitry Andric     // Emit the signature.
1825f757f3fSDimitry Andric     for (unsigned char Byte : API_NOTES_SIGNATURE)
1835f757f3fSDimitry Andric       Stream.Emit(Byte, 8);
1845f757f3fSDimitry Andric 
1855f757f3fSDimitry Andric     // Emit the blocks.
1865f757f3fSDimitry Andric     writeBlockInfoBlock(Stream);
1875f757f3fSDimitry Andric     writeControlBlock(Stream);
1885f757f3fSDimitry Andric     writeIdentifierBlock(Stream);
189*0fca6ea1SDimitry Andric     writeContextBlock(Stream);
1905f757f3fSDimitry Andric     writeObjCPropertyBlock(Stream);
1915f757f3fSDimitry Andric     writeObjCMethodBlock(Stream);
192*0fca6ea1SDimitry Andric     writeCXXMethodBlock(Stream);
1935f757f3fSDimitry Andric     writeObjCSelectorBlock(Stream);
1945f757f3fSDimitry Andric     writeGlobalVariableBlock(Stream);
1955f757f3fSDimitry Andric     writeGlobalFunctionBlock(Stream);
1965f757f3fSDimitry Andric     writeEnumConstantBlock(Stream);
1975f757f3fSDimitry Andric     writeTagBlock(Stream);
1985f757f3fSDimitry Andric     writeTypedefBlock(Stream);
1995f757f3fSDimitry Andric   }
2005f757f3fSDimitry Andric 
2015f757f3fSDimitry Andric   OS.write(Buffer.data(), Buffer.size());
2025f757f3fSDimitry Andric   OS.flush();
2035f757f3fSDimitry Andric }
2045f757f3fSDimitry Andric 
2055f757f3fSDimitry Andric namespace {
2065f757f3fSDimitry Andric /// Record the name of a block.
2075f757f3fSDimitry Andric void emitBlockID(llvm::BitstreamWriter &Stream, unsigned ID,
2085f757f3fSDimitry Andric                  llvm::StringRef Name) {
2095f757f3fSDimitry Andric   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
2105f757f3fSDimitry Andric                     llvm::ArrayRef<unsigned>{ID});
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric   // Emit the block name if present.
2135f757f3fSDimitry Andric   if (Name.empty())
2145f757f3fSDimitry Andric     return;
2155f757f3fSDimitry Andric   Stream.EmitRecord(
2165f757f3fSDimitry Andric       llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
2175f757f3fSDimitry Andric       llvm::ArrayRef<unsigned char>(
2185f757f3fSDimitry Andric           const_cast<unsigned char *>(
2195f757f3fSDimitry Andric               reinterpret_cast<const unsigned char *>(Name.data())),
2205f757f3fSDimitry Andric           Name.size()));
2215f757f3fSDimitry Andric }
2225f757f3fSDimitry Andric 
2235f757f3fSDimitry Andric /// Record the name of a record within a block.
2245f757f3fSDimitry Andric void emitRecordID(llvm::BitstreamWriter &Stream, unsigned ID,
2255f757f3fSDimitry Andric                   llvm::StringRef Name) {
2265f757f3fSDimitry Andric   assert(ID < 256 && "can't fit record ID in next to name");
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric   llvm::SmallVector<unsigned char, 64> Buffer;
2295f757f3fSDimitry Andric   Buffer.resize(Name.size() + 1);
2305f757f3fSDimitry Andric   Buffer[0] = ID;
2315f757f3fSDimitry Andric   memcpy(Buffer.data() + 1, Name.data(), Name.size());
2325f757f3fSDimitry Andric 
2335f757f3fSDimitry Andric   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Buffer);
2345f757f3fSDimitry Andric }
2355f757f3fSDimitry Andric } // namespace
2365f757f3fSDimitry Andric 
2375f757f3fSDimitry Andric void APINotesWriter::Implementation::writeBlockInfoBlock(
2385f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
2395f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, llvm::bitc::BLOCKINFO_BLOCK_ID, 2);
2405f757f3fSDimitry Andric 
2415f757f3fSDimitry Andric #define BLOCK(Block) emitBlockID(Stream, Block##_ID, #Block)
2425f757f3fSDimitry Andric #define BLOCK_RECORD(NameSpace, Block)                                         \
2435f757f3fSDimitry Andric   emitRecordID(Stream, NameSpace::Block, #Block)
2445f757f3fSDimitry Andric   BLOCK(CONTROL_BLOCK);
2455f757f3fSDimitry Andric   BLOCK_RECORD(control_block, METADATA);
2465f757f3fSDimitry Andric   BLOCK_RECORD(control_block, MODULE_NAME);
2475f757f3fSDimitry Andric 
2485f757f3fSDimitry Andric   BLOCK(IDENTIFIER_BLOCK);
2495f757f3fSDimitry Andric   BLOCK_RECORD(identifier_block, IDENTIFIER_DATA);
2505f757f3fSDimitry Andric 
2515f757f3fSDimitry Andric   BLOCK(OBJC_CONTEXT_BLOCK);
252*0fca6ea1SDimitry Andric   BLOCK_RECORD(context_block, CONTEXT_ID_DATA);
2535f757f3fSDimitry Andric 
2545f757f3fSDimitry Andric   BLOCK(OBJC_PROPERTY_BLOCK);
2555f757f3fSDimitry Andric   BLOCK_RECORD(objc_property_block, OBJC_PROPERTY_DATA);
2565f757f3fSDimitry Andric 
2575f757f3fSDimitry Andric   BLOCK(OBJC_METHOD_BLOCK);
2585f757f3fSDimitry Andric   BLOCK_RECORD(objc_method_block, OBJC_METHOD_DATA);
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric   BLOCK(OBJC_SELECTOR_BLOCK);
2615f757f3fSDimitry Andric   BLOCK_RECORD(objc_selector_block, OBJC_SELECTOR_DATA);
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric   BLOCK(GLOBAL_VARIABLE_BLOCK);
2645f757f3fSDimitry Andric   BLOCK_RECORD(global_variable_block, GLOBAL_VARIABLE_DATA);
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric   BLOCK(GLOBAL_FUNCTION_BLOCK);
2675f757f3fSDimitry Andric   BLOCK_RECORD(global_function_block, GLOBAL_FUNCTION_DATA);
2685f757f3fSDimitry Andric #undef BLOCK_RECORD
2695f757f3fSDimitry Andric #undef BLOCK
2705f757f3fSDimitry Andric }
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric void APINotesWriter::Implementation::writeControlBlock(
2735f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
2745f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, CONTROL_BLOCK_ID, 3);
2755f757f3fSDimitry Andric 
2765f757f3fSDimitry Andric   control_block::MetadataLayout Metadata(Stream);
2775f757f3fSDimitry Andric   Metadata.emit(Scratch, VERSION_MAJOR, VERSION_MINOR);
2785f757f3fSDimitry Andric 
2795f757f3fSDimitry Andric   control_block::ModuleNameLayout ModuleName(Stream);
2805f757f3fSDimitry Andric   ModuleName.emit(Scratch, this->ModuleName);
2815f757f3fSDimitry Andric 
2825f757f3fSDimitry Andric   if (SourceFile) {
2835f757f3fSDimitry Andric     control_block::SourceFileLayout SourceFile(Stream);
2845f757f3fSDimitry Andric     SourceFile.emit(Scratch, this->SourceFile->getSize(),
2855f757f3fSDimitry Andric                     this->SourceFile->getModificationTime());
2865f757f3fSDimitry Andric   }
2875f757f3fSDimitry Andric }
2885f757f3fSDimitry Andric 
2895f757f3fSDimitry Andric namespace {
2905f757f3fSDimitry Andric /// Used to serialize the on-disk identifier table.
2915f757f3fSDimitry Andric class IdentifierTableInfo {
2925f757f3fSDimitry Andric public:
2935f757f3fSDimitry Andric   using key_type = StringRef;
2945f757f3fSDimitry Andric   using key_type_ref = key_type;
2955f757f3fSDimitry Andric   using data_type = IdentifierID;
2965f757f3fSDimitry Andric   using data_type_ref = const data_type &;
2975f757f3fSDimitry Andric   using hash_value_type = uint32_t;
2985f757f3fSDimitry Andric   using offset_type = unsigned;
2995f757f3fSDimitry Andric 
3005f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
3015f757f3fSDimitry Andric 
3025f757f3fSDimitry Andric   std::pair<unsigned, unsigned>
3035f757f3fSDimitry Andric   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
3045f757f3fSDimitry Andric     uint32_t KeyLength = Key.size();
3055f757f3fSDimitry Andric     uint32_t DataLength = sizeof(uint32_t);
3065f757f3fSDimitry Andric 
3075f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
3085f757f3fSDimitry Andric     writer.write<uint16_t>(KeyLength);
3095f757f3fSDimitry Andric     writer.write<uint16_t>(DataLength);
3105f757f3fSDimitry Andric     return {KeyLength, DataLength};
3115f757f3fSDimitry Andric   }
3125f757f3fSDimitry Andric 
3135f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
3145f757f3fSDimitry Andric 
3155f757f3fSDimitry Andric   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
3165f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
3175f757f3fSDimitry Andric     writer.write<uint32_t>(Data);
3185f757f3fSDimitry Andric   }
3195f757f3fSDimitry Andric };
3205f757f3fSDimitry Andric } // namespace
3215f757f3fSDimitry Andric 
3225f757f3fSDimitry Andric void APINotesWriter::Implementation::writeIdentifierBlock(
3235f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
3245f757f3fSDimitry Andric   llvm::BCBlockRAII restoreBlock(Stream, IDENTIFIER_BLOCK_ID, 3);
3255f757f3fSDimitry Andric 
3265f757f3fSDimitry Andric   if (IdentifierIDs.empty())
3275f757f3fSDimitry Andric     return;
3285f757f3fSDimitry Andric 
3295f757f3fSDimitry Andric   llvm::SmallString<4096> HashTableBlob;
3305f757f3fSDimitry Andric   uint32_t Offset;
3315f757f3fSDimitry Andric   {
3325f757f3fSDimitry Andric     llvm::OnDiskChainedHashTableGenerator<IdentifierTableInfo> Generator;
3335f757f3fSDimitry Andric     for (auto &II : IdentifierIDs)
3345f757f3fSDimitry Andric       Generator.insert(II.first(), II.second);
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric     llvm::raw_svector_ostream BlobStream(HashTableBlob);
3375f757f3fSDimitry Andric     // Make sure that no bucket is at offset 0
3385f757f3fSDimitry Andric     llvm::support::endian::write<uint32_t>(BlobStream, 0,
3395f757f3fSDimitry Andric                                            llvm::endianness::little);
3405f757f3fSDimitry Andric     Offset = Generator.Emit(BlobStream);
3415f757f3fSDimitry Andric   }
3425f757f3fSDimitry Andric 
3435f757f3fSDimitry Andric   identifier_block::IdentifierDataLayout IdentifierData(Stream);
3445f757f3fSDimitry Andric   IdentifierData.emit(Scratch, Offset, HashTableBlob);
3455f757f3fSDimitry Andric }
3465f757f3fSDimitry Andric 
3475f757f3fSDimitry Andric namespace {
3485f757f3fSDimitry Andric /// Used to serialize the on-disk Objective-C context table.
349*0fca6ea1SDimitry Andric class ContextIDTableInfo {
3505f757f3fSDimitry Andric public:
3515f757f3fSDimitry Andric   using key_type = ContextTableKey;
3525f757f3fSDimitry Andric   using key_type_ref = key_type;
3535f757f3fSDimitry Andric   using data_type = unsigned;
3545f757f3fSDimitry Andric   using data_type_ref = const data_type &;
3555f757f3fSDimitry Andric   using hash_value_type = size_t;
3565f757f3fSDimitry Andric   using offset_type = unsigned;
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
3595f757f3fSDimitry Andric     return static_cast<size_t>(Key.hashValue());
3605f757f3fSDimitry Andric   }
3615f757f3fSDimitry Andric 
3625f757f3fSDimitry Andric   std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &OS, key_type_ref,
3635f757f3fSDimitry Andric                                                   data_type_ref) {
3645f757f3fSDimitry Andric     uint32_t KeyLength = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
3655f757f3fSDimitry Andric     uint32_t DataLength = sizeof(uint32_t);
3665f757f3fSDimitry Andric 
3675f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
3685f757f3fSDimitry Andric     writer.write<uint16_t>(KeyLength);
3695f757f3fSDimitry Andric     writer.write<uint16_t>(DataLength);
3705f757f3fSDimitry Andric     return {KeyLength, DataLength};
3715f757f3fSDimitry Andric   }
3725f757f3fSDimitry Andric 
3735f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
3745f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
3755f757f3fSDimitry Andric     writer.write<uint32_t>(Key.parentContextID);
3765f757f3fSDimitry Andric     writer.write<uint8_t>(Key.contextKind);
3775f757f3fSDimitry Andric     writer.write<uint32_t>(Key.contextID);
3785f757f3fSDimitry Andric   }
3795f757f3fSDimitry Andric 
3805f757f3fSDimitry Andric   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
3815f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
3825f757f3fSDimitry Andric     writer.write<uint32_t>(Data);
3835f757f3fSDimitry Andric   }
3845f757f3fSDimitry Andric };
3855f757f3fSDimitry Andric 
3865f757f3fSDimitry Andric /// Localized helper to make a type dependent, thwarting template argument
3875f757f3fSDimitry Andric /// deduction.
3885f757f3fSDimitry Andric template <typename T> struct MakeDependent { typedef T Type; };
3895f757f3fSDimitry Andric 
3905f757f3fSDimitry Andric /// Retrieve the serialized size of the given VersionTuple, for use in
3915f757f3fSDimitry Andric /// on-disk hash tables.
3925f757f3fSDimitry Andric unsigned getVersionTupleSize(const VersionTuple &VT) {
3935f757f3fSDimitry Andric   unsigned size = sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
3945f757f3fSDimitry Andric   if (VT.getMinor())
3955f757f3fSDimitry Andric     size += sizeof(uint32_t);
3965f757f3fSDimitry Andric   if (VT.getSubminor())
3975f757f3fSDimitry Andric     size += sizeof(uint32_t);
3985f757f3fSDimitry Andric   if (VT.getBuild())
3995f757f3fSDimitry Andric     size += sizeof(uint32_t);
4005f757f3fSDimitry Andric   return size;
4015f757f3fSDimitry Andric }
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric /// Determine the size of an array of versioned information,
4045f757f3fSDimitry Andric template <typename T>
4055f757f3fSDimitry Andric unsigned getVersionedInfoSize(
4065f757f3fSDimitry Andric     const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple, T>> &VI,
4075f757f3fSDimitry Andric     llvm::function_ref<unsigned(const typename MakeDependent<T>::Type &)>
4085f757f3fSDimitry Andric         getInfoSize) {
4095f757f3fSDimitry Andric   unsigned result = sizeof(uint16_t); // # of elements
4105f757f3fSDimitry Andric   for (const auto &E : VI) {
4115f757f3fSDimitry Andric     result += getVersionTupleSize(E.first);
4125f757f3fSDimitry Andric     result += getInfoSize(E.second);
4135f757f3fSDimitry Andric   }
4145f757f3fSDimitry Andric   return result;
4155f757f3fSDimitry Andric }
4165f757f3fSDimitry Andric 
4175f757f3fSDimitry Andric /// Emit a serialized representation of a version tuple.
4185f757f3fSDimitry Andric void emitVersionTuple(raw_ostream &OS, const VersionTuple &VT) {
4195f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
4205f757f3fSDimitry Andric 
4215f757f3fSDimitry Andric   // First byte contains the number of components beyond the 'major' component.
4225f757f3fSDimitry Andric   uint8_t descriptor;
4235f757f3fSDimitry Andric   if (VT.getBuild())
4245f757f3fSDimitry Andric     descriptor = 3;
4255f757f3fSDimitry Andric   else if (VT.getSubminor())
4265f757f3fSDimitry Andric     descriptor = 2;
4275f757f3fSDimitry Andric   else if (VT.getMinor())
4285f757f3fSDimitry Andric     descriptor = 1;
4295f757f3fSDimitry Andric   else
4305f757f3fSDimitry Andric     descriptor = 0;
4315f757f3fSDimitry Andric   writer.write<uint8_t>(descriptor);
4325f757f3fSDimitry Andric 
4335f757f3fSDimitry Andric   // Write the components.
4345f757f3fSDimitry Andric   writer.write<uint32_t>(VT.getMajor());
4355f757f3fSDimitry Andric   if (auto minor = VT.getMinor())
4365f757f3fSDimitry Andric     writer.write<uint32_t>(*minor);
4375f757f3fSDimitry Andric   if (auto subminor = VT.getSubminor())
4385f757f3fSDimitry Andric     writer.write<uint32_t>(*subminor);
4395f757f3fSDimitry Andric   if (auto build = VT.getBuild())
4405f757f3fSDimitry Andric     writer.write<uint32_t>(*build);
4415f757f3fSDimitry Andric }
4425f757f3fSDimitry Andric 
4435f757f3fSDimitry Andric /// Emit versioned information.
4445f757f3fSDimitry Andric template <typename T>
4455f757f3fSDimitry Andric void emitVersionedInfo(
4465f757f3fSDimitry Andric     raw_ostream &OS, llvm::SmallVectorImpl<std::pair<VersionTuple, T>> &VI,
4475f757f3fSDimitry Andric     llvm::function_ref<void(raw_ostream &,
4485f757f3fSDimitry Andric                             const typename MakeDependent<T>::Type &)>
4495f757f3fSDimitry Andric         emitInfo) {
4505f757f3fSDimitry Andric   std::sort(VI.begin(), VI.end(),
4515f757f3fSDimitry Andric             [](const std::pair<VersionTuple, T> &LHS,
4525f757f3fSDimitry Andric                const std::pair<VersionTuple, T> &RHS) -> bool {
453*0fca6ea1SDimitry Andric               assert((&LHS == &RHS || LHS.first != RHS.first) &&
4545f757f3fSDimitry Andric                      "two entries for the same version");
4555f757f3fSDimitry Andric               return LHS.first < RHS.first;
4565f757f3fSDimitry Andric             });
4575f757f3fSDimitry Andric 
4585f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
4595f757f3fSDimitry Andric   writer.write<uint16_t>(VI.size());
4605f757f3fSDimitry Andric   for (const auto &E : VI) {
4615f757f3fSDimitry Andric     emitVersionTuple(OS, E.first);
4625f757f3fSDimitry Andric     emitInfo(OS, E.second);
4635f757f3fSDimitry Andric   }
4645f757f3fSDimitry Andric }
4655f757f3fSDimitry Andric 
4665f757f3fSDimitry Andric /// On-disk hash table info key base for handling versioned data.
4675f757f3fSDimitry Andric template <typename Derived, typename KeyType, typename UnversionedDataType>
4685f757f3fSDimitry Andric class VersionedTableInfo {
4695f757f3fSDimitry Andric   Derived &asDerived() { return *static_cast<Derived *>(this); }
4705f757f3fSDimitry Andric 
4715f757f3fSDimitry Andric   const Derived &asDerived() const {
4725f757f3fSDimitry Andric     return *static_cast<const Derived *>(this);
4735f757f3fSDimitry Andric   }
4745f757f3fSDimitry Andric 
4755f757f3fSDimitry Andric public:
4765f757f3fSDimitry Andric   using key_type = KeyType;
4775f757f3fSDimitry Andric   using key_type_ref = key_type;
4785f757f3fSDimitry Andric   using data_type =
4795f757f3fSDimitry Andric       llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
4805f757f3fSDimitry Andric   using data_type_ref = data_type &;
4815f757f3fSDimitry Andric   using hash_value_type = size_t;
4825f757f3fSDimitry Andric   using offset_type = unsigned;
4835f757f3fSDimitry Andric 
4845f757f3fSDimitry Andric   std::pair<unsigned, unsigned>
4855f757f3fSDimitry Andric   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref Data) {
4865f757f3fSDimitry Andric     uint32_t KeyLength = asDerived().getKeyLength(Key);
4875f757f3fSDimitry Andric     uint32_t DataLength =
4885f757f3fSDimitry Andric         getVersionedInfoSize(Data, [this](const UnversionedDataType &UI) {
4895f757f3fSDimitry Andric           return asDerived().getUnversionedInfoSize(UI);
4905f757f3fSDimitry Andric         });
4915f757f3fSDimitry Andric 
4925f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
4935f757f3fSDimitry Andric     writer.write<uint16_t>(KeyLength);
4945f757f3fSDimitry Andric     writer.write<uint16_t>(DataLength);
4955f757f3fSDimitry Andric     return {KeyLength, DataLength};
4965f757f3fSDimitry Andric   }
4975f757f3fSDimitry Andric 
4985f757f3fSDimitry Andric   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
4995f757f3fSDimitry Andric     emitVersionedInfo(
5005f757f3fSDimitry Andric         OS, Data, [this](llvm::raw_ostream &OS, const UnversionedDataType &UI) {
5015f757f3fSDimitry Andric           asDerived().emitUnversionedInfo(OS, UI);
5025f757f3fSDimitry Andric         });
5035f757f3fSDimitry Andric   }
5045f757f3fSDimitry Andric };
5055f757f3fSDimitry Andric 
5065f757f3fSDimitry Andric /// Emit a serialized representation of the common entity information.
5075f757f3fSDimitry Andric void emitCommonEntityInfo(raw_ostream &OS, const CommonEntityInfo &CEI) {
5085f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
5095f757f3fSDimitry Andric 
5105f757f3fSDimitry Andric   uint8_t payload = 0;
5115f757f3fSDimitry Andric   if (auto swiftPrivate = CEI.isSwiftPrivate()) {
5125f757f3fSDimitry Andric     payload |= 0x01;
5135f757f3fSDimitry Andric     if (*swiftPrivate)
5145f757f3fSDimitry Andric       payload |= 0x02;
5155f757f3fSDimitry Andric   }
5165f757f3fSDimitry Andric   payload <<= 1;
5175f757f3fSDimitry Andric   payload |= CEI.Unavailable;
5185f757f3fSDimitry Andric   payload <<= 1;
5195f757f3fSDimitry Andric   payload |= CEI.UnavailableInSwift;
5205f757f3fSDimitry Andric 
5215f757f3fSDimitry Andric   writer.write<uint8_t>(payload);
5225f757f3fSDimitry Andric 
5235f757f3fSDimitry Andric   writer.write<uint16_t>(CEI.UnavailableMsg.size());
5245f757f3fSDimitry Andric   OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
5255f757f3fSDimitry Andric 
5265f757f3fSDimitry Andric   writer.write<uint16_t>(CEI.SwiftName.size());
5275f757f3fSDimitry Andric   OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
5285f757f3fSDimitry Andric }
5295f757f3fSDimitry Andric 
5305f757f3fSDimitry Andric /// Retrieve the serialized size of the given CommonEntityInfo, for use in
5315f757f3fSDimitry Andric /// on-disk hash tables.
5325f757f3fSDimitry Andric unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
5335f757f3fSDimitry Andric   return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
5345f757f3fSDimitry Andric }
5355f757f3fSDimitry Andric 
5365f757f3fSDimitry Andric // Retrieve the serialized size of the given CommonTypeInfo, for use
5375f757f3fSDimitry Andric // in on-disk hash tables.
5385f757f3fSDimitry Andric unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
5395f757f3fSDimitry Andric   return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
5405f757f3fSDimitry Andric          (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) +
5415f757f3fSDimitry Andric          getCommonEntityInfoSize(CTI);
5425f757f3fSDimitry Andric }
5435f757f3fSDimitry Andric 
5445f757f3fSDimitry Andric /// Emit a serialized representation of the common type information.
5455f757f3fSDimitry Andric void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
5465f757f3fSDimitry Andric   emitCommonEntityInfo(OS, CTI);
5475f757f3fSDimitry Andric 
5485f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
5495f757f3fSDimitry Andric   if (auto swiftBridge = CTI.getSwiftBridge()) {
5505f757f3fSDimitry Andric     writer.write<uint16_t>(swiftBridge->size() + 1);
5515f757f3fSDimitry Andric     OS.write(swiftBridge->c_str(), swiftBridge->size());
5525f757f3fSDimitry Andric   } else {
5535f757f3fSDimitry Andric     writer.write<uint16_t>(0);
5545f757f3fSDimitry Andric   }
5555f757f3fSDimitry Andric   if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
5565f757f3fSDimitry Andric     writer.write<uint16_t>(nsErrorDomain->size() + 1);
5575f757f3fSDimitry Andric     OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
5585f757f3fSDimitry Andric   } else {
5595f757f3fSDimitry Andric     writer.write<uint16_t>(0);
5605f757f3fSDimitry Andric   }
5615f757f3fSDimitry Andric }
5625f757f3fSDimitry Andric 
5635f757f3fSDimitry Andric /// Used to serialize the on-disk Objective-C property table.
564*0fca6ea1SDimitry Andric class ContextInfoTableInfo
565*0fca6ea1SDimitry Andric     : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
5665f757f3fSDimitry Andric public:
5675f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
5685f757f3fSDimitry Andric 
5695f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
5705f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
5715f757f3fSDimitry Andric     writer.write<uint32_t>(Key);
5725f757f3fSDimitry Andric   }
5735f757f3fSDimitry Andric 
5745f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
5755f757f3fSDimitry Andric     return static_cast<size_t>(llvm::hash_value(Key));
5765f757f3fSDimitry Andric   }
5775f757f3fSDimitry Andric 
578*0fca6ea1SDimitry Andric   unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
5795f757f3fSDimitry Andric     return getCommonTypeInfoSize(OCI) + 1;
5805f757f3fSDimitry Andric   }
5815f757f3fSDimitry Andric 
582*0fca6ea1SDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
5835f757f3fSDimitry Andric     emitCommonTypeInfo(OS, OCI);
5845f757f3fSDimitry Andric 
5855f757f3fSDimitry Andric     uint8_t payload = 0;
5865f757f3fSDimitry Andric     if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
5875f757f3fSDimitry Andric       payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
5885f757f3fSDimitry Andric     payload <<= 2;
5895f757f3fSDimitry Andric     if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
5905f757f3fSDimitry Andric       payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
5915f757f3fSDimitry Andric     payload <<= 3;
5925f757f3fSDimitry Andric     if (auto nullable = OCI.getDefaultNullability())
5935f757f3fSDimitry Andric       payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
5945f757f3fSDimitry Andric     payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
5955f757f3fSDimitry Andric 
5965f757f3fSDimitry Andric     OS << payload;
5975f757f3fSDimitry Andric   }
5985f757f3fSDimitry Andric };
5995f757f3fSDimitry Andric } // namespace
6005f757f3fSDimitry Andric 
601*0fca6ea1SDimitry Andric void APINotesWriter::Implementation::writeContextBlock(
6025f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
6035f757f3fSDimitry Andric   llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
6045f757f3fSDimitry Andric 
605*0fca6ea1SDimitry Andric   if (Contexts.empty())
6065f757f3fSDimitry Andric     return;
6075f757f3fSDimitry Andric 
6085f757f3fSDimitry Andric   {
6095f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
6105f757f3fSDimitry Andric     uint32_t Offset;
6115f757f3fSDimitry Andric     {
612*0fca6ea1SDimitry Andric       llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
613*0fca6ea1SDimitry Andric       for (auto &OC : Contexts)
6145f757f3fSDimitry Andric         Generator.insert(OC.first, OC.second.first);
6155f757f3fSDimitry Andric 
6165f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
6175f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
6185f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
6195f757f3fSDimitry Andric                                              llvm::endianness::little);
6205f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
6215f757f3fSDimitry Andric     }
6225f757f3fSDimitry Andric 
623*0fca6ea1SDimitry Andric     context_block::ContextIDLayout ContextID(Stream);
624*0fca6ea1SDimitry Andric     ContextID.emit(Scratch, Offset, HashTableBlob);
6255f757f3fSDimitry Andric   }
6265f757f3fSDimitry Andric 
6275f757f3fSDimitry Andric   {
6285f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
6295f757f3fSDimitry Andric     uint32_t Offset;
6305f757f3fSDimitry Andric     {
631*0fca6ea1SDimitry Andric       llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
632*0fca6ea1SDimitry Andric       for (auto &OC : Contexts)
6335f757f3fSDimitry Andric         Generator.insert(OC.second.first, OC.second.second);
6345f757f3fSDimitry Andric 
6355f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
6365f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
6375f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
6385f757f3fSDimitry Andric                                              llvm::endianness::little);
6395f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
6405f757f3fSDimitry Andric     }
6415f757f3fSDimitry Andric 
642*0fca6ea1SDimitry Andric     context_block::ContextInfoLayout ContextInfo(Stream);
643*0fca6ea1SDimitry Andric     ContextInfo.emit(Scratch, Offset, HashTableBlob);
6445f757f3fSDimitry Andric   }
6455f757f3fSDimitry Andric }
6465f757f3fSDimitry Andric 
6475f757f3fSDimitry Andric namespace {
6485f757f3fSDimitry Andric /// Retrieve the serialized size of the given VariableInfo, for use in
6495f757f3fSDimitry Andric /// on-disk hash tables.
6505f757f3fSDimitry Andric unsigned getVariableInfoSize(const VariableInfo &VI) {
6515f757f3fSDimitry Andric   return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
6525f757f3fSDimitry Andric }
6535f757f3fSDimitry Andric 
6545f757f3fSDimitry Andric /// Emit a serialized representation of the variable information.
6555f757f3fSDimitry Andric void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
6565f757f3fSDimitry Andric   emitCommonEntityInfo(OS, VI);
6575f757f3fSDimitry Andric 
6585f757f3fSDimitry Andric   uint8_t bytes[2] = {0, 0};
6595f757f3fSDimitry Andric   if (auto nullable = VI.getNullability()) {
6605f757f3fSDimitry Andric     bytes[0] = 1;
6615f757f3fSDimitry Andric     bytes[1] = static_cast<uint8_t>(*nullable);
6625f757f3fSDimitry Andric   } else {
6635f757f3fSDimitry Andric     // Nothing to do.
6645f757f3fSDimitry Andric   }
6655f757f3fSDimitry Andric 
6665f757f3fSDimitry Andric   OS.write(reinterpret_cast<const char *>(bytes), 2);
6675f757f3fSDimitry Andric 
6685f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
6695f757f3fSDimitry Andric   writer.write<uint16_t>(VI.getType().size());
6705f757f3fSDimitry Andric   OS.write(VI.getType().data(), VI.getType().size());
6715f757f3fSDimitry Andric }
6725f757f3fSDimitry Andric 
6735f757f3fSDimitry Andric /// Used to serialize the on-disk Objective-C property table.
6745f757f3fSDimitry Andric class ObjCPropertyTableInfo
6755f757f3fSDimitry Andric     : public VersionedTableInfo<ObjCPropertyTableInfo,
6765f757f3fSDimitry Andric                                 std::tuple<unsigned, unsigned, char>,
6775f757f3fSDimitry Andric                                 ObjCPropertyInfo> {
6785f757f3fSDimitry Andric public:
6795f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) {
6805f757f3fSDimitry Andric     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
6815f757f3fSDimitry Andric   }
6825f757f3fSDimitry Andric 
6835f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
6845f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
6855f757f3fSDimitry Andric     writer.write<uint32_t>(std::get<0>(Key));
6865f757f3fSDimitry Andric     writer.write<uint32_t>(std::get<1>(Key));
6875f757f3fSDimitry Andric     writer.write<uint8_t>(std::get<2>(Key));
6885f757f3fSDimitry Andric   }
6895f757f3fSDimitry Andric 
6905f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
6915f757f3fSDimitry Andric     return static_cast<size_t>(llvm::hash_value(Key));
6925f757f3fSDimitry Andric   }
6935f757f3fSDimitry Andric 
6945f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
6955f757f3fSDimitry Andric     return getVariableInfoSize(OPI) + 1;
6965f757f3fSDimitry Andric   }
6975f757f3fSDimitry Andric 
6985f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
6995f757f3fSDimitry Andric     emitVariableInfo(OS, OPI);
7005f757f3fSDimitry Andric 
7015f757f3fSDimitry Andric     uint8_t flags = 0;
7025f757f3fSDimitry Andric     if (auto value = OPI.getSwiftImportAsAccessors()) {
7035f757f3fSDimitry Andric       flags |= 1 << 0;
7045f757f3fSDimitry Andric       flags |= value.value() << 1;
7055f757f3fSDimitry Andric     }
7065f757f3fSDimitry Andric     OS << flags;
7075f757f3fSDimitry Andric   }
7085f757f3fSDimitry Andric };
7095f757f3fSDimitry Andric } // namespace
7105f757f3fSDimitry Andric 
7115f757f3fSDimitry Andric void APINotesWriter::Implementation::writeObjCPropertyBlock(
7125f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
7135f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
7145f757f3fSDimitry Andric 
7155f757f3fSDimitry Andric   if (ObjCProperties.empty())
7165f757f3fSDimitry Andric     return;
7175f757f3fSDimitry Andric 
7185f757f3fSDimitry Andric   {
7195f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
7205f757f3fSDimitry Andric     uint32_t Offset;
7215f757f3fSDimitry Andric     {
7225f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
7235f757f3fSDimitry Andric       for (auto &OP : ObjCProperties)
7245f757f3fSDimitry Andric         Generator.insert(OP.first, OP.second);
7255f757f3fSDimitry Andric 
7265f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
7275f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
7285f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
7295f757f3fSDimitry Andric                                              llvm::endianness::little);
7305f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
7315f757f3fSDimitry Andric     }
7325f757f3fSDimitry Andric 
7335f757f3fSDimitry Andric     objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
7345f757f3fSDimitry Andric     ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
7355f757f3fSDimitry Andric   }
7365f757f3fSDimitry Andric }
7375f757f3fSDimitry Andric 
7385f757f3fSDimitry Andric namespace {
7395f757f3fSDimitry Andric unsigned getFunctionInfoSize(const FunctionInfo &);
7405f757f3fSDimitry Andric void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
7415f757f3fSDimitry Andric 
7425f757f3fSDimitry Andric /// Used to serialize the on-disk Objective-C method table.
7435f757f3fSDimitry Andric class ObjCMethodTableInfo
7445f757f3fSDimitry Andric     : public VersionedTableInfo<ObjCMethodTableInfo,
7455f757f3fSDimitry Andric                                 std::tuple<unsigned, unsigned, char>,
7465f757f3fSDimitry Andric                                 ObjCMethodInfo> {
7475f757f3fSDimitry Andric public:
7485f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) {
7495f757f3fSDimitry Andric     return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
7505f757f3fSDimitry Andric   }
7515f757f3fSDimitry Andric 
7525f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
7535f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
7545f757f3fSDimitry Andric     writer.write<uint32_t>(std::get<0>(Key));
7555f757f3fSDimitry Andric     writer.write<uint32_t>(std::get<1>(Key));
7565f757f3fSDimitry Andric     writer.write<uint8_t>(std::get<2>(Key));
7575f757f3fSDimitry Andric   }
7585f757f3fSDimitry Andric 
7595f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref key) {
7605f757f3fSDimitry Andric     return static_cast<size_t>(llvm::hash_value(key));
7615f757f3fSDimitry Andric   }
7625f757f3fSDimitry Andric 
7635f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
7645f757f3fSDimitry Andric     return getFunctionInfoSize(OMI) + 1;
7655f757f3fSDimitry Andric   }
7665f757f3fSDimitry Andric 
7675f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
7685f757f3fSDimitry Andric     uint8_t flags = 0;
7695f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
7705f757f3fSDimitry Andric     flags = (flags << 1) | OMI.DesignatedInit;
7715f757f3fSDimitry Andric     flags = (flags << 1) | OMI.RequiredInit;
7725f757f3fSDimitry Andric     writer.write<uint8_t>(flags);
7735f757f3fSDimitry Andric 
7745f757f3fSDimitry Andric     emitFunctionInfo(OS, OMI);
7755f757f3fSDimitry Andric   }
7765f757f3fSDimitry Andric };
777*0fca6ea1SDimitry Andric 
778*0fca6ea1SDimitry Andric /// Used to serialize the on-disk C++ method table.
779*0fca6ea1SDimitry Andric class CXXMethodTableInfo
780*0fca6ea1SDimitry Andric     : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
781*0fca6ea1SDimitry Andric                                 CXXMethodInfo> {
782*0fca6ea1SDimitry Andric public:
783*0fca6ea1SDimitry Andric   unsigned getKeyLength(key_type_ref) {
784*0fca6ea1SDimitry Andric     return sizeof(uint32_t) + sizeof(uint32_t);
785*0fca6ea1SDimitry Andric   }
786*0fca6ea1SDimitry Andric 
787*0fca6ea1SDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
788*0fca6ea1SDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
789*0fca6ea1SDimitry Andric     writer.write<uint32_t>(Key.parentContextID);
790*0fca6ea1SDimitry Andric     writer.write<uint32_t>(Key.nameID);
791*0fca6ea1SDimitry Andric   }
792*0fca6ea1SDimitry Andric 
793*0fca6ea1SDimitry Andric   hash_value_type ComputeHash(key_type_ref key) {
794*0fca6ea1SDimitry Andric     return static_cast<size_t>(key.hashValue());
795*0fca6ea1SDimitry Andric   }
796*0fca6ea1SDimitry Andric 
797*0fca6ea1SDimitry Andric   unsigned getUnversionedInfoSize(const CXXMethodInfo &OMI) {
798*0fca6ea1SDimitry Andric     return getFunctionInfoSize(OMI);
799*0fca6ea1SDimitry Andric   }
800*0fca6ea1SDimitry Andric 
801*0fca6ea1SDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &OMI) {
802*0fca6ea1SDimitry Andric     emitFunctionInfo(OS, OMI);
803*0fca6ea1SDimitry Andric   }
804*0fca6ea1SDimitry Andric };
8055f757f3fSDimitry Andric } // namespace
8065f757f3fSDimitry Andric 
8075f757f3fSDimitry Andric void APINotesWriter::Implementation::writeObjCMethodBlock(
8085f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
8095f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
8105f757f3fSDimitry Andric 
8115f757f3fSDimitry Andric   if (ObjCMethods.empty())
8125f757f3fSDimitry Andric     return;
8135f757f3fSDimitry Andric 
8145f757f3fSDimitry Andric   {
8155f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
8165f757f3fSDimitry Andric     uint32_t Offset;
8175f757f3fSDimitry Andric     {
8185f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
8195f757f3fSDimitry Andric       for (auto &OM : ObjCMethods)
8205f757f3fSDimitry Andric         Generator.insert(OM.first, OM.second);
8215f757f3fSDimitry Andric 
8225f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
8235f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
8245f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
8255f757f3fSDimitry Andric                                              llvm::endianness::little);
8265f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
8275f757f3fSDimitry Andric     }
8285f757f3fSDimitry Andric 
8295f757f3fSDimitry Andric     objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
8305f757f3fSDimitry Andric     ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
8315f757f3fSDimitry Andric   }
8325f757f3fSDimitry Andric }
8335f757f3fSDimitry Andric 
834*0fca6ea1SDimitry Andric void APINotesWriter::Implementation::writeCXXMethodBlock(
835*0fca6ea1SDimitry Andric     llvm::BitstreamWriter &Stream) {
836*0fca6ea1SDimitry Andric   llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
837*0fca6ea1SDimitry Andric 
838*0fca6ea1SDimitry Andric   if (CXXMethods.empty())
839*0fca6ea1SDimitry Andric     return;
840*0fca6ea1SDimitry Andric 
841*0fca6ea1SDimitry Andric   {
842*0fca6ea1SDimitry Andric     llvm::SmallString<4096> HashTableBlob;
843*0fca6ea1SDimitry Andric     uint32_t Offset;
844*0fca6ea1SDimitry Andric     {
845*0fca6ea1SDimitry Andric       llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
846*0fca6ea1SDimitry Andric       for (auto &MD : CXXMethods)
847*0fca6ea1SDimitry Andric         Generator.insert(MD.first, MD.second);
848*0fca6ea1SDimitry Andric 
849*0fca6ea1SDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
850*0fca6ea1SDimitry Andric       // Make sure that no bucket is at offset 0
851*0fca6ea1SDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
852*0fca6ea1SDimitry Andric                                              llvm::endianness::little);
853*0fca6ea1SDimitry Andric       Offset = Generator.Emit(BlobStream);
854*0fca6ea1SDimitry Andric     }
855*0fca6ea1SDimitry Andric 
856*0fca6ea1SDimitry Andric     cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
857*0fca6ea1SDimitry Andric     CXXMethodData.emit(Scratch, Offset, HashTableBlob);
858*0fca6ea1SDimitry Andric   }
859*0fca6ea1SDimitry Andric }
860*0fca6ea1SDimitry Andric 
8615f757f3fSDimitry Andric namespace {
8625f757f3fSDimitry Andric /// Used to serialize the on-disk Objective-C selector table.
8635f757f3fSDimitry Andric class ObjCSelectorTableInfo {
8645f757f3fSDimitry Andric public:
8655f757f3fSDimitry Andric   using key_type = StoredObjCSelector;
8665f757f3fSDimitry Andric   using key_type_ref = const key_type &;
8675f757f3fSDimitry Andric   using data_type = SelectorID;
8685f757f3fSDimitry Andric   using data_type_ref = data_type;
8695f757f3fSDimitry Andric   using hash_value_type = unsigned;
8705f757f3fSDimitry Andric   using offset_type = unsigned;
8715f757f3fSDimitry Andric 
8725f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
8735f757f3fSDimitry Andric     return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
8745f757f3fSDimitry Andric   }
8755f757f3fSDimitry Andric 
8765f757f3fSDimitry Andric   std::pair<unsigned, unsigned>
8775f757f3fSDimitry Andric   EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
8785f757f3fSDimitry Andric     uint32_t KeyLength =
8795f757f3fSDimitry Andric         sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
8805f757f3fSDimitry Andric     uint32_t DataLength = sizeof(uint32_t);
8815f757f3fSDimitry Andric 
8825f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
8835f757f3fSDimitry Andric     writer.write<uint16_t>(KeyLength);
8845f757f3fSDimitry Andric     writer.write<uint16_t>(DataLength);
8855f757f3fSDimitry Andric     return {KeyLength, DataLength};
8865f757f3fSDimitry Andric   }
8875f757f3fSDimitry Andric 
8885f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
8895f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
8905f757f3fSDimitry Andric     writer.write<uint16_t>(Key.NumArgs);
8915f757f3fSDimitry Andric     for (auto Identifier : Key.Identifiers)
8925f757f3fSDimitry Andric       writer.write<uint32_t>(Identifier);
8935f757f3fSDimitry Andric   }
8945f757f3fSDimitry Andric 
8955f757f3fSDimitry Andric   void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
8965f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
8975f757f3fSDimitry Andric     writer.write<uint32_t>(Data);
8985f757f3fSDimitry Andric   }
8995f757f3fSDimitry Andric };
9005f757f3fSDimitry Andric } // namespace
9015f757f3fSDimitry Andric 
9025f757f3fSDimitry Andric void APINotesWriter::Implementation::writeObjCSelectorBlock(
9035f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
9045f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
9055f757f3fSDimitry Andric 
9065f757f3fSDimitry Andric   if (SelectorIDs.empty())
9075f757f3fSDimitry Andric     return;
9085f757f3fSDimitry Andric 
9095f757f3fSDimitry Andric   {
9105f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
9115f757f3fSDimitry Andric     uint32_t Offset;
9125f757f3fSDimitry Andric     {
9135f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
9145f757f3fSDimitry Andric       for (auto &S : SelectorIDs)
9155f757f3fSDimitry Andric         Generator.insert(S.first, S.second);
9165f757f3fSDimitry Andric 
9175f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
9185f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
9195f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
9205f757f3fSDimitry Andric                                              llvm::endianness::little);
9215f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
9225f757f3fSDimitry Andric     }
9235f757f3fSDimitry Andric 
9245f757f3fSDimitry Andric     objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
9255f757f3fSDimitry Andric     ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
9265f757f3fSDimitry Andric   }
9275f757f3fSDimitry Andric }
9285f757f3fSDimitry Andric 
9295f757f3fSDimitry Andric namespace {
9305f757f3fSDimitry Andric /// Used to serialize the on-disk global variable table.
9315f757f3fSDimitry Andric class GlobalVariableTableInfo
932*0fca6ea1SDimitry Andric     : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,
9335f757f3fSDimitry Andric                                 GlobalVariableInfo> {
9345f757f3fSDimitry Andric public:
9355f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) {
936*0fca6ea1SDimitry Andric     return sizeof(uint32_t) + sizeof(uint32_t);
9375f757f3fSDimitry Andric   }
9385f757f3fSDimitry Andric 
9395f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
9405f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
9415f757f3fSDimitry Andric     writer.write<uint32_t>(Key.parentContextID);
942*0fca6ea1SDimitry Andric     writer.write<uint32_t>(Key.nameID);
9435f757f3fSDimitry Andric   }
9445f757f3fSDimitry Andric 
9455f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
9465f757f3fSDimitry Andric     return static_cast<size_t>(Key.hashValue());
9475f757f3fSDimitry Andric   }
9485f757f3fSDimitry Andric 
9495f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
9505f757f3fSDimitry Andric     return getVariableInfoSize(GVI);
9515f757f3fSDimitry Andric   }
9525f757f3fSDimitry Andric 
9535f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
9545f757f3fSDimitry Andric     emitVariableInfo(OS, GVI);
9555f757f3fSDimitry Andric   }
9565f757f3fSDimitry Andric };
9575f757f3fSDimitry Andric } // namespace
9585f757f3fSDimitry Andric 
9595f757f3fSDimitry Andric void APINotesWriter::Implementation::writeGlobalVariableBlock(
9605f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
9615f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
9625f757f3fSDimitry Andric 
9635f757f3fSDimitry Andric   if (GlobalVariables.empty())
9645f757f3fSDimitry Andric     return;
9655f757f3fSDimitry Andric 
9665f757f3fSDimitry Andric   {
9675f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
9685f757f3fSDimitry Andric     uint32_t Offset;
9695f757f3fSDimitry Andric     {
9705f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
9715f757f3fSDimitry Andric       for (auto &GV : GlobalVariables)
9725f757f3fSDimitry Andric         Generator.insert(GV.first, GV.second);
9735f757f3fSDimitry Andric 
9745f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
9755f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
9765f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
9775f757f3fSDimitry Andric                                              llvm::endianness::little);
9785f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
9795f757f3fSDimitry Andric     }
9805f757f3fSDimitry Andric 
9815f757f3fSDimitry Andric     global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
9825f757f3fSDimitry Andric     GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
9835f757f3fSDimitry Andric   }
9845f757f3fSDimitry Andric }
9855f757f3fSDimitry Andric 
9865f757f3fSDimitry Andric namespace {
9875f757f3fSDimitry Andric unsigned getParamInfoSize(const ParamInfo &PI) {
9885f757f3fSDimitry Andric   return getVariableInfoSize(PI) + 1;
9895f757f3fSDimitry Andric }
9905f757f3fSDimitry Andric 
9915f757f3fSDimitry Andric void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
9925f757f3fSDimitry Andric   emitVariableInfo(OS, PI);
9935f757f3fSDimitry Andric 
9945f757f3fSDimitry Andric   uint8_t flags = 0;
9955f757f3fSDimitry Andric   if (auto noescape = PI.isNoEscape()) {
9965f757f3fSDimitry Andric     flags |= 0x01;
9975f757f3fSDimitry Andric     if (*noescape)
9985f757f3fSDimitry Andric       flags |= 0x02;
9995f757f3fSDimitry Andric   }
10005f757f3fSDimitry Andric   flags <<= 3;
10015f757f3fSDimitry Andric   if (auto RCC = PI.getRetainCountConvention())
10025f757f3fSDimitry Andric     flags |= static_cast<uint8_t>(RCC.value()) + 1;
10035f757f3fSDimitry Andric 
10045f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
10055f757f3fSDimitry Andric   writer.write<uint8_t>(flags);
10065f757f3fSDimitry Andric }
10075f757f3fSDimitry Andric 
10085f757f3fSDimitry Andric /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
10095f757f3fSDimitry Andric /// hash tables.
10105f757f3fSDimitry Andric unsigned getFunctionInfoSize(const FunctionInfo &FI) {
10115f757f3fSDimitry Andric   unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
10125f757f3fSDimitry Andric   size += sizeof(uint16_t);
10135f757f3fSDimitry Andric   for (const auto &P : FI.Params)
10145f757f3fSDimitry Andric     size += getParamInfoSize(P);
10155f757f3fSDimitry Andric   size += sizeof(uint16_t) + FI.ResultType.size();
10165f757f3fSDimitry Andric   return size;
10175f757f3fSDimitry Andric }
10185f757f3fSDimitry Andric 
10195f757f3fSDimitry Andric /// Emit a serialized representation of the function information.
10205f757f3fSDimitry Andric void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
10215f757f3fSDimitry Andric   emitCommonEntityInfo(OS, FI);
10225f757f3fSDimitry Andric 
10235f757f3fSDimitry Andric   uint8_t flags = 0;
10245f757f3fSDimitry Andric   flags |= FI.NullabilityAudited;
10255f757f3fSDimitry Andric   flags <<= 3;
10265f757f3fSDimitry Andric   if (auto RCC = FI.getRetainCountConvention())
10275f757f3fSDimitry Andric     flags |= static_cast<uint8_t>(RCC.value()) + 1;
10285f757f3fSDimitry Andric 
10295f757f3fSDimitry Andric   llvm::support::endian::Writer writer(OS, llvm::endianness::little);
10305f757f3fSDimitry Andric 
10315f757f3fSDimitry Andric   writer.write<uint8_t>(flags);
10325f757f3fSDimitry Andric   writer.write<uint8_t>(FI.NumAdjustedNullable);
10335f757f3fSDimitry Andric   writer.write<uint64_t>(FI.NullabilityPayload);
10345f757f3fSDimitry Andric 
10355f757f3fSDimitry Andric   writer.write<uint16_t>(FI.Params.size());
10365f757f3fSDimitry Andric   for (const auto &PI : FI.Params)
10375f757f3fSDimitry Andric     emitParamInfo(OS, PI);
10385f757f3fSDimitry Andric 
10395f757f3fSDimitry Andric   writer.write<uint16_t>(FI.ResultType.size());
10405f757f3fSDimitry Andric   writer.write(ArrayRef<char>{FI.ResultType.data(), FI.ResultType.size()});
10415f757f3fSDimitry Andric }
10425f757f3fSDimitry Andric 
10435f757f3fSDimitry Andric /// Used to serialize the on-disk global function table.
10445f757f3fSDimitry Andric class GlobalFunctionTableInfo
1045*0fca6ea1SDimitry Andric     : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
10465f757f3fSDimitry Andric                                 GlobalFunctionInfo> {
10475f757f3fSDimitry Andric public:
10485f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) {
1049*0fca6ea1SDimitry Andric     return sizeof(uint32_t) + sizeof(uint32_t);
10505f757f3fSDimitry Andric   }
10515f757f3fSDimitry Andric 
10525f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
10535f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
10545f757f3fSDimitry Andric     writer.write<uint32_t>(Key.parentContextID);
1055*0fca6ea1SDimitry Andric     writer.write<uint32_t>(Key.nameID);
10565f757f3fSDimitry Andric   }
10575f757f3fSDimitry Andric 
10585f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
10595f757f3fSDimitry Andric     return static_cast<size_t>(Key.hashValue());
10605f757f3fSDimitry Andric   }
10615f757f3fSDimitry Andric 
10625f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
10635f757f3fSDimitry Andric     return getFunctionInfoSize(GFI);
10645f757f3fSDimitry Andric   }
10655f757f3fSDimitry Andric 
10665f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
10675f757f3fSDimitry Andric     emitFunctionInfo(OS, GFI);
10685f757f3fSDimitry Andric   }
10695f757f3fSDimitry Andric };
10705f757f3fSDimitry Andric } // namespace
10715f757f3fSDimitry Andric 
10725f757f3fSDimitry Andric void APINotesWriter::Implementation::writeGlobalFunctionBlock(
10735f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
10745f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
10755f757f3fSDimitry Andric 
10765f757f3fSDimitry Andric   if (GlobalFunctions.empty())
10775f757f3fSDimitry Andric     return;
10785f757f3fSDimitry Andric 
10795f757f3fSDimitry Andric   {
10805f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
10815f757f3fSDimitry Andric     uint32_t Offset;
10825f757f3fSDimitry Andric     {
10835f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
10845f757f3fSDimitry Andric       for (auto &F : GlobalFunctions)
10855f757f3fSDimitry Andric         Generator.insert(F.first, F.second);
10865f757f3fSDimitry Andric 
10875f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
10885f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
10895f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
10905f757f3fSDimitry Andric                                              llvm::endianness::little);
10915f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
10925f757f3fSDimitry Andric     }
10935f757f3fSDimitry Andric 
10945f757f3fSDimitry Andric     global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
10955f757f3fSDimitry Andric     GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
10965f757f3fSDimitry Andric   }
10975f757f3fSDimitry Andric }
10985f757f3fSDimitry Andric 
10995f757f3fSDimitry Andric namespace {
11005f757f3fSDimitry Andric /// Used to serialize the on-disk global enum constant.
11015f757f3fSDimitry Andric class EnumConstantTableInfo
11025f757f3fSDimitry Andric     : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
11035f757f3fSDimitry Andric                                 EnumConstantInfo> {
11045f757f3fSDimitry Andric public:
11055f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
11065f757f3fSDimitry Andric 
11075f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
11085f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
11095f757f3fSDimitry Andric     writer.write<uint32_t>(Key);
11105f757f3fSDimitry Andric   }
11115f757f3fSDimitry Andric 
11125f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
11135f757f3fSDimitry Andric     return static_cast<size_t>(llvm::hash_value(Key));
11145f757f3fSDimitry Andric   }
11155f757f3fSDimitry Andric 
11165f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
11175f757f3fSDimitry Andric     return getCommonEntityInfoSize(ECI);
11185f757f3fSDimitry Andric   }
11195f757f3fSDimitry Andric 
11205f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
11215f757f3fSDimitry Andric     emitCommonEntityInfo(OS, ECI);
11225f757f3fSDimitry Andric   }
11235f757f3fSDimitry Andric };
11245f757f3fSDimitry Andric } // namespace
11255f757f3fSDimitry Andric 
11265f757f3fSDimitry Andric void APINotesWriter::Implementation::writeEnumConstantBlock(
11275f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
11285f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
11295f757f3fSDimitry Andric 
11305f757f3fSDimitry Andric   if (EnumConstants.empty())
11315f757f3fSDimitry Andric     return;
11325f757f3fSDimitry Andric 
11335f757f3fSDimitry Andric   {
11345f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
11355f757f3fSDimitry Andric     uint32_t Offset;
11365f757f3fSDimitry Andric     {
11375f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
11385f757f3fSDimitry Andric       for (auto &EC : EnumConstants)
11395f757f3fSDimitry Andric         Generator.insert(EC.first, EC.second);
11405f757f3fSDimitry Andric 
11415f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
11425f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
11435f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
11445f757f3fSDimitry Andric                                              llvm::endianness::little);
11455f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
11465f757f3fSDimitry Andric     }
11475f757f3fSDimitry Andric 
11485f757f3fSDimitry Andric     enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
11495f757f3fSDimitry Andric     EnumConstantData.emit(Scratch, Offset, HashTableBlob);
11505f757f3fSDimitry Andric   }
11515f757f3fSDimitry Andric }
11525f757f3fSDimitry Andric 
11535f757f3fSDimitry Andric namespace {
11545f757f3fSDimitry Andric template <typename Derived, typename UnversionedDataType>
11555f757f3fSDimitry Andric class CommonTypeTableInfo
1156*0fca6ea1SDimitry Andric     : public VersionedTableInfo<Derived, SingleDeclTableKey,
1157*0fca6ea1SDimitry Andric                                 UnversionedDataType> {
11585f757f3fSDimitry Andric public:
11595f757f3fSDimitry Andric   using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
11605f757f3fSDimitry Andric   using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
11615f757f3fSDimitry Andric 
11625f757f3fSDimitry Andric   unsigned getKeyLength(key_type_ref) {
1163*0fca6ea1SDimitry Andric     return sizeof(uint32_t) + sizeof(IdentifierID);
11645f757f3fSDimitry Andric   }
11655f757f3fSDimitry Andric 
11665f757f3fSDimitry Andric   void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
11675f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
11685f757f3fSDimitry Andric     writer.write<uint32_t>(Key.parentContextID);
1169*0fca6ea1SDimitry Andric     writer.write<IdentifierID>(Key.nameID);
11705f757f3fSDimitry Andric   }
11715f757f3fSDimitry Andric 
11725f757f3fSDimitry Andric   hash_value_type ComputeHash(key_type_ref Key) {
11735f757f3fSDimitry Andric     return static_cast<size_t>(Key.hashValue());
11745f757f3fSDimitry Andric   }
11755f757f3fSDimitry Andric 
11765f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
11775f757f3fSDimitry Andric     return getCommonTypeInfoSize(UDT);
11785f757f3fSDimitry Andric   }
11795f757f3fSDimitry Andric 
11805f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
11815f757f3fSDimitry Andric     emitCommonTypeInfo(OS, UDT);
11825f757f3fSDimitry Andric   }
11835f757f3fSDimitry Andric };
11845f757f3fSDimitry Andric 
11855f757f3fSDimitry Andric /// Used to serialize the on-disk tag table.
11865f757f3fSDimitry Andric class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
11875f757f3fSDimitry Andric public:
11885f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const TagInfo &TI) {
11895f757f3fSDimitry Andric     return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
11905f757f3fSDimitry Andric            2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
11915f757f3fSDimitry Andric            2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1192*0fca6ea1SDimitry Andric            2 + getCommonTypeInfoSize(TI);
11935f757f3fSDimitry Andric   }
11945f757f3fSDimitry Andric 
11955f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
11965f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
11975f757f3fSDimitry Andric 
11985f757f3fSDimitry Andric     uint8_t Flags = 0;
11995f757f3fSDimitry Andric     if (auto extensibility = TI.EnumExtensibility) {
12005f757f3fSDimitry Andric       Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
12015f757f3fSDimitry Andric       assert((Flags < (1 << 2)) && "must fit in two bits");
12025f757f3fSDimitry Andric     }
12035f757f3fSDimitry Andric 
12045f757f3fSDimitry Andric     Flags <<= 2;
12055f757f3fSDimitry Andric     if (auto value = TI.isFlagEnum())
12065f757f3fSDimitry Andric       Flags |= (value.value() << 1 | 1 << 0);
12075f757f3fSDimitry Andric 
12085f757f3fSDimitry Andric     writer.write<uint8_t>(Flags);
12095f757f3fSDimitry Andric 
1210*0fca6ea1SDimitry Andric     if (auto Copyable = TI.isSwiftCopyable())
1211*0fca6ea1SDimitry Andric       writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyable);
1212*0fca6ea1SDimitry Andric     else
1213*0fca6ea1SDimitry Andric       writer.write<uint8_t>(0);
1214*0fca6ea1SDimitry Andric 
12155f757f3fSDimitry Andric     if (auto ImportAs = TI.SwiftImportAs) {
12165f757f3fSDimitry Andric       writer.write<uint16_t>(ImportAs->size() + 1);
12175f757f3fSDimitry Andric       OS.write(ImportAs->c_str(), ImportAs->size());
12185f757f3fSDimitry Andric     } else {
12195f757f3fSDimitry Andric       writer.write<uint16_t>(0);
12205f757f3fSDimitry Andric     }
12215f757f3fSDimitry Andric     if (auto RetainOp = TI.SwiftRetainOp) {
12225f757f3fSDimitry Andric       writer.write<uint16_t>(RetainOp->size() + 1);
12235f757f3fSDimitry Andric       OS.write(RetainOp->c_str(), RetainOp->size());
12245f757f3fSDimitry Andric     } else {
12255f757f3fSDimitry Andric       writer.write<uint16_t>(0);
12265f757f3fSDimitry Andric     }
12275f757f3fSDimitry Andric     if (auto ReleaseOp = TI.SwiftReleaseOp) {
12285f757f3fSDimitry Andric       writer.write<uint16_t>(ReleaseOp->size() + 1);
12295f757f3fSDimitry Andric       OS.write(ReleaseOp->c_str(), ReleaseOp->size());
12305f757f3fSDimitry Andric     } else {
12315f757f3fSDimitry Andric       writer.write<uint16_t>(0);
12325f757f3fSDimitry Andric     }
12335f757f3fSDimitry Andric 
12345f757f3fSDimitry Andric     emitCommonTypeInfo(OS, TI);
12355f757f3fSDimitry Andric   }
12365f757f3fSDimitry Andric };
12375f757f3fSDimitry Andric } // namespace
12385f757f3fSDimitry Andric 
12395f757f3fSDimitry Andric void APINotesWriter::Implementation::writeTagBlock(
12405f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
12415f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
12425f757f3fSDimitry Andric 
12435f757f3fSDimitry Andric   if (Tags.empty())
12445f757f3fSDimitry Andric     return;
12455f757f3fSDimitry Andric 
12465f757f3fSDimitry Andric   {
12475f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
12485f757f3fSDimitry Andric     uint32_t Offset;
12495f757f3fSDimitry Andric     {
12505f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
12515f757f3fSDimitry Andric       for (auto &T : Tags)
12525f757f3fSDimitry Andric         Generator.insert(T.first, T.second);
12535f757f3fSDimitry Andric 
12545f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
12555f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
12565f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
12575f757f3fSDimitry Andric                                              llvm::endianness::little);
12585f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
12595f757f3fSDimitry Andric     }
12605f757f3fSDimitry Andric 
12615f757f3fSDimitry Andric     tag_block::TagDataLayout TagData(Stream);
12625f757f3fSDimitry Andric     TagData.emit(Scratch, Offset, HashTableBlob);
12635f757f3fSDimitry Andric   }
12645f757f3fSDimitry Andric }
12655f757f3fSDimitry Andric 
12665f757f3fSDimitry Andric namespace {
12675f757f3fSDimitry Andric /// Used to serialize the on-disk typedef table.
12685f757f3fSDimitry Andric class TypedefTableInfo
12695f757f3fSDimitry Andric     : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
12705f757f3fSDimitry Andric public:
12715f757f3fSDimitry Andric   unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
12725f757f3fSDimitry Andric     return 1 + getCommonTypeInfoSize(TI);
12735f757f3fSDimitry Andric   }
12745f757f3fSDimitry Andric 
12755f757f3fSDimitry Andric   void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
12765f757f3fSDimitry Andric     llvm::support::endian::Writer writer(OS, llvm::endianness::little);
12775f757f3fSDimitry Andric 
12785f757f3fSDimitry Andric     uint8_t Flags = 0;
12795f757f3fSDimitry Andric     if (auto swiftWrapper = TI.SwiftWrapper)
12805f757f3fSDimitry Andric       Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
12815f757f3fSDimitry Andric 
12825f757f3fSDimitry Andric     writer.write<uint8_t>(Flags);
12835f757f3fSDimitry Andric 
12845f757f3fSDimitry Andric     emitCommonTypeInfo(OS, TI);
12855f757f3fSDimitry Andric   }
12865f757f3fSDimitry Andric };
12875f757f3fSDimitry Andric } // namespace
12885f757f3fSDimitry Andric 
12895f757f3fSDimitry Andric void APINotesWriter::Implementation::writeTypedefBlock(
12905f757f3fSDimitry Andric     llvm::BitstreamWriter &Stream) {
12915f757f3fSDimitry Andric   llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
12925f757f3fSDimitry Andric 
12935f757f3fSDimitry Andric   if (Typedefs.empty())
12945f757f3fSDimitry Andric     return;
12955f757f3fSDimitry Andric 
12965f757f3fSDimitry Andric   {
12975f757f3fSDimitry Andric     llvm::SmallString<4096> HashTableBlob;
12985f757f3fSDimitry Andric     uint32_t Offset;
12995f757f3fSDimitry Andric     {
13005f757f3fSDimitry Andric       llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
13015f757f3fSDimitry Andric       for (auto &T : Typedefs)
13025f757f3fSDimitry Andric         Generator.insert(T.first, T.second);
13035f757f3fSDimitry Andric 
13045f757f3fSDimitry Andric       llvm::raw_svector_ostream BlobStream(HashTableBlob);
13055f757f3fSDimitry Andric       // Make sure that no bucket is at offset 0
13065f757f3fSDimitry Andric       llvm::support::endian::write<uint32_t>(BlobStream, 0,
13075f757f3fSDimitry Andric                                              llvm::endianness::little);
13085f757f3fSDimitry Andric       Offset = Generator.Emit(BlobStream);
13095f757f3fSDimitry Andric     }
13105f757f3fSDimitry Andric 
13115f757f3fSDimitry Andric     typedef_block::TypedefDataLayout TypedefData(Stream);
13125f757f3fSDimitry Andric     TypedefData.emit(Scratch, Offset, HashTableBlob);
13135f757f3fSDimitry Andric   }
13145f757f3fSDimitry Andric }
13155f757f3fSDimitry Andric 
13165f757f3fSDimitry Andric // APINotesWriter
13175f757f3fSDimitry Andric 
13185f757f3fSDimitry Andric APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
13195f757f3fSDimitry Andric     : Implementation(new class Implementation(ModuleName, SF)) {}
13205f757f3fSDimitry Andric 
13215f757f3fSDimitry Andric APINotesWriter::~APINotesWriter() = default;
13225f757f3fSDimitry Andric 
13235f757f3fSDimitry Andric void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
13245f757f3fSDimitry Andric   Implementation->writeToStream(OS);
13255f757f3fSDimitry Andric }
13265f757f3fSDimitry Andric 
1327*0fca6ea1SDimitry Andric ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1328*0fca6ea1SDimitry Andric                                      llvm::StringRef Name, ContextKind Kind,
1329*0fca6ea1SDimitry Andric                                      const ContextInfo &Info,
1330*0fca6ea1SDimitry Andric                                      llvm::VersionTuple SwiftVersion) {
13315f757f3fSDimitry Andric   IdentifierID NameID = Implementation->getIdentifier(Name);
13325f757f3fSDimitry Andric 
13335f757f3fSDimitry Andric   uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
13345f757f3fSDimitry Andric   ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1335*0fca6ea1SDimitry Andric   auto Known = Implementation->Contexts.find(Key);
1336*0fca6ea1SDimitry Andric   if (Known == Implementation->Contexts.end()) {
1337*0fca6ea1SDimitry Andric     unsigned NextID = Implementation->Contexts.size() + 1;
13385f757f3fSDimitry Andric 
1339*0fca6ea1SDimitry Andric     Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;
1340*0fca6ea1SDimitry Andric     Known = Implementation->Contexts
13415f757f3fSDimitry Andric                 .insert(std::make_pair(
13425f757f3fSDimitry Andric                     Key, std::make_pair(NextID, EmptyVersionedInfo)))
13435f757f3fSDimitry Andric                 .first;
13445f757f3fSDimitry Andric 
1345*0fca6ea1SDimitry Andric     Implementation->ContextNames[NextID] = NameID;
13465f757f3fSDimitry Andric     Implementation->ParentContexts[NextID] = RawParentCtxID;
13475f757f3fSDimitry Andric   }
13485f757f3fSDimitry Andric 
13495f757f3fSDimitry Andric   // Add this version information.
13505f757f3fSDimitry Andric   auto &VersionedVec = Known->second.second;
13515f757f3fSDimitry Andric   bool Found = false;
13525f757f3fSDimitry Andric   for (auto &Versioned : VersionedVec) {
13535f757f3fSDimitry Andric     if (Versioned.first == SwiftVersion) {
13545f757f3fSDimitry Andric       Versioned.second |= Info;
13555f757f3fSDimitry Andric       Found = true;
13565f757f3fSDimitry Andric       break;
13575f757f3fSDimitry Andric     }
13585f757f3fSDimitry Andric   }
13595f757f3fSDimitry Andric 
13605f757f3fSDimitry Andric   if (!Found)
13615f757f3fSDimitry Andric     VersionedVec.push_back({SwiftVersion, Info});
13625f757f3fSDimitry Andric 
13635f757f3fSDimitry Andric   return ContextID(Known->second.first);
13645f757f3fSDimitry Andric }
13655f757f3fSDimitry Andric 
13665f757f3fSDimitry Andric void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
13675f757f3fSDimitry Andric                                      bool IsInstanceProperty,
13685f757f3fSDimitry Andric                                      const ObjCPropertyInfo &Info,
13695f757f3fSDimitry Andric                                      VersionTuple SwiftVersion) {
13705f757f3fSDimitry Andric   IdentifierID NameID = Implementation->getIdentifier(Name);
13715f757f3fSDimitry Andric   Implementation
13725f757f3fSDimitry Andric       ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
13735f757f3fSDimitry Andric       .push_back({SwiftVersion, Info});
13745f757f3fSDimitry Andric }
13755f757f3fSDimitry Andric 
13765f757f3fSDimitry Andric void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
13775f757f3fSDimitry Andric                                    bool IsInstanceMethod,
13785f757f3fSDimitry Andric                                    const ObjCMethodInfo &Info,
13795f757f3fSDimitry Andric                                    VersionTuple SwiftVersion) {
13805f757f3fSDimitry Andric   SelectorID SelID = Implementation->getSelector(Selector);
13815f757f3fSDimitry Andric   auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
13825f757f3fSDimitry Andric                                                   IsInstanceMethod};
13835f757f3fSDimitry Andric   Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
13845f757f3fSDimitry Andric 
13855f757f3fSDimitry Andric   // If this method is a designated initializer, update the class to note that
13865f757f3fSDimitry Andric   // it has designated initializers.
13875f757f3fSDimitry Andric   if (Info.DesignatedInit) {
13885f757f3fSDimitry Andric     assert(Implementation->ParentContexts.contains(CtxID.Value));
13895f757f3fSDimitry Andric     uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
13905f757f3fSDimitry Andric     ContextTableKey CtxKey(ParentCtxID,
13915f757f3fSDimitry Andric                            static_cast<uint8_t>(ContextKind::ObjCClass),
1392*0fca6ea1SDimitry Andric                            Implementation->ContextNames[CtxID.Value]);
1393*0fca6ea1SDimitry Andric     assert(Implementation->Contexts.contains(CtxKey));
1394*0fca6ea1SDimitry Andric     auto &VersionedVec = Implementation->Contexts[CtxKey].second;
13955f757f3fSDimitry Andric     bool Found = false;
13965f757f3fSDimitry Andric     for (auto &Versioned : VersionedVec) {
13975f757f3fSDimitry Andric       if (Versioned.first == SwiftVersion) {
13985f757f3fSDimitry Andric         Versioned.second.setHasDesignatedInits(true);
13995f757f3fSDimitry Andric         Found = true;
14005f757f3fSDimitry Andric         break;
14015f757f3fSDimitry Andric       }
14025f757f3fSDimitry Andric     }
14035f757f3fSDimitry Andric 
14045f757f3fSDimitry Andric     if (!Found) {
1405*0fca6ea1SDimitry Andric       VersionedVec.push_back({SwiftVersion, ContextInfo()});
14065f757f3fSDimitry Andric       VersionedVec.back().second.setHasDesignatedInits(true);
14075f757f3fSDimitry Andric     }
14085f757f3fSDimitry Andric   }
14095f757f3fSDimitry Andric }
14105f757f3fSDimitry Andric 
1411*0fca6ea1SDimitry Andric void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1412*0fca6ea1SDimitry Andric                                   const CXXMethodInfo &Info,
1413*0fca6ea1SDimitry Andric                                   VersionTuple SwiftVersion) {
1414*0fca6ea1SDimitry Andric   IdentifierID NameID = Implementation->getIdentifier(Name);
1415*0fca6ea1SDimitry Andric   SingleDeclTableKey Key(CtxID.Value, NameID);
1416*0fca6ea1SDimitry Andric   Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
1417*0fca6ea1SDimitry Andric }
1418*0fca6ea1SDimitry Andric 
14195f757f3fSDimitry Andric void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
14205f757f3fSDimitry Andric                                        llvm::StringRef Name,
14215f757f3fSDimitry Andric                                        const GlobalVariableInfo &Info,
14225f757f3fSDimitry Andric                                        VersionTuple SwiftVersion) {
14235f757f3fSDimitry Andric   IdentifierID VariableID = Implementation->getIdentifier(Name);
1424*0fca6ea1SDimitry Andric   SingleDeclTableKey Key(Ctx, VariableID);
14255f757f3fSDimitry Andric   Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
14265f757f3fSDimitry Andric }
14275f757f3fSDimitry Andric 
14285f757f3fSDimitry Andric void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
14295f757f3fSDimitry Andric                                        llvm::StringRef Name,
14305f757f3fSDimitry Andric                                        const GlobalFunctionInfo &Info,
14315f757f3fSDimitry Andric                                        VersionTuple SwiftVersion) {
14325f757f3fSDimitry Andric   IdentifierID NameID = Implementation->getIdentifier(Name);
1433*0fca6ea1SDimitry Andric   SingleDeclTableKey Key(Ctx, NameID);
14345f757f3fSDimitry Andric   Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
14355f757f3fSDimitry Andric }
14365f757f3fSDimitry Andric 
14375f757f3fSDimitry Andric void APINotesWriter::addEnumConstant(llvm::StringRef Name,
14385f757f3fSDimitry Andric                                      const EnumConstantInfo &Info,
14395f757f3fSDimitry Andric                                      VersionTuple SwiftVersion) {
14405f757f3fSDimitry Andric   IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
14415f757f3fSDimitry Andric   Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
14425f757f3fSDimitry Andric }
14435f757f3fSDimitry Andric 
14445f757f3fSDimitry Andric void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
14455f757f3fSDimitry Andric                             const TagInfo &Info, VersionTuple SwiftVersion) {
14465f757f3fSDimitry Andric   IdentifierID TagID = Implementation->getIdentifier(Name);
1447*0fca6ea1SDimitry Andric   SingleDeclTableKey Key(Ctx, TagID);
14485f757f3fSDimitry Andric   Implementation->Tags[Key].push_back({SwiftVersion, Info});
14495f757f3fSDimitry Andric }
14505f757f3fSDimitry Andric 
14515f757f3fSDimitry Andric void APINotesWriter::addTypedef(std::optional<Context> Ctx,
14525f757f3fSDimitry Andric                                 llvm::StringRef Name, const TypedefInfo &Info,
14535f757f3fSDimitry Andric                                 VersionTuple SwiftVersion) {
14545f757f3fSDimitry Andric   IdentifierID TypedefID = Implementation->getIdentifier(Name);
1455*0fca6ea1SDimitry Andric   SingleDeclTableKey Key(Ctx, TypedefID);
14565f757f3fSDimitry Andric   Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
14575f757f3fSDimitry Andric }
14585f757f3fSDimitry Andric } // namespace api_notes
14595f757f3fSDimitry Andric } // namespace clang
1460