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<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>,
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 /// Information about C++ methods.
74 ///
75 /// Indexed by the context ID and name ID.
76 llvm::DenseMap<SingleDeclTableKey,
77 llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
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<
87 SingleDeclTableKey,
88 llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
89 GlobalVariables;
90
91 /// Information about global functions.
92 ///
93 /// Indexed by the context ID, identifier ID.
94 llvm::DenseMap<
95 SingleDeclTableKey,
96 llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
97 GlobalFunctions;
98
99 /// Information about enumerators.
100 ///
101 /// Indexed by the identifier ID.
102 llvm::DenseMap<
103 unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
104 EnumConstants;
105
106 /// Information about tags.
107 ///
108 /// Indexed by the context ID, identifier ID.
109 llvm::DenseMap<SingleDeclTableKey,
110 llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
111 Tags;
112
113 /// Information about typedefs.
114 ///
115 /// Indexed by the context ID, identifier ID.
116 llvm::DenseMap<SingleDeclTableKey,
117 llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
118 Typedefs;
119
120 /// Retrieve the ID for the given identifier.
121 IdentifierID getIdentifier(StringRef Identifier) {
122 if (Identifier.empty())
123 return 0;
124
125 auto Known = IdentifierIDs.find(Key: Identifier);
126 if (Known != IdentifierIDs.end())
127 return Known->second;
128
129 // Add to the identifier table.
130 Known = IdentifierIDs.insert(KV: {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.
137 StoredObjCSelector Selector;
138 Selector.NumArgs = SelectorRef.NumArgs;
139 Selector.Identifiers.reserve(N: SelectorRef.Identifiers.size());
140 for (auto piece : SelectorRef.Identifiers)
141 Selector.Identifiers.push_back(Elt: getIdentifier(Identifier: piece));
142
143 // Look for the stored selector.
144 auto Known = SelectorIDs.find(Val: Selector);
145 if (Known != SelectorIDs.end())
146 return Known->second;
147
148 // Add to the selector table.
149 Known = SelectorIDs.insert(KV: {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
175void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
176 llvm::SmallVector<char, 0> Buffer;
177
178 {
179 llvm::BitstreamWriter Stream(Buffer);
180
181 // Emit the signature.
182 for (unsigned char Byte : API_NOTES_SIGNATURE)
183 Stream.Emit(Val: Byte, NumBits: 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(Ptr: Buffer.data(), Size: 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(Code: llvm::bitc::BLOCKINFO_CODE_SETBID,
210 Vals: llvm::ArrayRef<unsigned>{ID});
211
212 // Emit the block name if present.
213 if (Name.empty())
214 return;
215 Stream.EmitRecord(
216 Code: llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
217 Vals: llvm::ArrayRef<unsigned char>(
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
228 llvm::SmallVector<unsigned char, 64> Buffer;
229 Buffer.resize(N: Name.size() + 1);
230 Buffer[0] = ID;
231 memcpy(dest: Buffer.data() + 1, src: Name.data(), n: Name.size());
232
233 Stream.EmitRecord(Code: llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Vals: 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(buffer&: Scratch, data: VERSION_MAJOR, data: VERSION_MINOR);
278
279 control_block::ModuleNameLayout ModuleName(Stream);
280 ModuleName.emit(buffer&: Scratch, data&: this->ModuleName);
281
282 if (SourceFile) {
283 control_block::SourceFileLayout SourceFile(Stream);
284 SourceFile.emit(buffer&: Scratch, data: this->SourceFile->getSize(),
285 data: 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(Buffer: 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>(Val: KeyLength);
309 writer.write<uint16_t>(Val: 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>(Val: 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(Key: II.first(), Data: 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>(os&: BlobStream, value: 0,
339 endian: llvm::endianness::little);
340 Offset = Generator.Emit(Out&: BlobStream);
341 }
342
343 identifier_block::IdentifierDataLayout IdentifierData(Stream);
344 IdentifierData.emit(buffer&: Scratch, data&: Offset, data&: 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>(Val: KeyLength);
369 writer.write<uint16_t>(Val: 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>(Val: Key.parentContextID);
376 writer.write<uint8_t>(Val: Key.contextKind);
377 writer.write<uint32_t>(Val: 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>(Val: 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>(Val: descriptor);
432
433 // Write the components.
434 writer.write<uint32_t>(Val: VT.getMajor());
435 if (auto minor = VT.getMinor())
436 writer.write<uint32_t>(Val: *minor);
437 if (auto subminor = VT.getSubminor())
438 writer.write<uint32_t>(Val: *subminor);
439 if (auto build = VT.getBuild())
440 writer.write<uint32_t>(Val: *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 =
479 llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
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>(Val: KeyLength);
494 writer.write<uint16_t>(Val: 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>(Val: payload);
522
523 writer.write<uint16_t>(Val: CEI.UnavailableMsg.size());
524 OS.write(Ptr: CEI.UnavailableMsg.c_str(), Size: CEI.UnavailableMsg.size());
525
526 writer.write<uint16_t>(Val: CEI.SwiftName.size());
527 OS.write(Ptr: CEI.SwiftName.c_str(), Size: 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(CEI: CTI);
542}
543
544/// Emit a serialized representation of the common type information.
545void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
546 emitCommonEntityInfo(OS, CEI: CTI);
547
548 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
549 if (auto swiftBridge = CTI.getSwiftBridge()) {
550 writer.write<uint16_t>(Val: swiftBridge->size() + 1);
551 OS.write(Ptr: swiftBridge->c_str(), Size: swiftBridge->size());
552 } else {
553 writer.write<uint16_t>(Val: 0);
554 }
555 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
556 writer.write<uint16_t>(Val: nsErrorDomain->size() + 1);
557 OS.write(Ptr: nsErrorDomain->c_str(), Size: CTI.getNSErrorDomain()->size());
558 } else {
559 writer.write<uint16_t>(Val: 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>(Val: Key);
572 }
573
574 hash_value_type ComputeHash(key_type_ref Key) {
575 return static_cast<size_t>(llvm::hash_value(value: Key));
576 }
577
578 unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
579 return getCommonTypeInfoSize(CTI: OCI) + 1;
580 }
581
582 void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
583 emitCommonTypeInfo(OS, CTI: 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(Key: OC.first, Data: 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>(os&: BlobStream, value: 0,
619 endian: llvm::endianness::little);
620 Offset = Generator.Emit(Out&: BlobStream);
621 }
622
623 context_block::ContextIDLayout ContextID(Stream);
624 ContextID.emit(buffer&: Scratch, data&: Offset, data&: 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(Key: OC.second.first, Data&: 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>(os&: BlobStream, value: 0,
638 endian: llvm::endianness::little);
639 Offset = Generator.Emit(Out&: BlobStream);
640 }
641
642 context_block::ContextInfoLayout ContextInfo(Stream);
643 ContextInfo.emit(buffer&: Scratch, data&: Offset, data&: 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(CEI: 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, CEI: 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(Ptr: reinterpret_cast<const char *>(bytes), Size: 2);
667
668 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
669 writer.write<uint16_t>(Val: VI.getType().size());
670 OS.write(Ptr: VI.getType().data(), Size: 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>(Val: std::get<0>(t&: Key));
686 writer.write<uint32_t>(Val: std::get<1>(t&: Key));
687 writer.write<uint8_t>(Val: std::get<2>(t&: Key));
688 }
689
690 hash_value_type ComputeHash(key_type_ref Key) {
691 return static_cast<size_t>(llvm::hash_value(arg: Key));
692 }
693
694 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
695 return getVariableInfoSize(VI: OPI) + 1;
696 }
697
698 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
699 emitVariableInfo(OS, VI: 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(Key: OP.first, Data&: 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>(os&: BlobStream, value: 0,
729 endian: llvm::endianness::little);
730 Offset = Generator.Emit(Out&: BlobStream);
731 }
732
733 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
734 ObjCPropertyData.emit(buffer&: Scratch, data&: Offset, data&: 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>(Val: std::get<0>(t&: Key));
755 writer.write<uint32_t>(Val: std::get<1>(t&: Key));
756 writer.write<uint8_t>(Val: std::get<2>(t&: Key));
757 }
758
759 hash_value_type ComputeHash(key_type_ref key) {
760 return static_cast<size_t>(llvm::hash_value(arg: 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>(Val: 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>(Val: Key.parentContextID);
790 writer.write<uint32_t>(Val: 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(Key: OM.first, Data&: 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>(os&: BlobStream, value: 0,
825 endian: llvm::endianness::little);
826 Offset = Generator.Emit(Out&: BlobStream);
827 }
828
829 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
830 ObjCMethodData.emit(buffer&: Scratch, data&: Offset, data&: 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(Key: MD.first, Data&: 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>(os&: BlobStream, value: 0,
852 endian: llvm::endianness::little);
853 Offset = Generator.Emit(Out&: BlobStream);
854 }
855
856 cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
857 CXXMethodData.emit(buffer&: Scratch, data&: Offset, data&: 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(Selector: 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>(Val: KeyLength);
884 writer.write<uint16_t>(Val: 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>(Val: Key.NumArgs);
891 for (auto Identifier : Key.Identifiers)
892 writer.write<uint32_t>(Val: 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>(Val: 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(Key: S.first, Data: 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>(os&: BlobStream, value: 0,
920 endian: llvm::endianness::little);
921 Offset = Generator.Emit(Out&: BlobStream);
922 }
923
924 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
925 ObjCSelectorData.emit(buffer&: Scratch, data&: Offset, data&: 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>(Val: Key.parentContextID);
942 writer.write<uint32_t>(Val: 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(VI: GVI);
951 }
952
953 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
954 emitVariableInfo(OS, VI: 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(Key: GV.first, Data&: 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>(os&: BlobStream, value: 0,
977 endian: llvm::endianness::little);
978 Offset = Generator.Emit(Out&: BlobStream);
979 }
980
981 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
982 GlobalVariableData.emit(buffer&: Scratch, data&: Offset, data&: HashTableBlob);
983 }
984}
985
986namespace {
987unsigned getParamInfoSize(const ParamInfo &PI) {
988 return getVariableInfoSize(VI: PI) + 1;
989}
990
991void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
992 emitVariableInfo(OS, VI: 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>(Val: 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(CEI: FI) + 2 + sizeof(uint64_t);
1012 size += sizeof(uint16_t);
1013 for (const auto &P : FI.Params)
1014 size += getParamInfoSize(PI: 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, CEI: 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>(Val: flags);
1032 writer.write<uint8_t>(Val: FI.NumAdjustedNullable);
1033 writer.write<uint64_t>(Val: FI.NullabilityPayload);
1034
1035 writer.write<uint16_t>(Val: FI.Params.size());
1036 for (const auto &PI : FI.Params)
1037 emitParamInfo(OS, PI);
1038
1039 writer.write<uint16_t>(Val: FI.ResultType.size());
1040 writer.write(Val: 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>(Val: Key.parentContextID);
1055 writer.write<uint32_t>(Val: 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(FI: GFI);
1064 }
1065
1066 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1067 emitFunctionInfo(OS, FI: 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(Key: F.first, Data&: 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>(os&: BlobStream, value: 0,
1090 endian: llvm::endianness::little);
1091 Offset = Generator.Emit(Out&: BlobStream);
1092 }
1093
1094 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1095 GlobalFunctionData.emit(buffer&: Scratch, data&: Offset, data&: 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>(Val: Key);
1110 }
1111
1112 hash_value_type ComputeHash(key_type_ref Key) {
1113 return static_cast<size_t>(llvm::hash_value(value: Key));
1114 }
1115
1116 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1117 return getCommonEntityInfoSize(CEI: ECI);
1118 }
1119
1120 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1121 emitCommonEntityInfo(OS, CEI: 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(Key: EC.first, Data&: 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>(os&: BlobStream, value: 0,
1144 endian: llvm::endianness::little);
1145 Offset = Generator.Emit(Out&: BlobStream);
1146 }
1147
1148 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1149 EnumConstantData.emit(buffer&: Scratch, data&: Offset, data&: 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 + getCommonTypeInfoSize(CTI: TI);
1193 }
1194
1195 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1196 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1197
1198 uint8_t Flags = 0;
1199 if (auto extensibility = TI.EnumExtensibility) {
1200 Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
1201 assert((Flags < (1 << 2)) && "must fit in two bits");
1202 }
1203
1204 Flags <<= 2;
1205 if (auto value = TI.isFlagEnum())
1206 Flags |= (value.value() << 1 | 1 << 0);
1207
1208 writer.write<uint8_t>(Val: Flags);
1209
1210 if (auto Copyable = TI.isSwiftCopyable())
1211 writer.write<uint8_t>(Val: *Copyable ? kSwiftCopyable : kSwiftNonCopyable);
1212 else
1213 writer.write<uint8_t>(Val: 0);
1214
1215 if (auto ImportAs = TI.SwiftImportAs) {
1216 writer.write<uint16_t>(Val: ImportAs->size() + 1);
1217 OS.write(Ptr: ImportAs->c_str(), Size: ImportAs->size());
1218 } else {
1219 writer.write<uint16_t>(Val: 0);
1220 }
1221 if (auto RetainOp = TI.SwiftRetainOp) {
1222 writer.write<uint16_t>(Val: RetainOp->size() + 1);
1223 OS.write(Ptr: RetainOp->c_str(), Size: RetainOp->size());
1224 } else {
1225 writer.write<uint16_t>(Val: 0);
1226 }
1227 if (auto ReleaseOp = TI.SwiftReleaseOp) {
1228 writer.write<uint16_t>(Val: ReleaseOp->size() + 1);
1229 OS.write(Ptr: ReleaseOp->c_str(), Size: ReleaseOp->size());
1230 } else {
1231 writer.write<uint16_t>(Val: 0);
1232 }
1233
1234 emitCommonTypeInfo(OS, CTI: TI);
1235 }
1236};
1237} // namespace
1238
1239void APINotesWriter::Implementation::writeTagBlock(
1240 llvm::BitstreamWriter &Stream) {
1241 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1242
1243 if (Tags.empty())
1244 return;
1245
1246 {
1247 llvm::SmallString<4096> HashTableBlob;
1248 uint32_t Offset;
1249 {
1250 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1251 for (auto &T : Tags)
1252 Generator.insert(Key: T.first, Data&: T.second);
1253
1254 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1255 // Make sure that no bucket is at offset 0
1256 llvm::support::endian::write<uint32_t>(os&: BlobStream, value: 0,
1257 endian: llvm::endianness::little);
1258 Offset = Generator.Emit(Out&: BlobStream);
1259 }
1260
1261 tag_block::TagDataLayout TagData(Stream);
1262 TagData.emit(buffer&: Scratch, data&: Offset, data&: HashTableBlob);
1263 }
1264}
1265
1266namespace {
1267/// Used to serialize the on-disk typedef table.
1268class TypedefTableInfo
1269 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1270public:
1271 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1272 return 1 + getCommonTypeInfoSize(CTI: TI);
1273 }
1274
1275 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1276 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1277
1278 uint8_t Flags = 0;
1279 if (auto swiftWrapper = TI.SwiftWrapper)
1280 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1281
1282 writer.write<uint8_t>(Val: Flags);
1283
1284 emitCommonTypeInfo(OS, CTI: TI);
1285 }
1286};
1287} // namespace
1288
1289void APINotesWriter::Implementation::writeTypedefBlock(
1290 llvm::BitstreamWriter &Stream) {
1291 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1292
1293 if (Typedefs.empty())
1294 return;
1295
1296 {
1297 llvm::SmallString<4096> HashTableBlob;
1298 uint32_t Offset;
1299 {
1300 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1301 for (auto &T : Typedefs)
1302 Generator.insert(Key: T.first, Data&: T.second);
1303
1304 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1305 // Make sure that no bucket is at offset 0
1306 llvm::support::endian::write<uint32_t>(os&: BlobStream, value: 0,
1307 endian: llvm::endianness::little);
1308 Offset = Generator.Emit(Out&: BlobStream);
1309 }
1310
1311 typedef_block::TypedefDataLayout TypedefData(Stream);
1312 TypedefData.emit(buffer&: Scratch, data&: Offset, data&: HashTableBlob);
1313 }
1314}
1315
1316// APINotesWriter
1317
1318APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1319 : Implementation(new class Implementation(ModuleName, SF)) {}
1320
1321APINotesWriter::~APINotesWriter() = default;
1322
1323void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1324 Implementation->writeToStream(OS);
1325}
1326
1327ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1328 llvm::StringRef Name, ContextKind Kind,
1329 const ContextInfo &Info,
1330 llvm::VersionTuple SwiftVersion) {
1331 IdentifierID NameID = Implementation->getIdentifier(Identifier: Name);
1332
1333 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1334 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1335 auto Known = Implementation->Contexts.find(Val: Key);
1336 if (Known == Implementation->Contexts.end()) {
1337 unsigned NextID = Implementation->Contexts.size() + 1;
1338
1339 Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;
1340 Known = Implementation->Contexts
1341 .insert(KV: std::make_pair(
1342 x&: Key, y: std::make_pair(x&: NextID, y&: EmptyVersionedInfo)))
1343 .first;
1344
1345 Implementation->ContextNames[NextID] = NameID;
1346 Implementation->ParentContexts[NextID] = RawParentCtxID;
1347 }
1348
1349 // Add this version information.
1350 auto &VersionedVec = Known->second.second;
1351 bool Found = false;
1352 for (auto &Versioned : VersionedVec) {
1353 if (Versioned.first == SwiftVersion) {
1354 Versioned.second |= Info;
1355 Found = true;
1356 break;
1357 }
1358 }
1359
1360 if (!Found)
1361 VersionedVec.push_back(Elt: {SwiftVersion, Info});
1362
1363 return ContextID(Known->second.first);
1364}
1365
1366void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
1367 bool IsInstanceProperty,
1368 const ObjCPropertyInfo &Info,
1369 VersionTuple SwiftVersion) {
1370 IdentifierID NameID = Implementation->getIdentifier(Identifier: Name);
1371 Implementation
1372 ->ObjCProperties[std::make_tuple(args&: CtxID.Value, args&: NameID, args&: IsInstanceProperty)]
1373 .push_back(Elt: {SwiftVersion, Info});
1374}
1375
1376void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
1377 bool IsInstanceMethod,
1378 const ObjCMethodInfo &Info,
1379 VersionTuple SwiftVersion) {
1380 SelectorID SelID = Implementation->getSelector(SelectorRef: Selector);
1381 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1382 IsInstanceMethod};
1383 Implementation->ObjCMethods[Key].push_back(Elt: {SwiftVersion, Info});
1384
1385 // If this method is a designated initializer, update the class to note that
1386 // it has designated initializers.
1387 if (Info.DesignatedInit) {
1388 assert(Implementation->ParentContexts.contains(CtxID.Value));
1389 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1390 ContextTableKey CtxKey(ParentCtxID,
1391 static_cast<uint8_t>(ContextKind::ObjCClass),
1392 Implementation->ContextNames[CtxID.Value]);
1393 assert(Implementation->Contexts.contains(CtxKey));
1394 auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1395 bool Found = false;
1396 for (auto &Versioned : VersionedVec) {
1397 if (Versioned.first == SwiftVersion) {
1398 Versioned.second.setHasDesignatedInits(true);
1399 Found = true;
1400 break;
1401 }
1402 }
1403
1404 if (!Found) {
1405 VersionedVec.push_back(Elt: {SwiftVersion, ContextInfo()});
1406 VersionedVec.back().second.setHasDesignatedInits(true);
1407 }
1408 }
1409}
1410
1411void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1412 const CXXMethodInfo &Info,
1413 VersionTuple SwiftVersion) {
1414 IdentifierID NameID = Implementation->getIdentifier(Identifier: Name);
1415 SingleDeclTableKey Key(CtxID.Value, NameID);
1416 Implementation->CXXMethods[Key].push_back(Elt: {SwiftVersion, Info});
1417}
1418
1419void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1420 llvm::StringRef Name,
1421 const GlobalVariableInfo &Info,
1422 VersionTuple SwiftVersion) {
1423 IdentifierID VariableID = Implementation->getIdentifier(Identifier: Name);
1424 SingleDeclTableKey Key(Ctx, VariableID);
1425 Implementation->GlobalVariables[Key].push_back(Elt: {SwiftVersion, Info});
1426}
1427
1428void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1429 llvm::StringRef Name,
1430 const GlobalFunctionInfo &Info,
1431 VersionTuple SwiftVersion) {
1432 IdentifierID NameID = Implementation->getIdentifier(Identifier: Name);
1433 SingleDeclTableKey Key(Ctx, NameID);
1434 Implementation->GlobalFunctions[Key].push_back(Elt: {SwiftVersion, Info});
1435}
1436
1437void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1438 const EnumConstantInfo &Info,
1439 VersionTuple SwiftVersion) {
1440 IdentifierID EnumConstantID = Implementation->getIdentifier(Identifier: Name);
1441 Implementation->EnumConstants[EnumConstantID].push_back(Elt: {SwiftVersion, Info});
1442}
1443
1444void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1445 const TagInfo &Info, VersionTuple SwiftVersion) {
1446 IdentifierID TagID = Implementation->getIdentifier(Identifier: Name);
1447 SingleDeclTableKey Key(Ctx, TagID);
1448 Implementation->Tags[Key].push_back(Elt: {SwiftVersion, Info});
1449}
1450
1451void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1452 llvm::StringRef Name, const TypedefInfo &Info,
1453 VersionTuple SwiftVersion) {
1454 IdentifierID TypedefID = Implementation->getIdentifier(Identifier: Name);
1455 SingleDeclTableKey Key(Ctx, TypedefID);
1456 Implementation->Typedefs[Key].push_back(Elt: {SwiftVersion, Info});
1457}
1458} // namespace api_notes
1459} // namespace clang
1460