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