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