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