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