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