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

source code of clang/lib/APINotes/APINotesWriter.cpp