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