1585 lines · cpp
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-exception6//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 20namespace clang {21namespace api_notes {22class 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 of42 /// this context and provides both the context ID and information describing43 /// 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 an59 /// 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 150private: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 166public: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 173void 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 204namespace {205/// Record the name of a block.206void 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.223void 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} // namespace235 236void 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_RECORD268#undef BLOCK269}270 271void 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 288namespace {289/// Used to serialize the on-disk identifier table.290class IdentifierTableInfo {291public: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} // namespace320 321void 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 0337 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 346namespace {347/// Used to serialize the on-disk Objective-C context table.348class ContextIDTableInfo {349public: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 argument386/// deduction.387template <typename T> struct MakeDependent { typedef T Type; };388 389/// Retrieve the serialized size of the given VersionTuple, for use in390/// on-disk hash tables.391unsigned 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,403template <typename T>404unsigned 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 elements409 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.417void 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 else429 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.443template <typename T>444void 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.466template <typename Derived, typename KeyType, typename UnversionedDataType>467class VersionedTableInfo {468 Derived &asDerived() { return *static_cast<Derived *>(this); }469 470 const Derived &asDerived() const {471 return *static_cast<const Derived *>(this);472 }473 474public: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.506void 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 safety = CEI.getSwiftSafety()) {511 payload = static_cast<unsigned>(*safety);512 payload <<= 1;513 payload |= 0x01;514 }515 payload <<= 2;516 if (auto swiftPrivate = CEI.isSwiftPrivate()) {517 payload |= 0x01;518 if (*swiftPrivate)519 payload |= 0x02;520 }521 payload <<= 1;522 payload |= CEI.Unavailable;523 payload <<= 1;524 payload |= CEI.UnavailableInSwift;525 526 writer.write<uint8_t>(payload);527 528 writer.write<uint16_t>(CEI.UnavailableMsg.size());529 OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());530 531 writer.write<uint16_t>(CEI.SwiftName.size());532 OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());533}534 535/// Retrieve the serialized size of the given CommonEntityInfo, for use in536/// on-disk hash tables.537unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {538 return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();539}540 541// Retrieve the serialized size of the given CommonTypeInfo, for use542// in on-disk hash tables.543unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {544 return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +545 (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) + 2 +546 (CTI.getSwiftConformance() ? CTI.getSwiftConformance()->size() : 0) +547 getCommonEntityInfoSize(CTI);548}549 550/// Emit a serialized representation of the common type information.551void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {552 emitCommonEntityInfo(OS, CTI);553 554 llvm::support::endian::Writer writer(OS, llvm::endianness::little);555 if (auto swiftBridge = CTI.getSwiftBridge()) {556 writer.write<uint16_t>(swiftBridge->size() + 1);557 OS.write(swiftBridge->c_str(), swiftBridge->size());558 } else {559 writer.write<uint16_t>(0);560 }561 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {562 writer.write<uint16_t>(nsErrorDomain->size() + 1);563 OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());564 } else {565 writer.write<uint16_t>(0);566 }567 if (auto conformance = CTI.getSwiftConformance()) {568 writer.write<uint16_t>(conformance->size() + 1);569 OS.write(conformance->c_str(), conformance->size());570 } else {571 writer.write<uint16_t>(0);572 }573}574 575/// Used to serialize the on-disk Objective-C property table.576class ContextInfoTableInfo577 : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {578public:579 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }580 581 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {582 llvm::support::endian::Writer writer(OS, llvm::endianness::little);583 writer.write<uint32_t>(Key);584 }585 586 hash_value_type ComputeHash(key_type_ref Key) {587 return static_cast<size_t>(llvm::hash_value(Key));588 }589 590 unsigned getUnversionedInfoSize(const ContextInfo &OCI) {591 return getCommonTypeInfoSize(OCI) + 1;592 }593 594 void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {595 emitCommonTypeInfo(OS, OCI);596 597 uint8_t payload = 0;598 if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())599 payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();600 payload <<= 2;601 if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())602 payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();603 payload <<= 3;604 if (auto nullable = OCI.getDefaultNullability())605 payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);606 payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);607 608 OS << payload;609 }610};611} // namespace612 613void APINotesWriter::Implementation::writeContextBlock(614 llvm::BitstreamWriter &Stream) {615 llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);616 617 if (Contexts.empty())618 return;619 620 {621 llvm::SmallString<4096> HashTableBlob;622 uint32_t Offset;623 {624 llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;625 for (auto &OC : Contexts)626 Generator.insert(OC.first, OC.second.first);627 628 llvm::raw_svector_ostream BlobStream(HashTableBlob);629 // Make sure that no bucket is at offset 0630 llvm::support::endian::write<uint32_t>(BlobStream, 0,631 llvm::endianness::little);632 Offset = Generator.Emit(BlobStream);633 }634 635 context_block::ContextIDLayout ContextID(Stream);636 ContextID.emit(Scratch, Offset, HashTableBlob);637 }638 639 {640 llvm::SmallString<4096> HashTableBlob;641 uint32_t Offset;642 {643 llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;644 for (auto &OC : Contexts)645 Generator.insert(OC.second.first, OC.second.second);646 647 llvm::raw_svector_ostream BlobStream(HashTableBlob);648 // Make sure that no bucket is at offset 0649 llvm::support::endian::write<uint32_t>(BlobStream, 0,650 llvm::endianness::little);651 Offset = Generator.Emit(BlobStream);652 }653 654 context_block::ContextInfoLayout ContextInfo(Stream);655 ContextInfo.emit(Scratch, Offset, HashTableBlob);656 }657}658 659namespace {660/// Retrieve the serialized size of the given VariableInfo, for use in661/// on-disk hash tables.662unsigned getVariableInfoSize(const VariableInfo &VI) {663 return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();664}665unsigned getParamInfoSize(const ParamInfo &PI);666 667/// Emit a serialized representation of the variable information.668void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {669 emitCommonEntityInfo(OS, VI);670 671 uint8_t bytes[2] = {0, 0};672 if (auto nullable = VI.getNullability()) {673 bytes[0] = 1;674 bytes[1] = static_cast<uint8_t>(*nullable);675 } else {676 // Nothing to do.677 }678 679 OS.write(reinterpret_cast<const char *>(bytes), 2);680 681 llvm::support::endian::Writer writer(OS, llvm::endianness::little);682 writer.write<uint16_t>(VI.getType().size());683 OS.write(VI.getType().data(), VI.getType().size());684}685 686/// Used to serialize the on-disk Objective-C property table.687class ObjCPropertyTableInfo688 : public VersionedTableInfo<ObjCPropertyTableInfo,689 std::tuple<unsigned, unsigned, char>,690 ObjCPropertyInfo> {691public:692 unsigned getKeyLength(key_type_ref) {693 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);694 }695 696 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {697 llvm::support::endian::Writer writer(OS, llvm::endianness::little);698 writer.write<uint32_t>(std::get<0>(Key));699 writer.write<uint32_t>(std::get<1>(Key));700 writer.write<uint8_t>(std::get<2>(Key));701 }702 703 hash_value_type ComputeHash(key_type_ref Key) {704 return static_cast<size_t>(llvm::hash_value(Key));705 }706 707 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {708 return getVariableInfoSize(OPI) + 1;709 }710 711 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {712 emitVariableInfo(OS, OPI);713 714 uint8_t flags = 0;715 if (auto value = OPI.getSwiftImportAsAccessors()) {716 flags |= 1 << 0;717 flags |= value.value() << 1;718 }719 OS << flags;720 }721};722} // namespace723 724void APINotesWriter::Implementation::writeObjCPropertyBlock(725 llvm::BitstreamWriter &Stream) {726 llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);727 728 if (ObjCProperties.empty())729 return;730 731 {732 llvm::SmallString<4096> HashTableBlob;733 uint32_t Offset;734 {735 llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;736 for (auto &OP : ObjCProperties)737 Generator.insert(OP.first, OP.second);738 739 llvm::raw_svector_ostream BlobStream(HashTableBlob);740 // Make sure that no bucket is at offset 0741 llvm::support::endian::write<uint32_t>(BlobStream, 0,742 llvm::endianness::little);743 Offset = Generator.Emit(BlobStream);744 }745 746 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);747 ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);748 }749}750 751namespace {752unsigned getFunctionInfoSize(const FunctionInfo &);753void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);754void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);755 756/// Used to serialize the on-disk Objective-C method table.757class ObjCMethodTableInfo758 : public VersionedTableInfo<ObjCMethodTableInfo,759 std::tuple<unsigned, unsigned, char>,760 ObjCMethodInfo> {761public:762 unsigned getKeyLength(key_type_ref) {763 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);764 }765 766 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {767 llvm::support::endian::Writer writer(OS, llvm::endianness::little);768 writer.write<uint32_t>(std::get<0>(Key));769 writer.write<uint32_t>(std::get<1>(Key));770 writer.write<uint8_t>(std::get<2>(Key));771 }772 773 hash_value_type ComputeHash(key_type_ref key) {774 return static_cast<size_t>(llvm::hash_value(key));775 }776 777 unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {778 auto size = getFunctionInfoSize(OMI) + 1;779 if (OMI.Self)780 size += getParamInfoSize(*OMI.Self);781 return size;782 }783 784 void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {785 uint8_t flags = 0;786 llvm::support::endian::Writer writer(OS, llvm::endianness::little);787 flags = (flags << 1) | OMI.DesignatedInit;788 flags = (flags << 1) | OMI.RequiredInit;789 flags = (flags << 1) | static_cast<bool>(OMI.Self);790 writer.write<uint8_t>(flags);791 792 emitFunctionInfo(OS, OMI);793 794 if (OMI.Self)795 emitParamInfo(OS, *OMI.Self);796 }797};798 799/// Used to serialize the on-disk C++ method table.800class CXXMethodTableInfo801 : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,802 CXXMethodInfo> {803public:804 unsigned getKeyLength(key_type_ref) {805 return sizeof(uint32_t) + sizeof(uint32_t);806 }807 808 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {809 llvm::support::endian::Writer writer(OS, llvm::endianness::little);810 writer.write<uint32_t>(Key.parentContextID);811 writer.write<uint32_t>(Key.nameID);812 }813 814 hash_value_type ComputeHash(key_type_ref key) {815 return static_cast<size_t>(key.hashValue());816 }817 818 unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {819 auto size = getFunctionInfoSize(MI) + 1;820 if (MI.This)821 size += getParamInfoSize(*MI.This);822 return size;823 }824 825 void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {826 uint8_t flags = 0;827 llvm::support::endian::Writer writer(OS, llvm::endianness::little);828 flags = (flags << 1) | static_cast<bool>(MI.This);829 writer.write<uint8_t>(flags);830 831 emitFunctionInfo(OS, MI);832 if (MI.This)833 emitParamInfo(OS, *MI.This);834 }835};836} // namespace837 838void APINotesWriter::Implementation::writeObjCMethodBlock(839 llvm::BitstreamWriter &Stream) {840 llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);841 842 if (ObjCMethods.empty())843 return;844 845 {846 llvm::SmallString<4096> HashTableBlob;847 uint32_t Offset;848 {849 llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;850 for (auto &OM : ObjCMethods)851 Generator.insert(OM.first, OM.second);852 853 llvm::raw_svector_ostream BlobStream(HashTableBlob);854 // Make sure that no bucket is at offset 0855 llvm::support::endian::write<uint32_t>(BlobStream, 0,856 llvm::endianness::little);857 Offset = Generator.Emit(BlobStream);858 }859 860 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);861 ObjCMethodData.emit(Scratch, Offset, HashTableBlob);862 }863}864 865void APINotesWriter::Implementation::writeCXXMethodBlock(866 llvm::BitstreamWriter &Stream) {867 llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);868 869 if (CXXMethods.empty())870 return;871 872 {873 llvm::SmallString<4096> HashTableBlob;874 uint32_t Offset;875 {876 llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;877 for (auto &MD : CXXMethods)878 Generator.insert(MD.first, MD.second);879 880 llvm::raw_svector_ostream BlobStream(HashTableBlob);881 // Make sure that no bucket is at offset 0882 llvm::support::endian::write<uint32_t>(BlobStream, 0,883 llvm::endianness::little);884 Offset = Generator.Emit(BlobStream);885 }886 887 cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);888 CXXMethodData.emit(Scratch, Offset, HashTableBlob);889 }890}891 892namespace {893/// Used to serialize the on-disk C field table.894class FieldTableInfo895 : public VersionedTableInfo<FieldTableInfo, SingleDeclTableKey, FieldInfo> {896public:897 unsigned getKeyLength(key_type_ref) {898 return sizeof(uint32_t) + sizeof(uint32_t);899 }900 901 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {902 llvm::support::endian::Writer writer(OS, llvm::endianness::little);903 writer.write<uint32_t>(Key.parentContextID);904 writer.write<uint32_t>(Key.nameID);905 }906 907 hash_value_type ComputeHash(key_type_ref key) {908 return static_cast<size_t>(key.hashValue());909 }910 911 unsigned getUnversionedInfoSize(const FieldInfo &FI) {912 return getVariableInfoSize(FI);913 }914 915 void emitUnversionedInfo(raw_ostream &OS, const FieldInfo &FI) {916 emitVariableInfo(OS, FI);917 }918};919} // namespace920 921void APINotesWriter::Implementation::writeFieldBlock(922 llvm::BitstreamWriter &Stream) {923 llvm::BCBlockRAII Scope(Stream, FIELD_BLOCK_ID, 3);924 925 if (Fields.empty())926 return;927 928 {929 llvm::SmallString<4096> HashTableBlob;930 uint32_t Offset;931 {932 llvm::OnDiskChainedHashTableGenerator<FieldTableInfo> Generator;933 for (auto &FD : Fields)934 Generator.insert(FD.first, FD.second);935 936 llvm::raw_svector_ostream BlobStream(HashTableBlob);937 // Make sure that no bucket is at offset 0938 llvm::support::endian::write<uint32_t>(BlobStream, 0,939 llvm::endianness::little);940 Offset = Generator.Emit(BlobStream);941 }942 943 field_block::FieldDataLayout FieldData(Stream);944 FieldData.emit(Scratch, Offset, HashTableBlob);945 }946}947 948namespace {949/// Used to serialize the on-disk Objective-C selector table.950class ObjCSelectorTableInfo {951public:952 using key_type = StoredObjCSelector;953 using key_type_ref = const key_type &;954 using data_type = SelectorID;955 using data_type_ref = data_type;956 using hash_value_type = unsigned;957 using offset_type = unsigned;958 959 hash_value_type ComputeHash(key_type_ref Key) {960 return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);961 }962 963 std::pair<unsigned, unsigned>964 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {965 uint32_t KeyLength =966 sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();967 uint32_t DataLength = sizeof(uint32_t);968 969 llvm::support::endian::Writer writer(OS, llvm::endianness::little);970 writer.write<uint16_t>(KeyLength);971 writer.write<uint16_t>(DataLength);972 return {KeyLength, DataLength};973 }974 975 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {976 llvm::support::endian::Writer writer(OS, llvm::endianness::little);977 writer.write<uint16_t>(Key.NumArgs);978 for (auto Identifier : Key.Identifiers)979 writer.write<uint32_t>(Identifier);980 }981 982 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {983 llvm::support::endian::Writer writer(OS, llvm::endianness::little);984 writer.write<uint32_t>(Data);985 }986};987} // namespace988 989void APINotesWriter::Implementation::writeObjCSelectorBlock(990 llvm::BitstreamWriter &Stream) {991 llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);992 993 if (SelectorIDs.empty())994 return;995 996 {997 llvm::SmallString<4096> HashTableBlob;998 uint32_t Offset;999 {1000 llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;1001 for (auto &S : SelectorIDs)1002 Generator.insert(S.first, S.second);1003 1004 llvm::raw_svector_ostream BlobStream(HashTableBlob);1005 // Make sure that no bucket is at offset 01006 llvm::support::endian::write<uint32_t>(BlobStream, 0,1007 llvm::endianness::little);1008 Offset = Generator.Emit(BlobStream);1009 }1010 1011 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);1012 ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);1013 }1014}1015 1016namespace {1017/// Used to serialize the on-disk global variable table.1018class GlobalVariableTableInfo1019 : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,1020 GlobalVariableInfo> {1021public:1022 unsigned getKeyLength(key_type_ref) {1023 return sizeof(uint32_t) + sizeof(uint32_t);1024 }1025 1026 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1027 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1028 writer.write<uint32_t>(Key.parentContextID);1029 writer.write<uint32_t>(Key.nameID);1030 }1031 1032 hash_value_type ComputeHash(key_type_ref Key) {1033 return static_cast<size_t>(Key.hashValue());1034 }1035 1036 unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {1037 return getVariableInfoSize(GVI);1038 }1039 1040 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {1041 emitVariableInfo(OS, GVI);1042 }1043};1044} // namespace1045 1046void APINotesWriter::Implementation::writeGlobalVariableBlock(1047 llvm::BitstreamWriter &Stream) {1048 llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);1049 1050 if (GlobalVariables.empty())1051 return;1052 1053 {1054 llvm::SmallString<4096> HashTableBlob;1055 uint32_t Offset;1056 {1057 llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;1058 for (auto &GV : GlobalVariables)1059 Generator.insert(GV.first, GV.second);1060 1061 llvm::raw_svector_ostream BlobStream(HashTableBlob);1062 // Make sure that no bucket is at offset 01063 llvm::support::endian::write<uint32_t>(BlobStream, 0,1064 llvm::endianness::little);1065 Offset = Generator.Emit(BlobStream);1066 }1067 1068 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);1069 GlobalVariableData.emit(Scratch, Offset, HashTableBlob);1070 }1071}1072 1073namespace {1074unsigned getParamInfoSize(const ParamInfo &PI) {1075 return getVariableInfoSize(PI) + 1;1076}1077 1078void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {1079 emitVariableInfo(OS, PI);1080 1081 uint8_t flags = 0;1082 if (auto noescape = PI.isNoEscape()) {1083 flags |= 0x01;1084 if (*noescape)1085 flags |= 0x02;1086 }1087 flags <<= 2;1088 if (auto lifetimebound = PI.isLifetimebound()) {1089 flags |= 0x01;1090 if (*lifetimebound)1091 flags |= 0x02;1092 }1093 flags <<= 3;1094 if (auto RCC = PI.getRetainCountConvention())1095 flags |= static_cast<uint8_t>(RCC.value()) + 1;1096 1097 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1098 writer.write<uint8_t>(flags);1099}1100 1101/// Retrieve the serialized size of the given FunctionInfo, for use in on-disk1102/// hash tables.1103unsigned getFunctionInfoSize(const FunctionInfo &FI) {1104 unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);1105 size += sizeof(uint16_t);1106 for (const auto &P : FI.Params)1107 size += getParamInfoSize(P);1108 size += sizeof(uint16_t) + FI.ResultType.size();1109 size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();1110 return size;1111}1112 1113/// Emit a serialized representation of the function information.1114void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {1115 emitCommonEntityInfo(OS, FI);1116 1117 uint8_t flags = 0;1118 flags |= FI.NullabilityAudited;1119 flags <<= 3;1120 if (auto RCC = FI.getRetainCountConvention())1121 flags |= static_cast<uint8_t>(RCC.value()) + 1;1122 1123 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1124 1125 writer.write<uint8_t>(flags);1126 writer.write<uint8_t>(FI.NumAdjustedNullable);1127 writer.write<uint64_t>(FI.NullabilityPayload);1128 1129 writer.write<uint16_t>(FI.Params.size());1130 for (const auto &PI : FI.Params)1131 emitParamInfo(OS, PI);1132 1133 writer.write<uint16_t>(FI.ResultType.size());1134 writer.write(ArrayRef<char>{FI.ResultType});1135 writer.write<uint16_t>(FI.SwiftReturnOwnership.size());1136 writer.write(ArrayRef<char>{FI.SwiftReturnOwnership});1137}1138 1139/// Used to serialize the on-disk global function table.1140class GlobalFunctionTableInfo1141 : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,1142 GlobalFunctionInfo> {1143public:1144 unsigned getKeyLength(key_type_ref) {1145 return sizeof(uint32_t) + sizeof(uint32_t);1146 }1147 1148 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1149 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1150 writer.write<uint32_t>(Key.parentContextID);1151 writer.write<uint32_t>(Key.nameID);1152 }1153 1154 hash_value_type ComputeHash(key_type_ref Key) {1155 return static_cast<size_t>(Key.hashValue());1156 }1157 1158 unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {1159 return getFunctionInfoSize(GFI);1160 }1161 1162 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {1163 emitFunctionInfo(OS, GFI);1164 }1165};1166} // namespace1167 1168void APINotesWriter::Implementation::writeGlobalFunctionBlock(1169 llvm::BitstreamWriter &Stream) {1170 llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);1171 1172 if (GlobalFunctions.empty())1173 return;1174 1175 {1176 llvm::SmallString<4096> HashTableBlob;1177 uint32_t Offset;1178 {1179 llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;1180 for (auto &F : GlobalFunctions)1181 Generator.insert(F.first, F.second);1182 1183 llvm::raw_svector_ostream BlobStream(HashTableBlob);1184 // Make sure that no bucket is at offset 01185 llvm::support::endian::write<uint32_t>(BlobStream, 0,1186 llvm::endianness::little);1187 Offset = Generator.Emit(BlobStream);1188 }1189 1190 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);1191 GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);1192 }1193}1194 1195namespace {1196/// Used to serialize the on-disk global enum constant.1197class EnumConstantTableInfo1198 : public VersionedTableInfo<EnumConstantTableInfo, unsigned,1199 EnumConstantInfo> {1200public:1201 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }1202 1203 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1204 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1205 writer.write<uint32_t>(Key);1206 }1207 1208 hash_value_type ComputeHash(key_type_ref Key) {1209 return static_cast<size_t>(llvm::hash_value(Key));1210 }1211 1212 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {1213 return getCommonEntityInfoSize(ECI);1214 }1215 1216 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {1217 emitCommonEntityInfo(OS, ECI);1218 }1219};1220} // namespace1221 1222void APINotesWriter::Implementation::writeEnumConstantBlock(1223 llvm::BitstreamWriter &Stream) {1224 llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);1225 1226 if (EnumConstants.empty())1227 return;1228 1229 {1230 llvm::SmallString<4096> HashTableBlob;1231 uint32_t Offset;1232 {1233 llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;1234 for (auto &EC : EnumConstants)1235 Generator.insert(EC.first, EC.second);1236 1237 llvm::raw_svector_ostream BlobStream(HashTableBlob);1238 // Make sure that no bucket is at offset 01239 llvm::support::endian::write<uint32_t>(BlobStream, 0,1240 llvm::endianness::little);1241 Offset = Generator.Emit(BlobStream);1242 }1243 1244 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);1245 EnumConstantData.emit(Scratch, Offset, HashTableBlob);1246 }1247}1248 1249namespace {1250template <typename Derived, typename UnversionedDataType>1251class CommonTypeTableInfo1252 : public VersionedTableInfo<Derived, SingleDeclTableKey,1253 UnversionedDataType> {1254public:1255 using key_type_ref = typename CommonTypeTableInfo::key_type_ref;1256 using hash_value_type = typename CommonTypeTableInfo::hash_value_type;1257 1258 unsigned getKeyLength(key_type_ref) {1259 return sizeof(uint32_t) + sizeof(IdentifierID);1260 }1261 1262 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {1263 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1264 writer.write<uint32_t>(Key.parentContextID);1265 writer.write<IdentifierID>(Key.nameID);1266 }1267 1268 hash_value_type ComputeHash(key_type_ref Key) {1269 return static_cast<size_t>(Key.hashValue());1270 }1271 1272 unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {1273 return getCommonTypeInfoSize(UDT);1274 }1275 1276 void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {1277 emitCommonTypeInfo(OS, UDT);1278 }1279};1280 1281/// Used to serialize the on-disk tag table.1282class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {1283public:1284 unsigned getUnversionedInfoSize(const TagInfo &TI) {1285 // clang-format off1286 return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +1287 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +1288 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +1289 2 + (TI.SwiftDestroyOp ? TI.SwiftDestroyOp->size() : 0) +1290 2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +1291 3 + getCommonTypeInfoSize(TI);1292 // clang-format on1293 }1294 1295 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {1296 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1297 1298 uint8_t Flags = 0;1299 if (auto extensibility = TI.EnumExtensibility) {1300 Flags |= static_cast<uint8_t>(extensibility.value()) + 1;1301 assert((Flags < (1 << 2)) && "must fit in two bits");1302 }1303 1304 Flags <<= 2;1305 if (auto value = TI.isFlagEnum())1306 Flags |= (value.value() << 1 | 1 << 0);1307 1308 writer.write<uint8_t>(Flags);1309 1310 if (auto Copyable = TI.isSwiftCopyable())1311 writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);1312 else1313 writer.write<uint8_t>(0);1314 1315 if (auto Escapable = TI.isSwiftEscapable())1316 writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);1317 else1318 writer.write<uint8_t>(0);1319 1320 if (auto ImportAs = TI.SwiftImportAs) {1321 writer.write<uint16_t>(ImportAs->size() + 1);1322 OS.write(ImportAs->c_str(), ImportAs->size());1323 } else {1324 writer.write<uint16_t>(0);1325 }1326 if (auto RetainOp = TI.SwiftRetainOp) {1327 writer.write<uint16_t>(RetainOp->size() + 1);1328 OS.write(RetainOp->c_str(), RetainOp->size());1329 } else {1330 writer.write<uint16_t>(0);1331 }1332 if (auto ReleaseOp = TI.SwiftReleaseOp) {1333 writer.write<uint16_t>(ReleaseOp->size() + 1);1334 OS.write(ReleaseOp->c_str(), ReleaseOp->size());1335 } else {1336 writer.write<uint16_t>(0);1337 }1338 if (auto DefaultOwnership = TI.SwiftDefaultOwnership) {1339 writer.write<uint16_t>(DefaultOwnership->size() + 1);1340 OS.write(DefaultOwnership->c_str(), DefaultOwnership->size());1341 } else {1342 writer.write<uint16_t>(0);1343 }1344 if (auto DestroyOp = TI.SwiftDestroyOp) {1345 writer.write<uint16_t>(DestroyOp->size() + 1);1346 OS.write(DestroyOp->c_str(), DestroyOp->size());1347 } else {1348 writer.write<uint16_t>(0);1349 }1350 1351 emitCommonTypeInfo(OS, TI);1352 }1353};1354} // namespace1355 1356void APINotesWriter::Implementation::writeTagBlock(1357 llvm::BitstreamWriter &Stream) {1358 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);1359 1360 if (Tags.empty())1361 return;1362 1363 {1364 llvm::SmallString<4096> HashTableBlob;1365 uint32_t Offset;1366 {1367 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;1368 for (auto &T : Tags)1369 Generator.insert(T.first, T.second);1370 1371 llvm::raw_svector_ostream BlobStream(HashTableBlob);1372 // Make sure that no bucket is at offset 01373 llvm::support::endian::write<uint32_t>(BlobStream, 0,1374 llvm::endianness::little);1375 Offset = Generator.Emit(BlobStream);1376 }1377 1378 tag_block::TagDataLayout TagData(Stream);1379 TagData.emit(Scratch, Offset, HashTableBlob);1380 }1381}1382 1383namespace {1384/// Used to serialize the on-disk typedef table.1385class TypedefTableInfo1386 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {1387public:1388 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {1389 return 1 + getCommonTypeInfoSize(TI);1390 }1391 1392 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {1393 llvm::support::endian::Writer writer(OS, llvm::endianness::little);1394 1395 uint8_t Flags = 0;1396 if (auto swiftWrapper = TI.SwiftWrapper)1397 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;1398 1399 writer.write<uint8_t>(Flags);1400 1401 emitCommonTypeInfo(OS, TI);1402 }1403};1404} // namespace1405 1406void APINotesWriter::Implementation::writeTypedefBlock(1407 llvm::BitstreamWriter &Stream) {1408 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);1409 1410 if (Typedefs.empty())1411 return;1412 1413 {1414 llvm::SmallString<4096> HashTableBlob;1415 uint32_t Offset;1416 {1417 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;1418 for (auto &T : Typedefs)1419 Generator.insert(T.first, T.second);1420 1421 llvm::raw_svector_ostream BlobStream(HashTableBlob);1422 // Make sure that no bucket is at offset 01423 llvm::support::endian::write<uint32_t>(BlobStream, 0,1424 llvm::endianness::little);1425 Offset = Generator.Emit(BlobStream);1426 }1427 1428 typedef_block::TypedefDataLayout TypedefData(Stream);1429 TypedefData.emit(Scratch, Offset, HashTableBlob);1430 }1431}1432 1433// APINotesWriter1434 1435APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)1436 : Implementation(new class Implementation(ModuleName, SF)) {}1437 1438APINotesWriter::~APINotesWriter() = default;1439 1440void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {1441 Implementation->writeToStream(OS);1442}1443 1444ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,1445 llvm::StringRef Name, ContextKind Kind,1446 const ContextInfo &Info,1447 llvm::VersionTuple SwiftVersion) {1448 IdentifierID NameID = Implementation->getIdentifier(Name);1449 1450 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;1451 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);1452 auto Known = Implementation->Contexts.find(Key);1453 if (Known == Implementation->Contexts.end()) {1454 unsigned NextID = Implementation->Contexts.size() + 1;1455 1456 Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;1457 Known = Implementation->Contexts1458 .insert(std::make_pair(1459 Key, std::make_pair(NextID, EmptyVersionedInfo)))1460 .first;1461 1462 Implementation->ContextNames[NextID] = NameID;1463 Implementation->ParentContexts[NextID] = RawParentCtxID;1464 }1465 1466 // Add this version information.1467 auto &VersionedVec = Known->second.second;1468 bool Found = false;1469 for (auto &Versioned : VersionedVec) {1470 if (Versioned.first == SwiftVersion) {1471 Versioned.second |= Info;1472 Found = true;1473 break;1474 }1475 }1476 1477 if (!Found)1478 VersionedVec.push_back({SwiftVersion, Info});1479 1480 return ContextID(Known->second.first);1481}1482 1483void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,1484 bool IsInstanceProperty,1485 const ObjCPropertyInfo &Info,1486 VersionTuple SwiftVersion) {1487 IdentifierID NameID = Implementation->getIdentifier(Name);1488 Implementation1489 ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]1490 .push_back({SwiftVersion, Info});1491}1492 1493void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,1494 bool IsInstanceMethod,1495 const ObjCMethodInfo &Info,1496 VersionTuple SwiftVersion) {1497 SelectorID SelID = Implementation->getSelector(Selector);1498 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,1499 IsInstanceMethod};1500 Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});1501 1502 // If this method is a designated initializer, update the class to note that1503 // it has designated initializers.1504 if (Info.DesignatedInit) {1505 assert(Implementation->ParentContexts.contains(CtxID.Value));1506 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];1507 ContextTableKey CtxKey(ParentCtxID,1508 static_cast<uint8_t>(ContextKind::ObjCClass),1509 Implementation->ContextNames[CtxID.Value]);1510 assert(Implementation->Contexts.contains(CtxKey));1511 auto &VersionedVec = Implementation->Contexts[CtxKey].second;1512 bool Found = false;1513 for (auto &Versioned : VersionedVec) {1514 if (Versioned.first == SwiftVersion) {1515 Versioned.second.setHasDesignatedInits(true);1516 Found = true;1517 break;1518 }1519 }1520 1521 if (!Found) {1522 VersionedVec.push_back({SwiftVersion, ContextInfo()});1523 VersionedVec.back().second.setHasDesignatedInits(true);1524 }1525 }1526}1527 1528void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,1529 const CXXMethodInfo &Info,1530 VersionTuple SwiftVersion) {1531 IdentifierID NameID = Implementation->getIdentifier(Name);1532 SingleDeclTableKey Key(CtxID.Value, NameID);1533 Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});1534}1535 1536void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,1537 const FieldInfo &Info,1538 VersionTuple SwiftVersion) {1539 IdentifierID NameID = Implementation->getIdentifier(Name);1540 SingleDeclTableKey Key(CtxID.Value, NameID);1541 Implementation->Fields[Key].push_back({SwiftVersion, Info});1542}1543 1544void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,1545 llvm::StringRef Name,1546 const GlobalVariableInfo &Info,1547 VersionTuple SwiftVersion) {1548 IdentifierID VariableID = Implementation->getIdentifier(Name);1549 SingleDeclTableKey Key(Ctx, VariableID);1550 Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});1551}1552 1553void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,1554 llvm::StringRef Name,1555 const GlobalFunctionInfo &Info,1556 VersionTuple SwiftVersion) {1557 IdentifierID NameID = Implementation->getIdentifier(Name);1558 SingleDeclTableKey Key(Ctx, NameID);1559 Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});1560}1561 1562void APINotesWriter::addEnumConstant(llvm::StringRef Name,1563 const EnumConstantInfo &Info,1564 VersionTuple SwiftVersion) {1565 IdentifierID EnumConstantID = Implementation->getIdentifier(Name);1566 Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});1567}1568 1569void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,1570 const TagInfo &Info, VersionTuple SwiftVersion) {1571 IdentifierID TagID = Implementation->getIdentifier(Name);1572 SingleDeclTableKey Key(Ctx, TagID);1573 Implementation->Tags[Key].push_back({SwiftVersion, Info});1574}1575 1576void APINotesWriter::addTypedef(std::optional<Context> Ctx,1577 llvm::StringRef Name, const TypedefInfo &Info,1578 VersionTuple SwiftVersion) {1579 IdentifierID TypedefID = Implementation->getIdentifier(Name);1580 SingleDeclTableKey Key(Ctx, TypedefID);1581 Implementation->Typedefs[Key].push_back({SwiftVersion, Info});1582}1583} // namespace api_notes1584} // namespace clang1585