brintos

brintos / llvm-project-archived public Read only

0
0
Text · 51.4 KiB · 47ed93a Raw
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