clang 22.0.0git
APINotesWriter.cpp
Go to the documentation of this file.
1//===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "APINotesFormat.h"
13#include "llvm/ADT/DenseMap.h"
14#include "llvm/ADT/StringMap.h"
15#include "llvm/Bitstream/BitstreamWriter.h"
16#include "llvm/Support/DJB.h"
17#include "llvm/Support/OnDiskHashTable.h"
18#include "llvm/Support/VersionTuple.h"
19
20namespace clang {
21namespace api_notes {
23 friend class APINotesWriter;
24
25 template <typename T>
28
29 std::string ModuleName;
30 const FileEntry *SourceFile;
31
32 /// Scratch space for bitstream writing.
34
35 /// Mapping from strings to identifier IDs.
36 llvm::StringMap<IdentifierID> IdentifierIDs;
37
38 /// Information about contexts (Objective-C classes or protocols or C++
39 /// namespaces).
40 ///
41 /// Indexed by the parent context ID, context kind and the identifier ID of
42 /// this context and provides both the context ID and information describing
43 /// the context within that module.
44 llvm::DenseMap<ContextTableKey,
45 std::pair<unsigned, VersionedSmallVector<ContextInfo>>>
46 Contexts;
47
48 /// Information about parent contexts for each context.
49 ///
50 /// Indexed by context ID, provides the parent context ID.
51 llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
52
53 /// Mapping from context IDs to the identifier ID holding the name.
54 llvm::DenseMap<unsigned, unsigned> ContextNames;
55
56 /// Information about Objective-C properties.
57 ///
58 /// Indexed by the context ID, property name, and whether this is an
59 /// instance property.
60 llvm::DenseMap<
61 std::tuple<unsigned, unsigned, char>,
63 ObjCProperties;
64
65 /// Information about C record fields.
66 ///
67 /// Indexed by the context ID and name ID.
68 llvm::DenseMap<SingleDeclTableKey,
70 Fields;
71
72 /// Information about Objective-C methods.
73 ///
74 /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
75 /// indicating whether this is a class or instance method.
76 llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
78 ObjCMethods;
79
80 /// Information about C++ methods.
81 ///
82 /// Indexed by the context ID and name ID.
83 llvm::DenseMap<SingleDeclTableKey,
85 CXXMethods;
86
87 /// Mapping from selectors to selector ID.
88 llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
89
90 /// Information about global variables.
91 ///
92 /// Indexed by the context ID, identifier ID.
93 llvm::DenseMap<
96 GlobalVariables;
97
98 /// Information about global functions.
99 ///
100 /// Indexed by the context ID, identifier ID.
101 llvm::DenseMap<
104 GlobalFunctions;
105
106 /// Information about enumerators.
107 ///
108 /// Indexed by the identifier ID.
109 llvm::DenseMap<
111 EnumConstants;
112
113 /// Information about tags.
114 ///
115 /// Indexed by the context ID, identifier ID.
116 llvm::DenseMap<SingleDeclTableKey,
118 Tags;
119
120 /// Information about typedefs.
121 ///
122 /// Indexed by the context ID, identifier ID.
123 llvm::DenseMap<SingleDeclTableKey,
125 Typedefs;
126
127 /// Retrieve the ID for the given identifier.
129 if (Identifier.empty())
130 return 0;
131
132 // Add to the identifier table if missing.
133 return IdentifierIDs.try_emplace(Identifier, 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.
141 Selector.NumArgs = SelectorRef.NumArgs;
142 Selector.Identifiers.reserve(SelectorRef.Identifiers.size());
143 for (auto piece : SelectorRef.Identifiers)
144 Selector.Identifiers.push_back(getIdentifier(piece));
145
146 // Look for the stored selector. Add to the selector table if missing.
147 return SelectorIDs.try_emplace(Selector, 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
175
176 {
177 llvm::BitstreamWriter Stream(Buffer);
178
179 // Emit the signature.
180 for (unsigned char Byte : API_NOTES_SIGNATURE)
181 Stream.Emit(Byte, 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(Buffer.data(), 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(llvm::bitc::BLOCKINFO_CODE_SETBID,
210
211 // Emit the block name if present.
212 if (Name.empty())
213 return;
214 Stream.EmitRecord(
215 llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
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
228 Buffer.resize(Name.size() + 1);
229 Buffer[0] = ID;
230 memcpy(Buffer.data() + 1, Name.data(), Name.size());
231
232 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, 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(Scratch, VERSION_MAJOR, VERSION_MINOR);
277
278 control_block::ModuleNameLayout ModuleName(Stream);
279 ModuleName.emit(Scratch, this->ModuleName);
280
281 if (SourceFile) {
282 control_block::SourceFileLayout SourceFile(Stream);
283 SourceFile.emit(Scratch, this->SourceFile->getSize(),
284 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(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>(KeyLength);
308 writer.write<uint16_t>(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>(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(II.first(), 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>(BlobStream, 0,
338 llvm::endianness::little);
339 Offset = Generator.Emit(BlobStream);
340 }
341
342 identifier_block::IdentifierDataLayout IdentifierData(Stream);
343 IdentifierData.emit(Scratch, Offset, 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>(KeyLength);
368 writer.write<uint16_t>(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>(Key.parentContextID);
375 writer.write<uint8_t>(Key.contextKind);
376 writer.write<uint32_t>(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>(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>(descriptor);
431
432 // Write the components.
433 writer.write<uint32_t>(VT.getMajor());
434 if (auto minor = VT.getMinor())
435 writer.write<uint32_t>(*minor);
436 if (auto subminor = VT.getSubminor())
437 writer.write<uint32_t>(*subminor);
438 if (auto build = VT.getBuild())
439 writer.write<uint32_t>(*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 =
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>(KeyLength);
493 writer.write<uint16_t>(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 swiftPrivate = CEI.isSwiftPrivate()) {
511 payload |= 0x01;
512 if (*swiftPrivate)
513 payload |= 0x02;
514 }
515 payload <<= 1;
516 payload |= CEI.Unavailable;
517 payload <<= 1;
518 payload |= CEI.UnavailableInSwift;
519
520 writer.write<uint8_t>(payload);
521
522 writer.write<uint16_t>(CEI.UnavailableMsg.size());
523 OS.write(CEI.UnavailableMsg.c_str(), CEI.UnavailableMsg.size());
524
525 writer.write<uint16_t>(CEI.SwiftName.size());
526 OS.write(CEI.SwiftName.c_str(), CEI.SwiftName.size());
527}
528
529/// Retrieve the serialized size of the given CommonEntityInfo, for use in
530/// on-disk hash tables.
531unsigned getCommonEntityInfoSize(const CommonEntityInfo &CEI) {
532 return 5 + CEI.UnavailableMsg.size() + CEI.SwiftName.size();
533}
534
535// Retrieve the serialized size of the given CommonTypeInfo, for use
536// in on-disk hash tables.
537unsigned getCommonTypeInfoSize(const CommonTypeInfo &CTI) {
538 return 2 + (CTI.getSwiftBridge() ? CTI.getSwiftBridge()->size() : 0) + 2 +
539 (CTI.getNSErrorDomain() ? CTI.getNSErrorDomain()->size() : 0) + 2 +
540 (CTI.getSwiftConformance() ? CTI.getSwiftConformance()->size() : 0) +
541 getCommonEntityInfoSize(CTI);
542}
543
544/// Emit a serialized representation of the common type information.
545void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
546 emitCommonEntityInfo(OS, CTI);
547
548 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
549 if (auto swiftBridge = CTI.getSwiftBridge()) {
550 writer.write<uint16_t>(swiftBridge->size() + 1);
551 OS.write(swiftBridge->c_str(), swiftBridge->size());
552 } else {
553 writer.write<uint16_t>(0);
554 }
555 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
556 writer.write<uint16_t>(nsErrorDomain->size() + 1);
557 OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
558 } else {
559 writer.write<uint16_t>(0);
560 }
561 if (auto conformance = CTI.getSwiftConformance()) {
562 writer.write<uint16_t>(conformance->size() + 1);
563 OS.write(conformance->c_str(), conformance->size());
564 } else {
565 writer.write<uint16_t>(0);
566 }
567}
568
569/// Used to serialize the on-disk Objective-C property table.
570class ContextInfoTableInfo
571 : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
572public:
573 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
574
575 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
576 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
577 writer.write<uint32_t>(Key);
578 }
579
580 hash_value_type ComputeHash(key_type_ref Key) {
581 return static_cast<size_t>(llvm::hash_value(Key));
582 }
583
584 unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
585 return getCommonTypeInfoSize(OCI) + 1;
586 }
587
588 void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
589 emitCommonTypeInfo(OS, OCI);
590
591 uint8_t payload = 0;
592 if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
593 payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
594 payload <<= 2;
595 if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
596 payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
597 payload <<= 3;
598 if (auto nullable = OCI.getDefaultNullability())
599 payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
600 payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
601
602 OS << payload;
603 }
604};
605} // namespace
606
607void APINotesWriter::Implementation::writeContextBlock(
608 llvm::BitstreamWriter &Stream) {
609 llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
610
611 if (Contexts.empty())
612 return;
613
614 {
615 llvm::SmallString<4096> HashTableBlob;
616 uint32_t Offset;
617 {
618 llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
619 for (auto &OC : Contexts)
620 Generator.insert(OC.first, OC.second.first);
621
622 llvm::raw_svector_ostream BlobStream(HashTableBlob);
623 // Make sure that no bucket is at offset 0
624 llvm::support::endian::write<uint32_t>(BlobStream, 0,
625 llvm::endianness::little);
626 Offset = Generator.Emit(BlobStream);
627 }
628
629 context_block::ContextIDLayout ContextID(Stream);
630 ContextID.emit(Scratch, Offset, HashTableBlob);
631 }
632
633 {
634 llvm::SmallString<4096> HashTableBlob;
635 uint32_t Offset;
636 {
637 llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
638 for (auto &OC : Contexts)
639 Generator.insert(OC.second.first, OC.second.second);
640
641 llvm::raw_svector_ostream BlobStream(HashTableBlob);
642 // Make sure that no bucket is at offset 0
643 llvm::support::endian::write<uint32_t>(BlobStream, 0,
644 llvm::endianness::little);
645 Offset = Generator.Emit(BlobStream);
646 }
647
648 context_block::ContextInfoLayout ContextInfo(Stream);
649 ContextInfo.emit(Scratch, Offset, HashTableBlob);
650 }
651}
652
653namespace {
654/// Retrieve the serialized size of the given VariableInfo, for use in
655/// on-disk hash tables.
656unsigned getVariableInfoSize(const VariableInfo &VI) {
657 return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
658}
659unsigned getParamInfoSize(const ParamInfo &PI);
660
661/// Emit a serialized representation of the variable information.
662void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
663 emitCommonEntityInfo(OS, VI);
664
665 uint8_t bytes[2] = {0, 0};
666 if (auto nullable = VI.getNullability()) {
667 bytes[0] = 1;
668 bytes[1] = static_cast<uint8_t>(*nullable);
669 } else {
670 // Nothing to do.
671 }
672
673 OS.write(reinterpret_cast<const char *>(bytes), 2);
674
675 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
676 writer.write<uint16_t>(VI.getType().size());
677 OS.write(VI.getType().data(), VI.getType().size());
678}
679
680/// Used to serialize the on-disk Objective-C property table.
681class ObjCPropertyTableInfo
682 : public VersionedTableInfo<ObjCPropertyTableInfo,
683 std::tuple<unsigned, unsigned, char>,
684 ObjCPropertyInfo> {
685public:
686 unsigned getKeyLength(key_type_ref) {
687 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
688 }
689
690 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
691 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
692 writer.write<uint32_t>(std::get<0>(Key));
693 writer.write<uint32_t>(std::get<1>(Key));
694 writer.write<uint8_t>(std::get<2>(Key));
695 }
696
697 hash_value_type ComputeHash(key_type_ref Key) {
698 return static_cast<size_t>(llvm::hash_value(Key));
699 }
700
701 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
702 return getVariableInfoSize(OPI) + 1;
703 }
704
705 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
706 emitVariableInfo(OS, OPI);
707
708 uint8_t flags = 0;
709 if (auto value = OPI.getSwiftImportAsAccessors()) {
710 flags |= 1 << 0;
711 flags |= value.value() << 1;
712 }
713 OS << flags;
714 }
715};
716} // namespace
717
718void APINotesWriter::Implementation::writeObjCPropertyBlock(
719 llvm::BitstreamWriter &Stream) {
720 llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
721
722 if (ObjCProperties.empty())
723 return;
724
725 {
726 llvm::SmallString<4096> HashTableBlob;
727 uint32_t Offset;
728 {
729 llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
730 for (auto &OP : ObjCProperties)
731 Generator.insert(OP.first, OP.second);
732
733 llvm::raw_svector_ostream BlobStream(HashTableBlob);
734 // Make sure that no bucket is at offset 0
735 llvm::support::endian::write<uint32_t>(BlobStream, 0,
736 llvm::endianness::little);
737 Offset = Generator.Emit(BlobStream);
738 }
739
740 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
741 ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
742 }
743}
744
745namespace {
746unsigned getFunctionInfoSize(const FunctionInfo &);
747void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
748void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);
749
750/// Used to serialize the on-disk Objective-C method table.
751class ObjCMethodTableInfo
752 : public VersionedTableInfo<ObjCMethodTableInfo,
753 std::tuple<unsigned, unsigned, char>,
754 ObjCMethodInfo> {
755public:
756 unsigned getKeyLength(key_type_ref) {
757 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
758 }
759
760 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
761 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
762 writer.write<uint32_t>(std::get<0>(Key));
763 writer.write<uint32_t>(std::get<1>(Key));
764 writer.write<uint8_t>(std::get<2>(Key));
765 }
766
767 hash_value_type ComputeHash(key_type_ref key) {
768 return static_cast<size_t>(llvm::hash_value(key));
769 }
770
771 unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
772 auto size = getFunctionInfoSize(OMI) + 1;
773 if (OMI.Self)
774 size += getParamInfoSize(*OMI.Self);
775 return size;
776 }
777
778 void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
779 uint8_t flags = 0;
780 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
781 flags = (flags << 1) | OMI.DesignatedInit;
782 flags = (flags << 1) | OMI.RequiredInit;
783 flags = (flags << 1) | static_cast<bool>(OMI.Self);
784 writer.write<uint8_t>(flags);
785
786 emitFunctionInfo(OS, OMI);
787
788 if (OMI.Self)
789 emitParamInfo(OS, *OMI.Self);
790 }
791};
792
793/// Used to serialize the on-disk C++ method table.
794class CXXMethodTableInfo
795 : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
796 CXXMethodInfo> {
797public:
798 unsigned getKeyLength(key_type_ref) {
799 return sizeof(uint32_t) + sizeof(uint32_t);
800 }
801
802 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
803 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
804 writer.write<uint32_t>(Key.parentContextID);
805 writer.write<uint32_t>(Key.nameID);
806 }
807
808 hash_value_type ComputeHash(key_type_ref key) {
809 return static_cast<size_t>(key.hashValue());
810 }
811
812 unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {
813 auto size = getFunctionInfoSize(MI) + 1;
814 if (MI.This)
815 size += getParamInfoSize(*MI.This);
816 return size;
817 }
818
819 void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {
820 uint8_t flags = 0;
821 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
822 flags = (flags << 1) | static_cast<bool>(MI.This);
823 writer.write<uint8_t>(flags);
824
825 emitFunctionInfo(OS, MI);
826 if (MI.This)
827 emitParamInfo(OS, *MI.This);
828 }
829};
830} // namespace
831
832void APINotesWriter::Implementation::writeObjCMethodBlock(
833 llvm::BitstreamWriter &Stream) {
834 llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
835
836 if (ObjCMethods.empty())
837 return;
838
839 {
840 llvm::SmallString<4096> HashTableBlob;
841 uint32_t Offset;
842 {
843 llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
844 for (auto &OM : ObjCMethods)
845 Generator.insert(OM.first, OM.second);
846
847 llvm::raw_svector_ostream BlobStream(HashTableBlob);
848 // Make sure that no bucket is at offset 0
849 llvm::support::endian::write<uint32_t>(BlobStream, 0,
850 llvm::endianness::little);
851 Offset = Generator.Emit(BlobStream);
852 }
853
854 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
855 ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
856 }
857}
858
859void APINotesWriter::Implementation::writeCXXMethodBlock(
860 llvm::BitstreamWriter &Stream) {
861 llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
862
863 if (CXXMethods.empty())
864 return;
865
866 {
867 llvm::SmallString<4096> HashTableBlob;
868 uint32_t Offset;
869 {
870 llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
871 for (auto &MD : CXXMethods)
872 Generator.insert(MD.first, MD.second);
873
874 llvm::raw_svector_ostream BlobStream(HashTableBlob);
875 // Make sure that no bucket is at offset 0
876 llvm::support::endian::write<uint32_t>(BlobStream, 0,
877 llvm::endianness::little);
878 Offset = Generator.Emit(BlobStream);
879 }
880
881 cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
882 CXXMethodData.emit(Scratch, Offset, HashTableBlob);
883 }
884}
885
886namespace {
887/// Used to serialize the on-disk C field table.
888class FieldTableInfo
889 : public VersionedTableInfo<FieldTableInfo, SingleDeclTableKey, FieldInfo> {
890public:
891 unsigned getKeyLength(key_type_ref) {
892 return sizeof(uint32_t) + sizeof(uint32_t);
893 }
894
895 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
896 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
897 writer.write<uint32_t>(Key.parentContextID);
898 writer.write<uint32_t>(Key.nameID);
899 }
900
901 hash_value_type ComputeHash(key_type_ref key) {
902 return static_cast<size_t>(key.hashValue());
903 }
904
905 unsigned getUnversionedInfoSize(const FieldInfo &FI) {
906 return getVariableInfoSize(FI);
907 }
908
909 void emitUnversionedInfo(raw_ostream &OS, const FieldInfo &FI) {
910 emitVariableInfo(OS, FI);
911 }
912};
913} // namespace
914
915void APINotesWriter::Implementation::writeFieldBlock(
916 llvm::BitstreamWriter &Stream) {
917 llvm::BCBlockRAII Scope(Stream, FIELD_BLOCK_ID, 3);
918
919 if (Fields.empty())
920 return;
921
922 {
923 llvm::SmallString<4096> HashTableBlob;
924 uint32_t Offset;
925 {
926 llvm::OnDiskChainedHashTableGenerator<FieldTableInfo> Generator;
927 for (auto &FD : Fields)
928 Generator.insert(FD.first, FD.second);
929
930 llvm::raw_svector_ostream BlobStream(HashTableBlob);
931 // Make sure that no bucket is at offset 0
932 llvm::support::endian::write<uint32_t>(BlobStream, 0,
933 llvm::endianness::little);
934 Offset = Generator.Emit(BlobStream);
935 }
936
937 field_block::FieldDataLayout FieldData(Stream);
938 FieldData.emit(Scratch, Offset, HashTableBlob);
939 }
940}
941
942namespace {
943/// Used to serialize the on-disk Objective-C selector table.
944class ObjCSelectorTableInfo {
945public:
946 using key_type = StoredObjCSelector;
947 using key_type_ref = const key_type &;
948 using data_type = SelectorID;
949 using data_type_ref = data_type;
950 using hash_value_type = unsigned;
951 using offset_type = unsigned;
952
953 hash_value_type ComputeHash(key_type_ref Key) {
954 return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
955 }
956
957 std::pair<unsigned, unsigned>
958 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
959 uint32_t KeyLength =
960 sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
961 uint32_t DataLength = sizeof(uint32_t);
962
963 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
964 writer.write<uint16_t>(KeyLength);
965 writer.write<uint16_t>(DataLength);
966 return {KeyLength, DataLength};
967 }
968
969 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
970 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
971 writer.write<uint16_t>(Key.NumArgs);
972 for (auto Identifier : Key.Identifiers)
973 writer.write<uint32_t>(Identifier);
974 }
975
976 void EmitData(raw_ostream &OS, key_type_ref, data_type_ref Data, unsigned) {
977 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
978 writer.write<uint32_t>(Data);
979 }
980};
981} // namespace
982
983void APINotesWriter::Implementation::writeObjCSelectorBlock(
984 llvm::BitstreamWriter &Stream) {
985 llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
986
987 if (SelectorIDs.empty())
988 return;
989
990 {
991 llvm::SmallString<4096> HashTableBlob;
992 uint32_t Offset;
993 {
994 llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
995 for (auto &S : SelectorIDs)
996 Generator.insert(S.first, S.second);
997
998 llvm::raw_svector_ostream BlobStream(HashTableBlob);
999 // Make sure that no bucket is at offset 0
1000 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1001 llvm::endianness::little);
1002 Offset = Generator.Emit(BlobStream);
1003 }
1004
1005 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
1006 ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
1007 }
1008}
1009
1010namespace {
1011/// Used to serialize the on-disk global variable table.
1012class GlobalVariableTableInfo
1013 : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,
1014 GlobalVariableInfo> {
1015public:
1016 unsigned getKeyLength(key_type_ref) {
1017 return sizeof(uint32_t) + sizeof(uint32_t);
1018 }
1019
1020 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1021 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1022 writer.write<uint32_t>(Key.parentContextID);
1023 writer.write<uint32_t>(Key.nameID);
1024 }
1025
1026 hash_value_type ComputeHash(key_type_ref Key) {
1027 return static_cast<size_t>(Key.hashValue());
1028 }
1029
1030 unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
1031 return getVariableInfoSize(GVI);
1032 }
1033
1034 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
1035 emitVariableInfo(OS, GVI);
1036 }
1037};
1038} // namespace
1039
1040void APINotesWriter::Implementation::writeGlobalVariableBlock(
1041 llvm::BitstreamWriter &Stream) {
1042 llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
1043
1044 if (GlobalVariables.empty())
1045 return;
1046
1047 {
1048 llvm::SmallString<4096> HashTableBlob;
1049 uint32_t Offset;
1050 {
1051 llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
1052 for (auto &GV : GlobalVariables)
1053 Generator.insert(GV.first, GV.second);
1054
1055 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1056 // Make sure that no bucket is at offset 0
1057 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1058 llvm::endianness::little);
1059 Offset = Generator.Emit(BlobStream);
1060 }
1061
1062 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
1063 GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
1064 }
1065}
1066
1067namespace {
1068unsigned getParamInfoSize(const ParamInfo &PI) {
1069 return getVariableInfoSize(PI) + 1;
1070}
1071
1072void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
1073 emitVariableInfo(OS, PI);
1074
1075 uint8_t flags = 0;
1076 if (auto noescape = PI.isNoEscape()) {
1077 flags |= 0x01;
1078 if (*noescape)
1079 flags |= 0x02;
1080 }
1081 flags <<= 2;
1082 if (auto lifetimebound = PI.isLifetimebound()) {
1083 flags |= 0x01;
1084 if (*lifetimebound)
1085 flags |= 0x02;
1086 }
1087 flags <<= 3;
1088 if (auto RCC = PI.getRetainCountConvention())
1089 flags |= static_cast<uint8_t>(RCC.value()) + 1;
1090
1091 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1092 writer.write<uint8_t>(flags);
1093}
1094
1095/// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
1096/// hash tables.
1097unsigned getFunctionInfoSize(const FunctionInfo &FI) {
1098 unsigned size = getCommonEntityInfoSize(FI) + 2 + sizeof(uint64_t);
1099 size += sizeof(uint16_t);
1100 for (const auto &P : FI.Params)
1101 size += getParamInfoSize(P);
1102 size += sizeof(uint16_t) + FI.ResultType.size();
1103 size += sizeof(uint16_t) + FI.SwiftReturnOwnership.size();
1104 return size;
1105}
1106
1107/// Emit a serialized representation of the function information.
1108void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
1109 emitCommonEntityInfo(OS, FI);
1110
1111 uint8_t flags = 0;
1112 flags |= FI.NullabilityAudited;
1113 flags <<= 3;
1114 if (auto RCC = FI.getRetainCountConvention())
1115 flags |= static_cast<uint8_t>(RCC.value()) + 1;
1116
1117 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1118
1119 writer.write<uint8_t>(flags);
1120 writer.write<uint8_t>(FI.NumAdjustedNullable);
1121 writer.write<uint64_t>(FI.NullabilityPayload);
1122
1123 writer.write<uint16_t>(FI.Params.size());
1124 for (const auto &PI : FI.Params)
1125 emitParamInfo(OS, PI);
1126
1127 writer.write<uint16_t>(FI.ResultType.size());
1128 writer.write(ArrayRef<char>{FI.ResultType});
1129 writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
1130 writer.write(ArrayRef<char>{FI.SwiftReturnOwnership});
1131}
1132
1133/// Used to serialize the on-disk global function table.
1134class GlobalFunctionTableInfo
1135 : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
1136 GlobalFunctionInfo> {
1137public:
1138 unsigned getKeyLength(key_type_ref) {
1139 return sizeof(uint32_t) + sizeof(uint32_t);
1140 }
1141
1142 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1143 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1144 writer.write<uint32_t>(Key.parentContextID);
1145 writer.write<uint32_t>(Key.nameID);
1146 }
1147
1148 hash_value_type ComputeHash(key_type_ref Key) {
1149 return static_cast<size_t>(Key.hashValue());
1150 }
1151
1152 unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1153 return getFunctionInfoSize(GFI);
1154 }
1155
1156 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1157 emitFunctionInfo(OS, GFI);
1158 }
1159};
1160} // namespace
1161
1162void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1163 llvm::BitstreamWriter &Stream) {
1164 llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1165
1166 if (GlobalFunctions.empty())
1167 return;
1168
1169 {
1170 llvm::SmallString<4096> HashTableBlob;
1171 uint32_t Offset;
1172 {
1173 llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1174 for (auto &F : GlobalFunctions)
1175 Generator.insert(F.first, F.second);
1176
1177 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1178 // Make sure that no bucket is at offset 0
1179 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1180 llvm::endianness::little);
1181 Offset = Generator.Emit(BlobStream);
1182 }
1183
1184 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1185 GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1186 }
1187}
1188
1189namespace {
1190/// Used to serialize the on-disk global enum constant.
1191class EnumConstantTableInfo
1192 : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1193 EnumConstantInfo> {
1194public:
1195 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1196
1197 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1198 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1199 writer.write<uint32_t>(Key);
1200 }
1201
1202 hash_value_type ComputeHash(key_type_ref Key) {
1203 return static_cast<size_t>(llvm::hash_value(Key));
1204 }
1205
1206 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1207 return getCommonEntityInfoSize(ECI);
1208 }
1209
1210 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1211 emitCommonEntityInfo(OS, ECI);
1212 }
1213};
1214} // namespace
1215
1216void APINotesWriter::Implementation::writeEnumConstantBlock(
1217 llvm::BitstreamWriter &Stream) {
1218 llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1219
1220 if (EnumConstants.empty())
1221 return;
1222
1223 {
1224 llvm::SmallString<4096> HashTableBlob;
1225 uint32_t Offset;
1226 {
1227 llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1228 for (auto &EC : EnumConstants)
1229 Generator.insert(EC.first, EC.second);
1230
1231 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1232 // Make sure that no bucket is at offset 0
1233 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1234 llvm::endianness::little);
1235 Offset = Generator.Emit(BlobStream);
1236 }
1237
1238 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1239 EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1240 }
1241}
1242
1243namespace {
1244template <typename Derived, typename UnversionedDataType>
1245class CommonTypeTableInfo
1246 : public VersionedTableInfo<Derived, SingleDeclTableKey,
1247 UnversionedDataType> {
1248public:
1249 using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1250 using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1251
1252 unsigned getKeyLength(key_type_ref) {
1253 return sizeof(uint32_t) + sizeof(IdentifierID);
1254 }
1255
1256 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1257 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1258 writer.write<uint32_t>(Key.parentContextID);
1259 writer.write<IdentifierID>(Key.nameID);
1260 }
1261
1262 hash_value_type ComputeHash(key_type_ref Key) {
1263 return static_cast<size_t>(Key.hashValue());
1264 }
1265
1266 unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1267 return getCommonTypeInfoSize(UDT);
1268 }
1269
1270 void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1271 emitCommonTypeInfo(OS, UDT);
1272 }
1273};
1274
1275/// Used to serialize the on-disk tag table.
1276class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1277public:
1278 unsigned getUnversionedInfoSize(const TagInfo &TI) {
1279 // clang-format off
1280 return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1281 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1282 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1283 2 + (TI.SwiftDestroyOp ? TI.SwiftDestroyOp->size() : 0) +
1284 2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +
1285 3 + getCommonTypeInfoSize(TI);
1286 // clang-format on
1287 }
1288
1289 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1290 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1291
1292 uint8_t Flags = 0;
1293 if (auto extensibility = TI.EnumExtensibility) {
1294 Flags |= static_cast<uint8_t>(extensibility.value()) + 1;
1295 assert((Flags < (1 << 2)) && "must fit in two bits");
1296 }
1297
1298 Flags <<= 2;
1299 if (auto value = TI.isFlagEnum())
1300 Flags |= (value.value() << 1 | 1 << 0);
1301
1302 writer.write<uint8_t>(Flags);
1303
1304 if (auto Copyable = TI.isSwiftCopyable())
1305 writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);
1306 else
1307 writer.write<uint8_t>(0);
1308
1309 if (auto Escapable = TI.isSwiftEscapable())
1310 writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);
1311 else
1312 writer.write<uint8_t>(0);
1313
1314 if (auto ImportAs = TI.SwiftImportAs) {
1315 writer.write<uint16_t>(ImportAs->size() + 1);
1316 OS.write(ImportAs->c_str(), ImportAs->size());
1317 } else {
1318 writer.write<uint16_t>(0);
1319 }
1320 if (auto RetainOp = TI.SwiftRetainOp) {
1321 writer.write<uint16_t>(RetainOp->size() + 1);
1322 OS.write(RetainOp->c_str(), RetainOp->size());
1323 } else {
1324 writer.write<uint16_t>(0);
1325 }
1326 if (auto ReleaseOp = TI.SwiftReleaseOp) {
1327 writer.write<uint16_t>(ReleaseOp->size() + 1);
1328 OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1329 } else {
1330 writer.write<uint16_t>(0);
1331 }
1332 if (auto DefaultOwnership = TI.SwiftDefaultOwnership) {
1333 writer.write<uint16_t>(DefaultOwnership->size() + 1);
1334 OS.write(DefaultOwnership->c_str(), DefaultOwnership->size());
1335 } else {
1336 writer.write<uint16_t>(0);
1337 }
1338 if (auto DestroyOp = TI.SwiftDestroyOp) {
1339 writer.write<uint16_t>(DestroyOp->size() + 1);
1340 OS.write(DestroyOp->c_str(), DestroyOp->size());
1341 } else {
1342 writer.write<uint16_t>(0);
1343 }
1344
1345 emitCommonTypeInfo(OS, TI);
1346 }
1347};
1348} // namespace
1349
1350void APINotesWriter::Implementation::writeTagBlock(
1351 llvm::BitstreamWriter &Stream) {
1352 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1353
1354 if (Tags.empty())
1355 return;
1356
1357 {
1358 llvm::SmallString<4096> HashTableBlob;
1359 uint32_t Offset;
1360 {
1361 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1362 for (auto &T : Tags)
1363 Generator.insert(T.first, T.second);
1364
1365 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1366 // Make sure that no bucket is at offset 0
1367 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1368 llvm::endianness::little);
1369 Offset = Generator.Emit(BlobStream);
1370 }
1371
1372 tag_block::TagDataLayout TagData(Stream);
1373 TagData.emit(Scratch, Offset, HashTableBlob);
1374 }
1375}
1376
1377namespace {
1378/// Used to serialize the on-disk typedef table.
1379class TypedefTableInfo
1380 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1381public:
1382 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1383 return 1 + getCommonTypeInfoSize(TI);
1384 }
1385
1386 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1387 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1388
1389 uint8_t Flags = 0;
1390 if (auto swiftWrapper = TI.SwiftWrapper)
1391 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1392
1393 writer.write<uint8_t>(Flags);
1394
1395 emitCommonTypeInfo(OS, TI);
1396 }
1397};
1398} // namespace
1399
1400void APINotesWriter::Implementation::writeTypedefBlock(
1401 llvm::BitstreamWriter &Stream) {
1402 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1403
1404 if (Typedefs.empty())
1405 return;
1406
1407 {
1408 llvm::SmallString<4096> HashTableBlob;
1409 uint32_t Offset;
1410 {
1411 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1412 for (auto &T : Typedefs)
1413 Generator.insert(T.first, T.second);
1414
1415 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1416 // Make sure that no bucket is at offset 0
1417 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1418 llvm::endianness::little);
1419 Offset = Generator.Emit(BlobStream);
1420 }
1421
1422 typedef_block::TypedefDataLayout TypedefData(Stream);
1423 TypedefData.emit(Scratch, Offset, HashTableBlob);
1424 }
1425}
1426
1427// APINotesWriter
1428
1429APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1430 : Implementation(new class Implementation(ModuleName, SF)) {}
1431
1433
1434void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1436}
1437
1438ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1439 llvm::StringRef Name, ContextKind Kind,
1440 const ContextInfo &Info,
1441 llvm::VersionTuple SwiftVersion) {
1442 IdentifierID NameID = Implementation->getIdentifier(Name);
1443
1444 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1445 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1446 auto Known = Implementation->Contexts.find(Key);
1447 if (Known == Implementation->Contexts.end()) {
1448 unsigned NextID = Implementation->Contexts.size() + 1;
1449
1451 Known = Implementation->Contexts
1452 .insert(std::make_pair(
1453 Key, std::make_pair(NextID, EmptyVersionedInfo)))
1454 .first;
1455
1456 Implementation->ContextNames[NextID] = NameID;
1457 Implementation->ParentContexts[NextID] = RawParentCtxID;
1458 }
1459
1460 // Add this version information.
1461 auto &VersionedVec = Known->second.second;
1462 bool Found = false;
1463 for (auto &Versioned : VersionedVec) {
1464 if (Versioned.first == SwiftVersion) {
1465 Versioned.second |= Info;
1466 Found = true;
1467 break;
1468 }
1469 }
1470
1471 if (!Found)
1472 VersionedVec.push_back({SwiftVersion, Info});
1473
1474 return ContextID(Known->second.first);
1475}
1476
1478 bool IsInstanceProperty,
1479 const ObjCPropertyInfo &Info,
1480 VersionTuple SwiftVersion) {
1481 IdentifierID NameID = Implementation->getIdentifier(Name);
1483 ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1484 .push_back({SwiftVersion, Info});
1485}
1486
1488 bool IsInstanceMethod,
1489 const ObjCMethodInfo &Info,
1490 VersionTuple SwiftVersion) {
1491 SelectorID SelID = Implementation->getSelector(Selector);
1492 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1493 IsInstanceMethod};
1494 Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1495
1496 // If this method is a designated initializer, update the class to note that
1497 // it has designated initializers.
1498 if (Info.DesignatedInit) {
1499 assert(Implementation->ParentContexts.contains(CtxID.Value));
1500 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1501 ContextTableKey CtxKey(ParentCtxID,
1502 static_cast<uint8_t>(ContextKind::ObjCClass),
1503 Implementation->ContextNames[CtxID.Value]);
1504 assert(Implementation->Contexts.contains(CtxKey));
1505 auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1506 bool Found = false;
1507 for (auto &Versioned : VersionedVec) {
1508 if (Versioned.first == SwiftVersion) {
1509 Versioned.second.setHasDesignatedInits(true);
1510 Found = true;
1511 break;
1512 }
1513 }
1514
1515 if (!Found) {
1516 VersionedVec.push_back({SwiftVersion, ContextInfo()});
1517 VersionedVec.back().second.setHasDesignatedInits(true);
1518 }
1519 }
1520}
1521
1522void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1523 const CXXMethodInfo &Info,
1524 VersionTuple SwiftVersion) {
1525 IdentifierID NameID = Implementation->getIdentifier(Name);
1526 SingleDeclTableKey Key(CtxID.Value, NameID);
1527 Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
1528}
1529
1530void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,
1531 const FieldInfo &Info,
1532 VersionTuple SwiftVersion) {
1533 IdentifierID NameID = Implementation->getIdentifier(Name);
1534 SingleDeclTableKey Key(CtxID.Value, NameID);
1535 Implementation->Fields[Key].push_back({SwiftVersion, Info});
1536}
1537
1538void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1539 llvm::StringRef Name,
1540 const GlobalVariableInfo &Info,
1541 VersionTuple SwiftVersion) {
1542 IdentifierID VariableID = Implementation->getIdentifier(Name);
1543 SingleDeclTableKey Key(Ctx, VariableID);
1544 Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1545}
1546
1547void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1548 llvm::StringRef Name,
1549 const GlobalFunctionInfo &Info,
1550 VersionTuple SwiftVersion) {
1551 IdentifierID NameID = Implementation->getIdentifier(Name);
1552 SingleDeclTableKey Key(Ctx, NameID);
1553 Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1554}
1555
1556void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1557 const EnumConstantInfo &Info,
1558 VersionTuple SwiftVersion) {
1559 IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1560 Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1561}
1562
1563void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1564 const TagInfo &Info, VersionTuple SwiftVersion) {
1565 IdentifierID TagID = Implementation->getIdentifier(Name);
1566 SingleDeclTableKey Key(Ctx, TagID);
1567 Implementation->Tags[Key].push_back({SwiftVersion, Info});
1568}
1569
1570void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1571 llvm::StringRef Name, const TypedefInfo &Info,
1572 VersionTuple SwiftVersion) {
1573 IdentifierID TypedefID = Implementation->getIdentifier(Name);
1574 SingleDeclTableKey Key(Ctx, TypedefID);
1575 Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1576}
1577} // namespace api_notes
1578} // namespace clang
#define BLOCK_RECORD(NameSpace, Block)
MatchType Type
StringRef P
static StringRef bytes(const std::vector< T, Allocator > &v)
Definition: ASTWriter.cpp:126
static char ID
Definition: Arena.cpp:183
enum clang::sema::@1840::IndirectLocalPathEntry::EntryKind Kind
Expr * E
Defines the clang::FileManager interface and associated types.
StringRef Identifier
Definition: Format.cpp:3185
static void emitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, SmallVectorImpl< uint64_t > &Record)
static void emitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, SmallVectorImpl< uint64_t > &Record)
static StringRef getIdentifier(const Token &Tok)
const char * Data
#define BLOCK(DERIVED, BASE)
Definition: Template.h:640
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
__SIZE_TYPE__ size_t
Cached information about one file (either on disk or in the virtual file system).
Definition: FileEntry.h:306
off_t getSize() const
Definition: FileEntry.h:332
Smart pointer class that efficiently represents Objective-C method names.
Implementation(llvm::StringRef ModuleName, const FileEntry *SF)
A class that writes API notes data to a binary representation that can be read by the APINotesReader.
void addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector, bool IsInstanceMethod, const ObjCMethodInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C method.
void addEnumConstant(llvm::StringRef Name, const EnumConstantInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about an enumerator.
ContextID addContext(std::optional< ContextID > ParentCtxID, llvm::StringRef Name, ContextKind Kind, const ContextInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C class or protocol or a C++ namespace.
void addGlobalFunction(std::optional< Context > Ctx, llvm::StringRef Name, const GlobalFunctionInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a global function.
void addObjCProperty(ContextID CtxID, llvm::StringRef Name, bool IsInstanceProperty, const ObjCPropertyInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific Objective-C property.
void addField(ContextID CtxID, llvm::StringRef Name, const FieldInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific C record field.
void addGlobalVariable(std::optional< Context > Ctx, llvm::StringRef Name, const GlobalVariableInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a global variable.
void addTypedef(std::optional< Context > Ctx, llvm::StringRef Name, const TypedefInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a typedef.
void writeToStream(llvm::raw_ostream &OS)
void addCXXMethod(ContextID CtxID, llvm::StringRef Name, const CXXMethodInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a specific C++ method.
void addTag(std::optional< Context > Ctx, llvm::StringRef Name, const TagInfo &Info, llvm::VersionTuple SwiftVersion)
Add information about a tag (struct/union/enum/C++ class).
APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
Create a new API notes writer with the given module name and (optional) source file.
Describes API notes data for a C++ method.
Definition: Types.h:710
Opaque context ID used to refer to an Objective-C class or protocol or a C++ namespace.
Definition: Types.h:877
Describes API notes data for an Objective-C class or protocol or a C++ namespace.
Definition: Types.h:211
Describes API notes data for an enumerator.
Definition: Types.h:728
Describes API notes data for a C/C++ record field.
Definition: Types.h:704
Describes API notes data for a global function.
Definition: Types.h:698
Describes API notes data for a global variable.
Definition: Types.h:692
Describes API notes data for an Objective-C method.
Definition: Types.h:651
unsigned DesignatedInit
Whether this is a designated initializer of its class.
Definition: Types.h:655
Describes API notes data for an Objective-C property.
Definition: Types.h:375
Describes API notes data for a tag.
Definition: Types.h:734
Describes API notes data for a typedef.
Definition: Types.h:845
llvm::BCRecordLayout< CONTEXT_ID_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ContextIDLayout
llvm::BCRecordLayout< CONTEXT_INFO_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ContextInfoLayout
llvm::BCRecordLayout< SOURCE_FILE, llvm::BCVBR< 16 >, llvm::BCVBR< 16 > > SourceFileLayout
llvm::BCRecordLayout< MODULE_NAME, llvm::BCBlob > ModuleNameLayout
llvm::BCRecordLayout< METADATA, llvm::BCFixed< 16 >, llvm::BCFixed< 16 > > MetadataLayout
llvm::BCRecordLayout< CXX_METHOD_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > CXXMethodDataLayout
llvm::BCRecordLayout< ENUM_CONSTANT_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > EnumConstantDataLayout
llvm::BCRecordLayout< FIELD_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > FieldDataLayout
llvm::BCRecordLayout< GLOBAL_FUNCTION_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > GlobalFunctionDataLayout
llvm::BCRecordLayout< GLOBAL_VARIABLE_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > GlobalVariableDataLayout
llvm::BCRecordLayout< IDENTIFIER_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > IdentifierDataLayout
llvm::BCRecordLayout< OBJC_METHOD_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCMethodDataLayout
llvm::BCRecordLayout< OBJC_PROPERTY_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCPropertyDataLayout
llvm::BCRecordLayout< OBJC_SELECTOR_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > ObjCSelectorDataLayout
llvm::BCRecordLayout< TAG_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > TagDataLayout
llvm::BCRecordLayout< TYPEDEF_DATA, llvm::BCVBR< 16 >, llvm::BCBlob > TypedefDataLayout
llvm::PointerEmbeddedInt< unsigned, 31 > SelectorID
llvm::PointerEmbeddedInt< unsigned, 31 > IdentifierID
const uint16_t VERSION_MAJOR
API notes file major version number.
const unsigned char API_NOTES_SIGNATURE[]
Magic number for API notes files.
const uint16_t VERSION_MINOR
API notes file minor version number.
@ OBJC_CONTEXT_BLOCK_ID
The Objective-C context data block, which contains information about Objective-C classes and protocol...
@ TYPEDEF_BLOCK_ID
The typedef data block, which maps typedef names to information about the typedefs.
@ OBJC_PROPERTY_BLOCK_ID
The Objective-C property data block, which maps Objective-C (class name, property name) pairs to info...
@ ENUM_CONSTANT_BLOCK_ID
The enum constant data block, which maps enumerator names to information about the enumerators.
@ TAG_BLOCK_ID
The tag data block, which maps tag names to information about the tags.
@ OBJC_METHOD_BLOCK_ID
The Objective-C property data block, which maps Objective-C (class name, selector,...
@ FIELD_BLOCK_ID
The fields data block, which maps names fields of C records to information about the field.
@ OBJC_SELECTOR_BLOCK_ID
The Objective-C selector data block, which maps Objective-C selector names (# of pieces,...
@ CXX_METHOD_BLOCK_ID
The C++ method data block, which maps C++ (context id, method name) pairs to information about the me...
@ GLOBAL_FUNCTION_BLOCK_ID
The (global) functions data block, which maps global function names to information about the global f...
@ CONTROL_BLOCK_ID
The control block, which contains all of the information that needs to be validated prior to committi...
@ IDENTIFIER_BLOCK_ID
The identifier data block, which maps identifier strings to IDs.
@ GLOBAL_VARIABLE_BLOCK_ID
The global variables data block, which maps global variable names to information about the global var...
uint32_t SelectorID
An ID number that refers to an ObjC selector in an AST file.
Definition: ASTBitCodes.h:167
uint64_t IdentifierID
An ID number that refers to an identifier in an AST file.
Definition: ASTBitCodes.h:63
unsigned ComputeHash(Selector Sel)
Definition: ASTCommon.cpp:294
std::shared_ptr< MatchComputation< T > > Generator
Definition: RewriteRule.h:65
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
unsigned long uint64_t
unsigned int uint32_t
hash_code hash_value(const clang::tooling::dependencies::ModuleID &ID)
A stored Objective-C or C++ context, represented by the ID of its parent context, the kind of this co...
A temporary reference to an Objective-C selector, suitable for referencing selector data on the stack...
Definition: Types.h:904
llvm::ArrayRef< llvm::StringRef > Identifiers
Definition: Types.h:906
A stored Objective-C or C++ declaration, represented by the ID of its parent context,...
A stored Objective-C selector.