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