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