1 //===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
22 class APINotesWriter::Implementation
{
23 friend class APINotesWriter
;
26 using VersionedSmallVector
=
27 llvm::SmallVector
<std::pair
<llvm::VersionTuple
, T
>, 1>;
29 std::string ModuleName
;
30 const FileEntry
*SourceFile
;
32 /// Scratch space for bitstream writing.
33 llvm::SmallVector
<uint64_t, 64> Scratch
;
35 /// Mapping from strings to identifier IDs.
36 llvm::StringMap
<IdentifierID
> IdentifierIDs
;
38 /// Information about contexts (Objective-C classes or protocols or C++
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
>>>
48 /// Information about parent contexts for each context.
50 /// Indexed by context ID, provides the parent context ID.
51 llvm::DenseMap
<uint32_t, uint32_t> ParentContexts
;
53 /// Mapping from context IDs to the identifier ID holding the name.
54 llvm::DenseMap
<unsigned, unsigned> ContextNames
;
56 /// Information about Objective-C properties.
58 /// Indexed by the context ID, property name, and whether this is an
59 /// instance property.
61 std::tuple
<unsigned, unsigned, char>,
62 llvm::SmallVector
<std::pair
<VersionTuple
, ObjCPropertyInfo
>, 1>>
65 /// Information about C record fields.
67 /// Indexed by the context ID and name ID.
68 llvm::DenseMap
<SingleDeclTableKey
,
69 llvm::SmallVector
<std::pair
<VersionTuple
, FieldInfo
>, 1>>
72 /// Information about Objective-C methods.
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>>
80 /// Information about C++ methods.
82 /// Indexed by the context ID and name ID.
83 llvm::DenseMap
<SingleDeclTableKey
,
84 llvm::SmallVector
<std::pair
<VersionTuple
, CXXMethodInfo
>, 1>>
87 /// Mapping from selectors to selector ID.
88 llvm::DenseMap
<StoredObjCSelector
, SelectorID
> SelectorIDs
;
90 /// Information about global variables.
92 /// Indexed by the context ID, identifier ID.
95 llvm::SmallVector
<std::pair
<VersionTuple
, GlobalVariableInfo
>, 1>>
98 /// Information about global functions.
100 /// Indexed by the context ID, identifier ID.
103 llvm::SmallVector
<std::pair
<VersionTuple
, GlobalFunctionInfo
>, 1>>
106 /// Information about enumerators.
108 /// Indexed by the identifier ID.
110 unsigned, llvm::SmallVector
<std::pair
<VersionTuple
, EnumConstantInfo
>, 1>>
113 /// Information about tags.
115 /// Indexed by the context ID, identifier ID.
116 llvm::DenseMap
<SingleDeclTableKey
,
117 llvm::SmallVector
<std::pair
<VersionTuple
, TagInfo
>, 1>>
120 /// Information about typedefs.
122 /// Indexed by the context ID, identifier ID.
123 llvm::DenseMap
<SingleDeclTableKey
,
124 llvm::SmallVector
<std::pair
<VersionTuple
, TypedefInfo
>, 1>>
127 /// Retrieve the ID for the given identifier.
128 IdentifierID
getIdentifier(StringRef Identifier
) {
129 if (Identifier
.empty())
132 // Add to the identifier table if missing.
133 return IdentifierIDs
.try_emplace(Identifier
, IdentifierIDs
.size() + 1)
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(SelectorRef
.Identifiers
.size());
143 for (auto piece
: SelectorRef
.Identifiers
)
144 Selector
.Identifiers
.push_back(getIdentifier(piece
));
146 // Look for the stored selector. Add to the selector table if missing.
147 return SelectorIDs
.try_emplace(Selector
, SelectorIDs
.size()).first
->second
;
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
);
167 Implementation(llvm::StringRef ModuleName
, const FileEntry
*SF
)
168 : ModuleName(std::string(ModuleName
)), SourceFile(SF
) {}
170 void writeToStream(llvm::raw_ostream
&OS
);
173 void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream
&OS
) {
174 llvm::SmallVector
<char, 0> Buffer
;
177 llvm::BitstreamWriter
Stream(Buffer
);
179 // Emit the signature.
180 for (unsigned char Byte
: API_NOTES_SIGNATURE
)
181 Stream
.Emit(Byte
, 8);
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
);
200 OS
.write(Buffer
.data(), Buffer
.size());
205 /// Record the name of a block.
206 void emitBlockID(llvm::BitstreamWriter
&Stream
, unsigned ID
,
207 llvm::StringRef Name
) {
208 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID
,
209 llvm::ArrayRef
<unsigned>{ID
});
211 // Emit the block name if present.
215 llvm::bitc::BLOCKINFO_CODE_BLOCKNAME
,
216 llvm::ArrayRef
<unsigned char>(
217 const_cast<unsigned char *>(
218 reinterpret_cast<const unsigned char *>(Name
.data())),
222 /// Record the name of a record within a block.
223 void emitRecordID(llvm::BitstreamWriter
&Stream
, unsigned ID
,
224 llvm::StringRef Name
) {
225 assert(ID
< 256 && "can't fit record ID in next to name");
227 llvm::SmallVector
<unsigned char, 64> Buffer
;
228 Buffer
.resize(Name
.size() + 1);
230 memcpy(Buffer
.data() + 1, Name
.data(), Name
.size());
232 Stream
.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME
, Buffer
);
236 void APINotesWriter::Implementation::writeBlockInfoBlock(
237 llvm::BitstreamWriter
&Stream
) {
238 llvm::BCBlockRAII
Scope(Stream
, llvm::bitc::BLOCKINFO_BLOCK_ID
, 2);
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
);
247 BLOCK(IDENTIFIER_BLOCK
);
248 BLOCK_RECORD(identifier_block
, IDENTIFIER_DATA
);
250 BLOCK(OBJC_CONTEXT_BLOCK
);
251 BLOCK_RECORD(context_block
, CONTEXT_ID_DATA
);
253 BLOCK(OBJC_PROPERTY_BLOCK
);
254 BLOCK_RECORD(objc_property_block
, OBJC_PROPERTY_DATA
);
256 BLOCK(OBJC_METHOD_BLOCK
);
257 BLOCK_RECORD(objc_method_block
, OBJC_METHOD_DATA
);
259 BLOCK(OBJC_SELECTOR_BLOCK
);
260 BLOCK_RECORD(objc_selector_block
, OBJC_SELECTOR_DATA
);
262 BLOCK(GLOBAL_VARIABLE_BLOCK
);
263 BLOCK_RECORD(global_variable_block
, GLOBAL_VARIABLE_DATA
);
265 BLOCK(GLOBAL_FUNCTION_BLOCK
);
266 BLOCK_RECORD(global_function_block
, GLOBAL_FUNCTION_DATA
);
271 void APINotesWriter::Implementation::writeControlBlock(
272 llvm::BitstreamWriter
&Stream
) {
273 llvm::BCBlockRAII
Scope(Stream
, CONTROL_BLOCK_ID
, 3);
275 control_block::MetadataLayout
Metadata(Stream
);
276 Metadata
.emit(Scratch
, VERSION_MAJOR
, VERSION_MINOR
);
278 control_block::ModuleNameLayout
ModuleName(Stream
);
279 ModuleName
.emit(Scratch
, this->ModuleName
);
282 control_block::SourceFileLayout
SourceFile(Stream
);
283 SourceFile
.emit(Scratch
, this->SourceFile
->getSize(),
284 this->SourceFile
->getModificationTime());
289 /// Used to serialize the on-disk identifier table.
290 class IdentifierTableInfo
{
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;
299 hash_value_type
ComputeHash(key_type_ref Key
) { return llvm::djbHash(Key
); }
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);
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
};
312 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) { OS
<< Key
; }
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
);
321 void APINotesWriter::Implementation::writeIdentifierBlock(
322 llvm::BitstreamWriter
&Stream
) {
323 llvm::BCBlockRAII
restoreBlock(Stream
, IDENTIFIER_BLOCK_ID
, 3);
325 if (IdentifierIDs
.empty())
328 llvm::SmallString
<4096> HashTableBlob
;
331 llvm::OnDiskChainedHashTableGenerator
<IdentifierTableInfo
> Generator
;
332 for (auto &II
: IdentifierIDs
)
333 Generator
.insert(II
.first(), II
.second
);
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
);
342 identifier_block::IdentifierDataLayout
IdentifierData(Stream
);
343 IdentifierData
.emit(Scratch
, Offset
, HashTableBlob
);
347 /// Used to serialize the on-disk Objective-C context table.
348 class ContextIDTableInfo
{
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;
357 hash_value_type
ComputeHash(key_type_ref Key
) {
358 return static_cast<size_t>(Key
.hashValue());
361 std::pair
<unsigned, unsigned> EmitKeyDataLength(raw_ostream
&OS
, key_type_ref
,
363 uint32_t KeyLength
= sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
364 uint32_t DataLength
= sizeof(uint32_t);
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
};
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
);
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
);
385 /// Localized helper to make a type dependent, thwarting template argument
387 template <typename T
> struct MakeDependent
{ typedef T Type
; };
389 /// Retrieve the serialized size of the given VersionTuple, for use in
390 /// on-disk hash tables.
391 unsigned getVersionTupleSize(const VersionTuple
&VT
) {
392 unsigned size
= sizeof(uint8_t) + /*major*/ sizeof(uint32_t);
394 size
+= sizeof(uint32_t);
395 if (VT
.getSubminor())
396 size
+= sizeof(uint32_t);
398 size
+= sizeof(uint32_t);
402 /// Determine the size of an array of versioned information,
403 template <typename T
>
404 unsigned getVersionedInfoSize(
405 const llvm::SmallVectorImpl
<std::pair
<llvm::VersionTuple
, T
>> &VI
,
406 llvm::function_ref
<unsigned(const typename MakeDependent
<T
>::Type
&)>
408 unsigned result
= sizeof(uint16_t); // # of elements
409 for (const auto &E
: VI
) {
410 result
+= getVersionTupleSize(E
.first
);
411 result
+= getInfoSize(E
.second
);
416 /// Emit a serialized representation of a version tuple.
417 void emitVersionTuple(raw_ostream
&OS
, const VersionTuple
&VT
) {
418 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
420 // First byte contains the number of components beyond the 'major' component.
424 else if (VT
.getSubminor())
426 else if (VT
.getMinor())
430 writer
.write
<uint8_t>(descriptor
);
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
);
442 /// Emit versioned information.
443 template <typename T
>
444 void 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
&)>
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
;
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
);
465 /// On-disk hash table info key base for handling versioned data.
466 template <typename Derived
, typename KeyType
, typename UnversionedDataType
>
467 class VersionedTableInfo
{
468 Derived
&asDerived() { return *static_cast<Derived
*>(this); }
470 const Derived
&asDerived() const {
471 return *static_cast<const Derived
*>(this);
475 using key_type
= KeyType
;
476 using key_type_ref
= key_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;
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
);
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
};
497 void EmitData(raw_ostream
&OS
, key_type_ref
, data_type_ref Data
, unsigned) {
499 OS
, Data
, [this](llvm::raw_ostream
&OS
, const UnversionedDataType
&UI
) {
500 asDerived().emitUnversionedInfo(OS
, UI
);
505 /// Emit a serialized representation of the common entity information.
506 void emitCommonEntityInfo(raw_ostream
&OS
, const CommonEntityInfo
&CEI
) {
507 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
510 if (auto swiftPrivate
= CEI
.isSwiftPrivate()) {
516 payload
|= CEI
.Unavailable
;
518 payload
|= CEI
.UnavailableInSwift
;
520 writer
.write
<uint8_t>(payload
);
522 writer
.write
<uint16_t>(CEI
.UnavailableMsg
.size());
523 OS
.write(CEI
.UnavailableMsg
.c_str(), CEI
.UnavailableMsg
.size());
525 writer
.write
<uint16_t>(CEI
.SwiftName
.size());
526 OS
.write(CEI
.SwiftName
.c_str(), CEI
.SwiftName
.size());
529 /// Retrieve the serialized size of the given CommonEntityInfo, for use in
530 /// on-disk hash tables.
531 unsigned getCommonEntityInfoSize(const CommonEntityInfo
&CEI
) {
532 return 5 + CEI
.UnavailableMsg
.size() + CEI
.SwiftName
.size();
535 // Retrieve the serialized size of the given CommonTypeInfo, for use
536 // in on-disk hash tables.
537 unsigned getCommonTypeInfoSize(const CommonTypeInfo
&CTI
) {
538 return 2 + (CTI
.getSwiftBridge() ? CTI
.getSwiftBridge()->size() : 0) + 2 +
539 (CTI
.getNSErrorDomain() ? CTI
.getNSErrorDomain()->size() : 0) +
540 getCommonEntityInfoSize(CTI
);
543 /// Emit a serialized representation of the common type information.
544 void emitCommonTypeInfo(raw_ostream
&OS
, const CommonTypeInfo
&CTI
) {
545 emitCommonEntityInfo(OS
, CTI
);
547 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
548 if (auto swiftBridge
= CTI
.getSwiftBridge()) {
549 writer
.write
<uint16_t>(swiftBridge
->size() + 1);
550 OS
.write(swiftBridge
->c_str(), swiftBridge
->size());
552 writer
.write
<uint16_t>(0);
554 if (auto nsErrorDomain
= CTI
.getNSErrorDomain()) {
555 writer
.write
<uint16_t>(nsErrorDomain
->size() + 1);
556 OS
.write(nsErrorDomain
->c_str(), CTI
.getNSErrorDomain()->size());
558 writer
.write
<uint16_t>(0);
562 /// Used to serialize the on-disk Objective-C property table.
563 class ContextInfoTableInfo
564 : public VersionedTableInfo
<ContextInfoTableInfo
, unsigned, ContextInfo
> {
566 unsigned getKeyLength(key_type_ref
) { return sizeof(uint32_t); }
568 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
569 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
570 writer
.write
<uint32_t>(Key
);
573 hash_value_type
ComputeHash(key_type_ref Key
) {
574 return static_cast<size_t>(llvm::hash_value(Key
));
577 unsigned getUnversionedInfoSize(const ContextInfo
&OCI
) {
578 return getCommonTypeInfoSize(OCI
) + 1;
581 void emitUnversionedInfo(raw_ostream
&OS
, const ContextInfo
&OCI
) {
582 emitCommonTypeInfo(OS
, OCI
);
585 if (auto swiftImportAsNonGeneric
= OCI
.getSwiftImportAsNonGeneric())
586 payload
|= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric
.value();
588 if (auto swiftObjCMembers
= OCI
.getSwiftObjCMembers())
589 payload
|= (0x01 << 1) | (uint8_t)swiftObjCMembers
.value();
591 if (auto nullable
= OCI
.getDefaultNullability())
592 payload
|= (0x01 << 2) | static_cast<uint8_t>(*nullable
);
593 payload
= (payload
<< 1) | (OCI
.hasDesignatedInits() ? 1 : 0);
600 void APINotesWriter::Implementation::writeContextBlock(
601 llvm::BitstreamWriter
&Stream
) {
602 llvm::BCBlockRAII
restoreBlock(Stream
, OBJC_CONTEXT_BLOCK_ID
, 3);
604 if (Contexts
.empty())
608 llvm::SmallString
<4096> HashTableBlob
;
611 llvm::OnDiskChainedHashTableGenerator
<ContextIDTableInfo
> Generator
;
612 for (auto &OC
: Contexts
)
613 Generator
.insert(OC
.first
, OC
.second
.first
);
615 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
616 // Make sure that no bucket is at offset 0
617 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
618 llvm::endianness::little
);
619 Offset
= Generator
.Emit(BlobStream
);
622 context_block::ContextIDLayout
ContextID(Stream
);
623 ContextID
.emit(Scratch
, Offset
, HashTableBlob
);
627 llvm::SmallString
<4096> HashTableBlob
;
630 llvm::OnDiskChainedHashTableGenerator
<ContextInfoTableInfo
> Generator
;
631 for (auto &OC
: Contexts
)
632 Generator
.insert(OC
.second
.first
, OC
.second
.second
);
634 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
635 // Make sure that no bucket is at offset 0
636 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
637 llvm::endianness::little
);
638 Offset
= Generator
.Emit(BlobStream
);
641 context_block::ContextInfoLayout
ContextInfo(Stream
);
642 ContextInfo
.emit(Scratch
, Offset
, HashTableBlob
);
647 /// Retrieve the serialized size of the given VariableInfo, for use in
648 /// on-disk hash tables.
649 unsigned getVariableInfoSize(const VariableInfo
&VI
) {
650 return 2 + getCommonEntityInfoSize(VI
) + 2 + VI
.getType().size();
652 unsigned getParamInfoSize(const ParamInfo
&PI
);
654 /// Emit a serialized representation of the variable information.
655 void emitVariableInfo(raw_ostream
&OS
, const VariableInfo
&VI
) {
656 emitCommonEntityInfo(OS
, VI
);
658 uint8_t bytes
[2] = {0, 0};
659 if (auto nullable
= VI
.getNullability()) {
661 bytes
[1] = static_cast<uint8_t>(*nullable
);
666 OS
.write(reinterpret_cast<const char *>(bytes
), 2);
668 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
669 writer
.write
<uint16_t>(VI
.getType().size());
670 OS
.write(VI
.getType().data(), VI
.getType().size());
673 /// Used to serialize the on-disk Objective-C property table.
674 class ObjCPropertyTableInfo
675 : public VersionedTableInfo
<ObjCPropertyTableInfo
,
676 std::tuple
<unsigned, unsigned, char>,
679 unsigned getKeyLength(key_type_ref
) {
680 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
683 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
684 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
685 writer
.write
<uint32_t>(std::get
<0>(Key
));
686 writer
.write
<uint32_t>(std::get
<1>(Key
));
687 writer
.write
<uint8_t>(std::get
<2>(Key
));
690 hash_value_type
ComputeHash(key_type_ref Key
) {
691 return static_cast<size_t>(llvm::hash_value(Key
));
694 unsigned getUnversionedInfoSize(const ObjCPropertyInfo
&OPI
) {
695 return getVariableInfoSize(OPI
) + 1;
698 void emitUnversionedInfo(raw_ostream
&OS
, const ObjCPropertyInfo
&OPI
) {
699 emitVariableInfo(OS
, OPI
);
702 if (auto value
= OPI
.getSwiftImportAsAccessors()) {
704 flags
|= value
.value() << 1;
711 void APINotesWriter::Implementation::writeObjCPropertyBlock(
712 llvm::BitstreamWriter
&Stream
) {
713 llvm::BCBlockRAII
Scope(Stream
, OBJC_PROPERTY_BLOCK_ID
, 3);
715 if (ObjCProperties
.empty())
719 llvm::SmallString
<4096> HashTableBlob
;
722 llvm::OnDiskChainedHashTableGenerator
<ObjCPropertyTableInfo
> Generator
;
723 for (auto &OP
: ObjCProperties
)
724 Generator
.insert(OP
.first
, OP
.second
);
726 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
727 // Make sure that no bucket is at offset 0
728 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
729 llvm::endianness::little
);
730 Offset
= Generator
.Emit(BlobStream
);
733 objc_property_block::ObjCPropertyDataLayout
ObjCPropertyData(Stream
);
734 ObjCPropertyData
.emit(Scratch
, Offset
, HashTableBlob
);
739 unsigned getFunctionInfoSize(const FunctionInfo
&);
740 void emitFunctionInfo(llvm::raw_ostream
&, const FunctionInfo
&);
741 void emitParamInfo(raw_ostream
&OS
, const ParamInfo
&PI
);
743 /// Used to serialize the on-disk Objective-C method table.
744 class ObjCMethodTableInfo
745 : public VersionedTableInfo
<ObjCMethodTableInfo
,
746 std::tuple
<unsigned, unsigned, char>,
749 unsigned getKeyLength(key_type_ref
) {
750 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
753 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
754 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
755 writer
.write
<uint32_t>(std::get
<0>(Key
));
756 writer
.write
<uint32_t>(std::get
<1>(Key
));
757 writer
.write
<uint8_t>(std::get
<2>(Key
));
760 hash_value_type
ComputeHash(key_type_ref key
) {
761 return static_cast<size_t>(llvm::hash_value(key
));
764 unsigned getUnversionedInfoSize(const ObjCMethodInfo
&OMI
) {
765 auto size
= getFunctionInfoSize(OMI
) + 1;
767 size
+= getParamInfoSize(*OMI
.Self
);
771 void emitUnversionedInfo(raw_ostream
&OS
, const ObjCMethodInfo
&OMI
) {
773 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
774 flags
= (flags
<< 1) | OMI
.DesignatedInit
;
775 flags
= (flags
<< 1) | OMI
.RequiredInit
;
776 flags
= (flags
<< 1) | static_cast<bool>(OMI
.Self
);
777 writer
.write
<uint8_t>(flags
);
779 emitFunctionInfo(OS
, OMI
);
782 emitParamInfo(OS
, *OMI
.Self
);
786 /// Used to serialize the on-disk C++ method table.
787 class CXXMethodTableInfo
788 : public VersionedTableInfo
<CXXMethodTableInfo
, SingleDeclTableKey
,
791 unsigned getKeyLength(key_type_ref
) {
792 return sizeof(uint32_t) + sizeof(uint32_t);
795 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
796 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
797 writer
.write
<uint32_t>(Key
.parentContextID
);
798 writer
.write
<uint32_t>(Key
.nameID
);
801 hash_value_type
ComputeHash(key_type_ref key
) {
802 return static_cast<size_t>(key
.hashValue());
805 unsigned getUnversionedInfoSize(const CXXMethodInfo
&MI
) {
806 auto size
= getFunctionInfoSize(MI
) + 1;
808 size
+= getParamInfoSize(*MI
.This
);
812 void emitUnversionedInfo(raw_ostream
&OS
, const CXXMethodInfo
&MI
) {
814 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
815 flags
= (flags
<< 1) | static_cast<bool>(MI
.This
);
816 writer
.write
<uint8_t>(flags
);
818 emitFunctionInfo(OS
, MI
);
820 emitParamInfo(OS
, *MI
.This
);
825 void APINotesWriter::Implementation::writeObjCMethodBlock(
826 llvm::BitstreamWriter
&Stream
) {
827 llvm::BCBlockRAII
Scope(Stream
, OBJC_METHOD_BLOCK_ID
, 3);
829 if (ObjCMethods
.empty())
833 llvm::SmallString
<4096> HashTableBlob
;
836 llvm::OnDiskChainedHashTableGenerator
<ObjCMethodTableInfo
> Generator
;
837 for (auto &OM
: ObjCMethods
)
838 Generator
.insert(OM
.first
, OM
.second
);
840 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
841 // Make sure that no bucket is at offset 0
842 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
843 llvm::endianness::little
);
844 Offset
= Generator
.Emit(BlobStream
);
847 objc_method_block::ObjCMethodDataLayout
ObjCMethodData(Stream
);
848 ObjCMethodData
.emit(Scratch
, Offset
, HashTableBlob
);
852 void APINotesWriter::Implementation::writeCXXMethodBlock(
853 llvm::BitstreamWriter
&Stream
) {
854 llvm::BCBlockRAII
Scope(Stream
, CXX_METHOD_BLOCK_ID
, 3);
856 if (CXXMethods
.empty())
860 llvm::SmallString
<4096> HashTableBlob
;
863 llvm::OnDiskChainedHashTableGenerator
<CXXMethodTableInfo
> Generator
;
864 for (auto &MD
: CXXMethods
)
865 Generator
.insert(MD
.first
, MD
.second
);
867 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
868 // Make sure that no bucket is at offset 0
869 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
870 llvm::endianness::little
);
871 Offset
= Generator
.Emit(BlobStream
);
874 cxx_method_block::CXXMethodDataLayout
CXXMethodData(Stream
);
875 CXXMethodData
.emit(Scratch
, Offset
, HashTableBlob
);
880 /// Used to serialize the on-disk C field table.
882 : public VersionedTableInfo
<FieldTableInfo
, SingleDeclTableKey
, FieldInfo
> {
884 unsigned getKeyLength(key_type_ref
) {
885 return sizeof(uint32_t) + sizeof(uint32_t);
888 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
889 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
890 writer
.write
<uint32_t>(Key
.parentContextID
);
891 writer
.write
<uint32_t>(Key
.nameID
);
894 hash_value_type
ComputeHash(key_type_ref key
) {
895 return static_cast<size_t>(key
.hashValue());
898 unsigned getUnversionedInfoSize(const FieldInfo
&FI
) {
899 return getVariableInfoSize(FI
);
902 void emitUnversionedInfo(raw_ostream
&OS
, const FieldInfo
&FI
) {
903 emitVariableInfo(OS
, FI
);
908 void APINotesWriter::Implementation::writeFieldBlock(
909 llvm::BitstreamWriter
&Stream
) {
910 llvm::BCBlockRAII
Scope(Stream
, FIELD_BLOCK_ID
, 3);
916 llvm::SmallString
<4096> HashTableBlob
;
919 llvm::OnDiskChainedHashTableGenerator
<FieldTableInfo
> Generator
;
920 for (auto &FD
: Fields
)
921 Generator
.insert(FD
.first
, FD
.second
);
923 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
924 // Make sure that no bucket is at offset 0
925 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
926 llvm::endianness::little
);
927 Offset
= Generator
.Emit(BlobStream
);
930 field_block::FieldDataLayout
FieldData(Stream
);
931 FieldData
.emit(Scratch
, Offset
, HashTableBlob
);
936 /// Used to serialize the on-disk Objective-C selector table.
937 class ObjCSelectorTableInfo
{
939 using key_type
= StoredObjCSelector
;
940 using key_type_ref
= const key_type
&;
941 using data_type
= SelectorID
;
942 using data_type_ref
= data_type
;
943 using hash_value_type
= unsigned;
944 using offset_type
= unsigned;
946 hash_value_type
ComputeHash(key_type_ref Key
) {
947 return llvm::DenseMapInfo
<StoredObjCSelector
>::getHashValue(Key
);
950 std::pair
<unsigned, unsigned>
951 EmitKeyDataLength(raw_ostream
&OS
, key_type_ref Key
, data_type_ref
) {
953 sizeof(uint16_t) + sizeof(uint32_t) * Key
.Identifiers
.size();
954 uint32_t DataLength
= sizeof(uint32_t);
956 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
957 writer
.write
<uint16_t>(KeyLength
);
958 writer
.write
<uint16_t>(DataLength
);
959 return {KeyLength
, DataLength
};
962 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
963 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
964 writer
.write
<uint16_t>(Key
.NumArgs
);
965 for (auto Identifier
: Key
.Identifiers
)
966 writer
.write
<uint32_t>(Identifier
);
969 void EmitData(raw_ostream
&OS
, key_type_ref
, data_type_ref Data
, unsigned) {
970 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
971 writer
.write
<uint32_t>(Data
);
976 void APINotesWriter::Implementation::writeObjCSelectorBlock(
977 llvm::BitstreamWriter
&Stream
) {
978 llvm::BCBlockRAII
Scope(Stream
, OBJC_SELECTOR_BLOCK_ID
, 3);
980 if (SelectorIDs
.empty())
984 llvm::SmallString
<4096> HashTableBlob
;
987 llvm::OnDiskChainedHashTableGenerator
<ObjCSelectorTableInfo
> Generator
;
988 for (auto &S
: SelectorIDs
)
989 Generator
.insert(S
.first
, S
.second
);
991 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
992 // Make sure that no bucket is at offset 0
993 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
994 llvm::endianness::little
);
995 Offset
= Generator
.Emit(BlobStream
);
998 objc_selector_block::ObjCSelectorDataLayout
ObjCSelectorData(Stream
);
999 ObjCSelectorData
.emit(Scratch
, Offset
, HashTableBlob
);
1004 /// Used to serialize the on-disk global variable table.
1005 class GlobalVariableTableInfo
1006 : public VersionedTableInfo
<GlobalVariableTableInfo
, SingleDeclTableKey
,
1007 GlobalVariableInfo
> {
1009 unsigned getKeyLength(key_type_ref
) {
1010 return sizeof(uint32_t) + sizeof(uint32_t);
1013 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
1014 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1015 writer
.write
<uint32_t>(Key
.parentContextID
);
1016 writer
.write
<uint32_t>(Key
.nameID
);
1019 hash_value_type
ComputeHash(key_type_ref Key
) {
1020 return static_cast<size_t>(Key
.hashValue());
1023 unsigned getUnversionedInfoSize(const GlobalVariableInfo
&GVI
) {
1024 return getVariableInfoSize(GVI
);
1027 void emitUnversionedInfo(raw_ostream
&OS
, const GlobalVariableInfo
&GVI
) {
1028 emitVariableInfo(OS
, GVI
);
1033 void APINotesWriter::Implementation::writeGlobalVariableBlock(
1034 llvm::BitstreamWriter
&Stream
) {
1035 llvm::BCBlockRAII
Scope(Stream
, GLOBAL_VARIABLE_BLOCK_ID
, 3);
1037 if (GlobalVariables
.empty())
1041 llvm::SmallString
<4096> HashTableBlob
;
1044 llvm::OnDiskChainedHashTableGenerator
<GlobalVariableTableInfo
> Generator
;
1045 for (auto &GV
: GlobalVariables
)
1046 Generator
.insert(GV
.first
, GV
.second
);
1048 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
1049 // Make sure that no bucket is at offset 0
1050 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
1051 llvm::endianness::little
);
1052 Offset
= Generator
.Emit(BlobStream
);
1055 global_variable_block::GlobalVariableDataLayout
GlobalVariableData(Stream
);
1056 GlobalVariableData
.emit(Scratch
, Offset
, HashTableBlob
);
1061 unsigned getParamInfoSize(const ParamInfo
&PI
) {
1062 return getVariableInfoSize(PI
) + 1;
1065 void emitParamInfo(raw_ostream
&OS
, const ParamInfo
&PI
) {
1066 emitVariableInfo(OS
, PI
);
1069 if (auto noescape
= PI
.isNoEscape()) {
1075 if (auto lifetimebound
= PI
.isLifetimebound()) {
1081 if (auto RCC
= PI
.getRetainCountConvention())
1082 flags
|= static_cast<uint8_t>(RCC
.value()) + 1;
1084 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1085 writer
.write
<uint8_t>(flags
);
1088 /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
1090 unsigned getFunctionInfoSize(const FunctionInfo
&FI
) {
1091 unsigned size
= getCommonEntityInfoSize(FI
) + 2 + sizeof(uint64_t);
1092 size
+= sizeof(uint16_t);
1093 for (const auto &P
: FI
.Params
)
1094 size
+= getParamInfoSize(P
);
1095 size
+= sizeof(uint16_t) + FI
.ResultType
.size();
1096 size
+= sizeof(uint16_t) + FI
.SwiftReturnOwnership
.size();
1100 /// Emit a serialized representation of the function information.
1101 void emitFunctionInfo(raw_ostream
&OS
, const FunctionInfo
&FI
) {
1102 emitCommonEntityInfo(OS
, FI
);
1105 flags
|= FI
.NullabilityAudited
;
1107 if (auto RCC
= FI
.getRetainCountConvention())
1108 flags
|= static_cast<uint8_t>(RCC
.value()) + 1;
1110 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1112 writer
.write
<uint8_t>(flags
);
1113 writer
.write
<uint8_t>(FI
.NumAdjustedNullable
);
1114 writer
.write
<uint64_t>(FI
.NullabilityPayload
);
1116 writer
.write
<uint16_t>(FI
.Params
.size());
1117 for (const auto &PI
: FI
.Params
)
1118 emitParamInfo(OS
, PI
);
1120 writer
.write
<uint16_t>(FI
.ResultType
.size());
1121 writer
.write(ArrayRef
<char>{FI
.ResultType
.data(), FI
.ResultType
.size()});
1122 writer
.write
<uint16_t>(FI
.SwiftReturnOwnership
.size());
1123 writer
.write(ArrayRef
<char>{FI
.SwiftReturnOwnership
.data(),
1124 FI
.SwiftReturnOwnership
.size()});
1127 /// Used to serialize the on-disk global function table.
1128 class GlobalFunctionTableInfo
1129 : public VersionedTableInfo
<GlobalFunctionTableInfo
, SingleDeclTableKey
,
1130 GlobalFunctionInfo
> {
1132 unsigned getKeyLength(key_type_ref
) {
1133 return sizeof(uint32_t) + sizeof(uint32_t);
1136 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
1137 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1138 writer
.write
<uint32_t>(Key
.parentContextID
);
1139 writer
.write
<uint32_t>(Key
.nameID
);
1142 hash_value_type
ComputeHash(key_type_ref Key
) {
1143 return static_cast<size_t>(Key
.hashValue());
1146 unsigned getUnversionedInfoSize(const GlobalFunctionInfo
&GFI
) {
1147 return getFunctionInfoSize(GFI
);
1150 void emitUnversionedInfo(raw_ostream
&OS
, const GlobalFunctionInfo
&GFI
) {
1151 emitFunctionInfo(OS
, GFI
);
1156 void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1157 llvm::BitstreamWriter
&Stream
) {
1158 llvm::BCBlockRAII
Scope(Stream
, GLOBAL_FUNCTION_BLOCK_ID
, 3);
1160 if (GlobalFunctions
.empty())
1164 llvm::SmallString
<4096> HashTableBlob
;
1167 llvm::OnDiskChainedHashTableGenerator
<GlobalFunctionTableInfo
> Generator
;
1168 for (auto &F
: GlobalFunctions
)
1169 Generator
.insert(F
.first
, F
.second
);
1171 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
1172 // Make sure that no bucket is at offset 0
1173 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
1174 llvm::endianness::little
);
1175 Offset
= Generator
.Emit(BlobStream
);
1178 global_function_block::GlobalFunctionDataLayout
GlobalFunctionData(Stream
);
1179 GlobalFunctionData
.emit(Scratch
, Offset
, HashTableBlob
);
1184 /// Used to serialize the on-disk global enum constant.
1185 class EnumConstantTableInfo
1186 : public VersionedTableInfo
<EnumConstantTableInfo
, unsigned,
1189 unsigned getKeyLength(key_type_ref
) { return sizeof(uint32_t); }
1191 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
1192 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1193 writer
.write
<uint32_t>(Key
);
1196 hash_value_type
ComputeHash(key_type_ref Key
) {
1197 return static_cast<size_t>(llvm::hash_value(Key
));
1200 unsigned getUnversionedInfoSize(const EnumConstantInfo
&ECI
) {
1201 return getCommonEntityInfoSize(ECI
);
1204 void emitUnversionedInfo(raw_ostream
&OS
, const EnumConstantInfo
&ECI
) {
1205 emitCommonEntityInfo(OS
, ECI
);
1210 void APINotesWriter::Implementation::writeEnumConstantBlock(
1211 llvm::BitstreamWriter
&Stream
) {
1212 llvm::BCBlockRAII
Scope(Stream
, ENUM_CONSTANT_BLOCK_ID
, 3);
1214 if (EnumConstants
.empty())
1218 llvm::SmallString
<4096> HashTableBlob
;
1221 llvm::OnDiskChainedHashTableGenerator
<EnumConstantTableInfo
> Generator
;
1222 for (auto &EC
: EnumConstants
)
1223 Generator
.insert(EC
.first
, EC
.second
);
1225 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
1226 // Make sure that no bucket is at offset 0
1227 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
1228 llvm::endianness::little
);
1229 Offset
= Generator
.Emit(BlobStream
);
1232 enum_constant_block::EnumConstantDataLayout
EnumConstantData(Stream
);
1233 EnumConstantData
.emit(Scratch
, Offset
, HashTableBlob
);
1238 template <typename Derived
, typename UnversionedDataType
>
1239 class CommonTypeTableInfo
1240 : public VersionedTableInfo
<Derived
, SingleDeclTableKey
,
1241 UnversionedDataType
> {
1243 using key_type_ref
= typename
CommonTypeTableInfo::key_type_ref
;
1244 using hash_value_type
= typename
CommonTypeTableInfo::hash_value_type
;
1246 unsigned getKeyLength(key_type_ref
) {
1247 return sizeof(uint32_t) + sizeof(IdentifierID
);
1250 void EmitKey(raw_ostream
&OS
, key_type_ref Key
, unsigned) {
1251 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1252 writer
.write
<uint32_t>(Key
.parentContextID
);
1253 writer
.write
<IdentifierID
>(Key
.nameID
);
1256 hash_value_type
ComputeHash(key_type_ref Key
) {
1257 return static_cast<size_t>(Key
.hashValue());
1260 unsigned getUnversionedInfoSize(const UnversionedDataType
&UDT
) {
1261 return getCommonTypeInfoSize(UDT
);
1264 void emitUnversionedInfo(raw_ostream
&OS
, const UnversionedDataType
&UDT
) {
1265 emitCommonTypeInfo(OS
, UDT
);
1269 /// Used to serialize the on-disk tag table.
1270 class TagTableInfo
: public CommonTypeTableInfo
<TagTableInfo
, TagInfo
> {
1272 unsigned getUnversionedInfoSize(const TagInfo
&TI
) {
1274 return 2 + (TI
.SwiftImportAs
? TI
.SwiftImportAs
->size() : 0) +
1275 2 + (TI
.SwiftRetainOp
? TI
.SwiftRetainOp
->size() : 0) +
1276 2 + (TI
.SwiftReleaseOp
? TI
.SwiftReleaseOp
->size() : 0) +
1277 2 + (TI
.SwiftConformance
? TI
.SwiftConformance
->size() : 0) +
1278 3 + getCommonTypeInfoSize(TI
);
1282 void emitUnversionedInfo(raw_ostream
&OS
, const TagInfo
&TI
) {
1283 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1286 if (auto extensibility
= TI
.EnumExtensibility
) {
1287 Flags
|= static_cast<uint8_t>(extensibility
.value()) + 1;
1288 assert((Flags
< (1 << 2)) && "must fit in two bits");
1292 if (auto value
= TI
.isFlagEnum())
1293 Flags
|= (value
.value() << 1 | 1 << 0);
1295 writer
.write
<uint8_t>(Flags
);
1297 if (auto Copyable
= TI
.isSwiftCopyable())
1298 writer
.write
<uint8_t>(*Copyable
? kSwiftConforms
: kSwiftDoesNotConform
);
1300 writer
.write
<uint8_t>(0);
1302 if (auto Escapable
= TI
.isSwiftEscapable())
1303 writer
.write
<uint8_t>(*Escapable
? kSwiftConforms
: kSwiftDoesNotConform
);
1305 writer
.write
<uint8_t>(0);
1307 if (auto ImportAs
= TI
.SwiftImportAs
) {
1308 writer
.write
<uint16_t>(ImportAs
->size() + 1);
1309 OS
.write(ImportAs
->c_str(), ImportAs
->size());
1311 writer
.write
<uint16_t>(0);
1313 if (auto RetainOp
= TI
.SwiftRetainOp
) {
1314 writer
.write
<uint16_t>(RetainOp
->size() + 1);
1315 OS
.write(RetainOp
->c_str(), RetainOp
->size());
1317 writer
.write
<uint16_t>(0);
1319 if (auto ReleaseOp
= TI
.SwiftReleaseOp
) {
1320 writer
.write
<uint16_t>(ReleaseOp
->size() + 1);
1321 OS
.write(ReleaseOp
->c_str(), ReleaseOp
->size());
1323 writer
.write
<uint16_t>(0);
1325 if (auto Conformance
= TI
.SwiftConformance
) {
1326 writer
.write
<uint16_t>(Conformance
->size() + 1);
1327 OS
.write(Conformance
->c_str(), Conformance
->size());
1329 writer
.write
<uint16_t>(0);
1332 emitCommonTypeInfo(OS
, TI
);
1337 void APINotesWriter::Implementation::writeTagBlock(
1338 llvm::BitstreamWriter
&Stream
) {
1339 llvm::BCBlockRAII
Scope(Stream
, TAG_BLOCK_ID
, 3);
1345 llvm::SmallString
<4096> HashTableBlob
;
1348 llvm::OnDiskChainedHashTableGenerator
<TagTableInfo
> Generator
;
1349 for (auto &T
: Tags
)
1350 Generator
.insert(T
.first
, T
.second
);
1352 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
1353 // Make sure that no bucket is at offset 0
1354 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
1355 llvm::endianness::little
);
1356 Offset
= Generator
.Emit(BlobStream
);
1359 tag_block::TagDataLayout
TagData(Stream
);
1360 TagData
.emit(Scratch
, Offset
, HashTableBlob
);
1365 /// Used to serialize the on-disk typedef table.
1366 class TypedefTableInfo
1367 : public CommonTypeTableInfo
<TypedefTableInfo
, TypedefInfo
> {
1369 unsigned getUnversionedInfoSize(const TypedefInfo
&TI
) {
1370 return 1 + getCommonTypeInfoSize(TI
);
1373 void emitUnversionedInfo(raw_ostream
&OS
, const TypedefInfo
&TI
) {
1374 llvm::support::endian::Writer
writer(OS
, llvm::endianness::little
);
1377 if (auto swiftWrapper
= TI
.SwiftWrapper
)
1378 Flags
|= static_cast<uint8_t>(*swiftWrapper
) + 1;
1380 writer
.write
<uint8_t>(Flags
);
1382 emitCommonTypeInfo(OS
, TI
);
1387 void APINotesWriter::Implementation::writeTypedefBlock(
1388 llvm::BitstreamWriter
&Stream
) {
1389 llvm::BCBlockRAII
Scope(Stream
, TYPEDEF_BLOCK_ID
, 3);
1391 if (Typedefs
.empty())
1395 llvm::SmallString
<4096> HashTableBlob
;
1398 llvm::OnDiskChainedHashTableGenerator
<TypedefTableInfo
> Generator
;
1399 for (auto &T
: Typedefs
)
1400 Generator
.insert(T
.first
, T
.second
);
1402 llvm::raw_svector_ostream
BlobStream(HashTableBlob
);
1403 // Make sure that no bucket is at offset 0
1404 llvm::support::endian::write
<uint32_t>(BlobStream
, 0,
1405 llvm::endianness::little
);
1406 Offset
= Generator
.Emit(BlobStream
);
1409 typedef_block::TypedefDataLayout
TypedefData(Stream
);
1410 TypedefData
.emit(Scratch
, Offset
, HashTableBlob
);
1416 APINotesWriter::APINotesWriter(llvm::StringRef ModuleName
, const FileEntry
*SF
)
1417 : Implementation(new class Implementation(ModuleName
, SF
)) {}
1419 APINotesWriter::~APINotesWriter() = default;
1421 void APINotesWriter::writeToStream(llvm::raw_ostream
&OS
) {
1422 Implementation
->writeToStream(OS
);
1425 ContextID
APINotesWriter::addContext(std::optional
<ContextID
> ParentCtxID
,
1426 llvm::StringRef Name
, ContextKind Kind
,
1427 const ContextInfo
&Info
,
1428 llvm::VersionTuple SwiftVersion
) {
1429 IdentifierID NameID
= Implementation
->getIdentifier(Name
);
1431 uint32_t RawParentCtxID
= ParentCtxID
? ParentCtxID
->Value
: -1;
1432 ContextTableKey
Key(RawParentCtxID
, static_cast<uint8_t>(Kind
), NameID
);
1433 auto Known
= Implementation
->Contexts
.find(Key
);
1434 if (Known
== Implementation
->Contexts
.end()) {
1435 unsigned NextID
= Implementation
->Contexts
.size() + 1;
1437 Implementation::VersionedSmallVector
<ContextInfo
> EmptyVersionedInfo
;
1438 Known
= Implementation
->Contexts
1439 .insert(std::make_pair(
1440 Key
, std::make_pair(NextID
, EmptyVersionedInfo
)))
1443 Implementation
->ContextNames
[NextID
] = NameID
;
1444 Implementation
->ParentContexts
[NextID
] = RawParentCtxID
;
1447 // Add this version information.
1448 auto &VersionedVec
= Known
->second
.second
;
1450 for (auto &Versioned
: VersionedVec
) {
1451 if (Versioned
.first
== SwiftVersion
) {
1452 Versioned
.second
|= Info
;
1459 VersionedVec
.push_back({SwiftVersion
, Info
});
1461 return ContextID(Known
->second
.first
);
1464 void APINotesWriter::addObjCProperty(ContextID CtxID
, StringRef Name
,
1465 bool IsInstanceProperty
,
1466 const ObjCPropertyInfo
&Info
,
1467 VersionTuple SwiftVersion
) {
1468 IdentifierID NameID
= Implementation
->getIdentifier(Name
);
1470 ->ObjCProperties
[std::make_tuple(CtxID
.Value
, NameID
, IsInstanceProperty
)]
1471 .push_back({SwiftVersion
, Info
});
1474 void APINotesWriter::addObjCMethod(ContextID CtxID
, ObjCSelectorRef Selector
,
1475 bool IsInstanceMethod
,
1476 const ObjCMethodInfo
&Info
,
1477 VersionTuple SwiftVersion
) {
1478 SelectorID SelID
= Implementation
->getSelector(Selector
);
1479 auto Key
= std::tuple
<unsigned, unsigned, char>{CtxID
.Value
, SelID
,
1481 Implementation
->ObjCMethods
[Key
].push_back({SwiftVersion
, Info
});
1483 // If this method is a designated initializer, update the class to note that
1484 // it has designated initializers.
1485 if (Info
.DesignatedInit
) {
1486 assert(Implementation
->ParentContexts
.contains(CtxID
.Value
));
1487 uint32_t ParentCtxID
= Implementation
->ParentContexts
[CtxID
.Value
];
1488 ContextTableKey
CtxKey(ParentCtxID
,
1489 static_cast<uint8_t>(ContextKind::ObjCClass
),
1490 Implementation
->ContextNames
[CtxID
.Value
]);
1491 assert(Implementation
->Contexts
.contains(CtxKey
));
1492 auto &VersionedVec
= Implementation
->Contexts
[CtxKey
].second
;
1494 for (auto &Versioned
: VersionedVec
) {
1495 if (Versioned
.first
== SwiftVersion
) {
1496 Versioned
.second
.setHasDesignatedInits(true);
1503 VersionedVec
.push_back({SwiftVersion
, ContextInfo()});
1504 VersionedVec
.back().second
.setHasDesignatedInits(true);
1509 void APINotesWriter::addCXXMethod(ContextID CtxID
, llvm::StringRef Name
,
1510 const CXXMethodInfo
&Info
,
1511 VersionTuple SwiftVersion
) {
1512 IdentifierID NameID
= Implementation
->getIdentifier(Name
);
1513 SingleDeclTableKey
Key(CtxID
.Value
, NameID
);
1514 Implementation
->CXXMethods
[Key
].push_back({SwiftVersion
, Info
});
1517 void APINotesWriter::addField(ContextID CtxID
, llvm::StringRef Name
,
1518 const FieldInfo
&Info
,
1519 VersionTuple SwiftVersion
) {
1520 IdentifierID NameID
= Implementation
->getIdentifier(Name
);
1521 SingleDeclTableKey
Key(CtxID
.Value
, NameID
);
1522 Implementation
->Fields
[Key
].push_back({SwiftVersion
, Info
});
1525 void APINotesWriter::addGlobalVariable(std::optional
<Context
> Ctx
,
1526 llvm::StringRef Name
,
1527 const GlobalVariableInfo
&Info
,
1528 VersionTuple SwiftVersion
) {
1529 IdentifierID VariableID
= Implementation
->getIdentifier(Name
);
1530 SingleDeclTableKey
Key(Ctx
, VariableID
);
1531 Implementation
->GlobalVariables
[Key
].push_back({SwiftVersion
, Info
});
1534 void APINotesWriter::addGlobalFunction(std::optional
<Context
> Ctx
,
1535 llvm::StringRef Name
,
1536 const GlobalFunctionInfo
&Info
,
1537 VersionTuple SwiftVersion
) {
1538 IdentifierID NameID
= Implementation
->getIdentifier(Name
);
1539 SingleDeclTableKey
Key(Ctx
, NameID
);
1540 Implementation
->GlobalFunctions
[Key
].push_back({SwiftVersion
, Info
});
1543 void APINotesWriter::addEnumConstant(llvm::StringRef Name
,
1544 const EnumConstantInfo
&Info
,
1545 VersionTuple SwiftVersion
) {
1546 IdentifierID EnumConstantID
= Implementation
->getIdentifier(Name
);
1547 Implementation
->EnumConstants
[EnumConstantID
].push_back({SwiftVersion
, Info
});
1550 void APINotesWriter::addTag(std::optional
<Context
> Ctx
, llvm::StringRef Name
,
1551 const TagInfo
&Info
, VersionTuple SwiftVersion
) {
1552 IdentifierID TagID
= Implementation
->getIdentifier(Name
);
1553 SingleDeclTableKey
Key(Ctx
, TagID
);
1554 Implementation
->Tags
[Key
].push_back({SwiftVersion
, Info
});
1557 void APINotesWriter::addTypedef(std::optional
<Context
> Ctx
,
1558 llvm::StringRef Name
, const TypedefInfo
&Info
,
1559 VersionTuple SwiftVersion
) {
1560 IdentifierID TypedefID
= Implementation
->getIdentifier(Name
);
1561 SingleDeclTableKey
Key(Ctx
, TypedefID
);
1562 Implementation
->Typedefs
[Key
].push_back({SwiftVersion
, Info
});
1564 } // namespace api_notes
1565 } // namespace clang