1 //===-- APINotesWriter.cpp - API Notes Writer -------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "clang/APINotes/APINotesWriter.h"
10 #include "APINotesFormat.h"
11 #include "clang/APINotes/Types.h"
12 #include "clang/Basic/FileManager.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/Bitstream/BitstreamWriter.h"
16 #include "llvm/Support/DJB.h"
17 #include "llvm/Support/OnDiskHashTable.h"
18 #include "llvm/Support/VersionTuple.h"
19
20 namespace clang {
21 namespace api_notes {
22 class APINotesWriter::Implementation {
23 friend class APINotesWriter;
24
25 template <typename T>
26 using VersionedSmallVector =
27 llvm::SmallVector<std::pair<llvm::VersionTuple, T>, 1>;
28
29 std::string ModuleName;
30 const FileEntry *SourceFile;
31
32 /// Scratch space for bitstream writing.
33 llvm::SmallVector<uint64_t, 64> Scratch;
34
35 /// Mapping from strings to identifier IDs.
36 llvm::StringMap<IdentifierID> IdentifierIDs;
37
38 /// Information about contexts (Objective-C classes or protocols or C++
39 /// namespaces).
40 ///
41 /// Indexed by the parent context ID, context kind and the identifier ID of
42 /// this context and provides both the context ID and information describing
43 /// the context within that module.
44 llvm::DenseMap<ContextTableKey,
45 std::pair<unsigned, VersionedSmallVector<ContextInfo>>>
46 Contexts;
47
48 /// Information about parent contexts for each context.
49 ///
50 /// Indexed by context ID, provides the parent context ID.
51 llvm::DenseMap<uint32_t, uint32_t> ParentContexts;
52
53 /// Mapping from context IDs to the identifier ID holding the name.
54 llvm::DenseMap<unsigned, unsigned> ContextNames;
55
56 /// Information about Objective-C properties.
57 ///
58 /// Indexed by the context ID, property name, and whether this is an
59 /// instance property.
60 llvm::DenseMap<
61 std::tuple<unsigned, unsigned, char>,
62 llvm::SmallVector<std::pair<VersionTuple, ObjCPropertyInfo>, 1>>
63 ObjCProperties;
64
65 /// Information about C record fields.
66 ///
67 /// Indexed by the context ID and name ID.
68 llvm::DenseMap<SingleDeclTableKey,
69 llvm::SmallVector<std::pair<VersionTuple, FieldInfo>, 1>>
70 Fields;
71
72 /// Information about Objective-C methods.
73 ///
74 /// Indexed by the context ID, selector ID, and Boolean (stored as a char)
75 /// indicating whether this is a class or instance method.
76 llvm::DenseMap<std::tuple<unsigned, unsigned, char>,
77 llvm::SmallVector<std::pair<VersionTuple, ObjCMethodInfo>, 1>>
78 ObjCMethods;
79
80 /// Information about C++ methods.
81 ///
82 /// Indexed by the context ID and name ID.
83 llvm::DenseMap<SingleDeclTableKey,
84 llvm::SmallVector<std::pair<VersionTuple, CXXMethodInfo>, 1>>
85 CXXMethods;
86
87 /// Mapping from selectors to selector ID.
88 llvm::DenseMap<StoredObjCSelector, SelectorID> SelectorIDs;
89
90 /// Information about global variables.
91 ///
92 /// Indexed by the context ID, identifier ID.
93 llvm::DenseMap<
94 SingleDeclTableKey,
95 llvm::SmallVector<std::pair<VersionTuple, GlobalVariableInfo>, 1>>
96 GlobalVariables;
97
98 /// Information about global functions.
99 ///
100 /// Indexed by the context ID, identifier ID.
101 llvm::DenseMap<
102 SingleDeclTableKey,
103 llvm::SmallVector<std::pair<VersionTuple, GlobalFunctionInfo>, 1>>
104 GlobalFunctions;
105
106 /// Information about enumerators.
107 ///
108 /// Indexed by the identifier ID.
109 llvm::DenseMap<
110 unsigned, llvm::SmallVector<std::pair<VersionTuple, EnumConstantInfo>, 1>>
111 EnumConstants;
112
113 /// Information about tags.
114 ///
115 /// Indexed by the context ID, identifier ID.
116 llvm::DenseMap<SingleDeclTableKey,
117 llvm::SmallVector<std::pair<VersionTuple, TagInfo>, 1>>
118 Tags;
119
120 /// Information about typedefs.
121 ///
122 /// Indexed by the context ID, identifier ID.
123 llvm::DenseMap<SingleDeclTableKey,
124 llvm::SmallVector<std::pair<VersionTuple, TypedefInfo>, 1>>
125 Typedefs;
126
127 /// Retrieve the ID for the given identifier.
getIdentifier(StringRef Identifier)128 IdentifierID getIdentifier(StringRef Identifier) {
129 if (Identifier.empty())
130 return 0;
131
132 // Add to the identifier table if missing.
133 return IdentifierIDs.try_emplace(Identifier, IdentifierIDs.size() + 1)
134 .first->second;
135 }
136
137 /// Retrieve the ID for the given selector.
getSelector(ObjCSelectorRef SelectorRef)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));
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
150 private:
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
166 public:
Implementation(llvm::StringRef ModuleName,const FileEntry * SF)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
writeToStream(llvm::raw_ostream & OS)173 void APINotesWriter::Implementation::writeToStream(llvm::raw_ostream &OS) {
174 llvm::SmallVector<char, 0> Buffer;
175
176 {
177 llvm::BitstreamWriter Stream(Buffer);
178
179 // Emit the signature.
180 for (unsigned char Byte : API_NOTES_SIGNATURE)
181 Stream.Emit(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
204 namespace {
205 /// Record the name of a block.
emitBlockID(llvm::BitstreamWriter & Stream,unsigned ID,llvm::StringRef Name)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});
210
211 // Emit the block name if present.
212 if (Name.empty())
213 return;
214 Stream.EmitRecord(
215 llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
216 llvm::ArrayRef<unsigned char>(
217 const_cast<unsigned char *>(
218 reinterpret_cast<const unsigned char *>(Name.data())),
219 Name.size()));
220 }
221
222 /// Record the name of a record within a block.
emitRecordID(llvm::BitstreamWriter & Stream,unsigned ID,llvm::StringRef Name)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");
226
227 llvm::SmallVector<unsigned char, 64> Buffer;
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
writeBlockInfoBlock(llvm::BitstreamWriter & Stream)236 void 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
writeControlBlock(llvm::BitstreamWriter & Stream)271 void 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
288 namespace {
289 /// Used to serialize the on-disk identifier table.
290 class IdentifierTableInfo {
291 public:
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
ComputeHash(key_type_ref Key)299 hash_value_type ComputeHash(key_type_ref Key) { return llvm::djbHash(Key); }
300
301 std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref)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
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)312 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) { OS << Key; }
313
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)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
writeIdentifierBlock(llvm::BitstreamWriter & Stream)321 void 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
346 namespace {
347 /// Used to serialize the on-disk Objective-C context table.
348 class ContextIDTableInfo {
349 public:
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
ComputeHash(key_type_ref Key)357 hash_value_type ComputeHash(key_type_ref Key) {
358 return static_cast<size_t>(Key.hashValue());
359 }
360
EmitKeyDataLength(raw_ostream & OS,key_type_ref,data_type_ref)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
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)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.
387 template <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.
getVersionTupleSize(const VersionTuple & VT)391 unsigned 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,
403 template <typename T>
getVersionedInfoSize(const llvm::SmallVectorImpl<std::pair<llvm::VersionTuple,T>> & VI,llvm::function_ref<unsigned (const typename MakeDependent<T>::Type &)> getInfoSize)404 unsigned 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.
emitVersionTuple(raw_ostream & OS,const VersionTuple & VT)417 void 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.
443 template <typename T>
emitVersionedInfo(raw_ostream & OS,llvm::SmallVectorImpl<std::pair<VersionTuple,T>> & VI,llvm::function_ref<void (raw_ostream &,const typename MakeDependent<T>::Type &)> emitInfo)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 &)>
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.
466 template <typename Derived, typename KeyType, typename UnversionedDataType>
467 class VersionedTableInfo {
asDerived()468 Derived &asDerived() { return *static_cast<Derived *>(this); }
469
asDerived() const470 const Derived &asDerived() const {
471 return *static_cast<const Derived *>(this);
472 }
473
474 public:
475 using key_type = KeyType;
476 using key_type_ref = key_type;
477 using data_type =
478 llvm::SmallVector<std::pair<llvm::VersionTuple, UnversionedDataType>, 1>;
479 using data_type_ref = data_type &;
480 using hash_value_type = size_t;
481 using offset_type = unsigned;
482
483 std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref Data)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
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)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.
emitCommonEntityInfo(raw_ostream & OS,const CommonEntityInfo & CEI)506 void 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.
getCommonEntityInfoSize(const CommonEntityInfo & CEI)531 unsigned 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.
getCommonTypeInfoSize(const CommonTypeInfo & CTI)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);
541 }
542
543 /// Emit a serialized representation of the common type information.
emitCommonTypeInfo(raw_ostream & OS,const CommonTypeInfo & CTI)544 void emitCommonTypeInfo(raw_ostream &OS, const CommonTypeInfo &CTI) {
545 emitCommonEntityInfo(OS, CTI);
546
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());
551 } else {
552 writer.write<uint16_t>(0);
553 }
554 if (auto nsErrorDomain = CTI.getNSErrorDomain()) {
555 writer.write<uint16_t>(nsErrorDomain->size() + 1);
556 OS.write(nsErrorDomain->c_str(), CTI.getNSErrorDomain()->size());
557 } else {
558 writer.write<uint16_t>(0);
559 }
560 }
561
562 /// Used to serialize the on-disk Objective-C property table.
563 class ContextInfoTableInfo
564 : public VersionedTableInfo<ContextInfoTableInfo, unsigned, ContextInfo> {
565 public:
getKeyLength(key_type_ref)566 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
567
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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);
571 }
572
ComputeHash(key_type_ref Key)573 hash_value_type ComputeHash(key_type_ref Key) {
574 return static_cast<size_t>(llvm::hash_value(Key));
575 }
576
getUnversionedInfoSize(const ContextInfo & OCI)577 unsigned getUnversionedInfoSize(const ContextInfo &OCI) {
578 return getCommonTypeInfoSize(OCI) + 1;
579 }
580
emitUnversionedInfo(raw_ostream & OS,const ContextInfo & OCI)581 void emitUnversionedInfo(raw_ostream &OS, const ContextInfo &OCI) {
582 emitCommonTypeInfo(OS, OCI);
583
584 uint8_t payload = 0;
585 if (auto swiftImportAsNonGeneric = OCI.getSwiftImportAsNonGeneric())
586 payload |= (0x01 << 1) | (uint8_t)swiftImportAsNonGeneric.value();
587 payload <<= 2;
588 if (auto swiftObjCMembers = OCI.getSwiftObjCMembers())
589 payload |= (0x01 << 1) | (uint8_t)swiftObjCMembers.value();
590 payload <<= 3;
591 if (auto nullable = OCI.getDefaultNullability())
592 payload |= (0x01 << 2) | static_cast<uint8_t>(*nullable);
593 payload = (payload << 1) | (OCI.hasDesignatedInits() ? 1 : 0);
594
595 OS << payload;
596 }
597 };
598 } // namespace
599
writeContextBlock(llvm::BitstreamWriter & Stream)600 void APINotesWriter::Implementation::writeContextBlock(
601 llvm::BitstreamWriter &Stream) {
602 llvm::BCBlockRAII restoreBlock(Stream, OBJC_CONTEXT_BLOCK_ID, 3);
603
604 if (Contexts.empty())
605 return;
606
607 {
608 llvm::SmallString<4096> HashTableBlob;
609 uint32_t Offset;
610 {
611 llvm::OnDiskChainedHashTableGenerator<ContextIDTableInfo> Generator;
612 for (auto &OC : Contexts)
613 Generator.insert(OC.first, OC.second.first);
614
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);
620 }
621
622 context_block::ContextIDLayout ContextID(Stream);
623 ContextID.emit(Scratch, Offset, HashTableBlob);
624 }
625
626 {
627 llvm::SmallString<4096> HashTableBlob;
628 uint32_t Offset;
629 {
630 llvm::OnDiskChainedHashTableGenerator<ContextInfoTableInfo> Generator;
631 for (auto &OC : Contexts)
632 Generator.insert(OC.second.first, OC.second.second);
633
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);
639 }
640
641 context_block::ContextInfoLayout ContextInfo(Stream);
642 ContextInfo.emit(Scratch, Offset, HashTableBlob);
643 }
644 }
645
646 namespace {
647 /// Retrieve the serialized size of the given VariableInfo, for use in
648 /// on-disk hash tables.
getVariableInfoSize(const VariableInfo & VI)649 unsigned getVariableInfoSize(const VariableInfo &VI) {
650 return 2 + getCommonEntityInfoSize(VI) + 2 + VI.getType().size();
651 }
652 unsigned getParamInfoSize(const ParamInfo &PI);
653
654 /// Emit a serialized representation of the variable information.
emitVariableInfo(raw_ostream & OS,const VariableInfo & VI)655 void emitVariableInfo(raw_ostream &OS, const VariableInfo &VI) {
656 emitCommonEntityInfo(OS, VI);
657
658 uint8_t bytes[2] = {0, 0};
659 if (auto nullable = VI.getNullability()) {
660 bytes[0] = 1;
661 bytes[1] = static_cast<uint8_t>(*nullable);
662 } else {
663 // Nothing to do.
664 }
665
666 OS.write(reinterpret_cast<const char *>(bytes), 2);
667
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());
671 }
672
673 /// Used to serialize the on-disk Objective-C property table.
674 class ObjCPropertyTableInfo
675 : public VersionedTableInfo<ObjCPropertyTableInfo,
676 std::tuple<unsigned, unsigned, char>,
677 ObjCPropertyInfo> {
678 public:
getKeyLength(key_type_ref)679 unsigned getKeyLength(key_type_ref) {
680 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
681 }
682
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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));
688 }
689
ComputeHash(key_type_ref Key)690 hash_value_type ComputeHash(key_type_ref Key) {
691 return static_cast<size_t>(llvm::hash_value(Key));
692 }
693
getUnversionedInfoSize(const ObjCPropertyInfo & OPI)694 unsigned getUnversionedInfoSize(const ObjCPropertyInfo &OPI) {
695 return getVariableInfoSize(OPI) + 1;
696 }
697
emitUnversionedInfo(raw_ostream & OS,const ObjCPropertyInfo & OPI)698 void emitUnversionedInfo(raw_ostream &OS, const ObjCPropertyInfo &OPI) {
699 emitVariableInfo(OS, OPI);
700
701 uint8_t flags = 0;
702 if (auto value = OPI.getSwiftImportAsAccessors()) {
703 flags |= 1 << 0;
704 flags |= value.value() << 1;
705 }
706 OS << flags;
707 }
708 };
709 } // namespace
710
writeObjCPropertyBlock(llvm::BitstreamWriter & Stream)711 void APINotesWriter::Implementation::writeObjCPropertyBlock(
712 llvm::BitstreamWriter &Stream) {
713 llvm::BCBlockRAII Scope(Stream, OBJC_PROPERTY_BLOCK_ID, 3);
714
715 if (ObjCProperties.empty())
716 return;
717
718 {
719 llvm::SmallString<4096> HashTableBlob;
720 uint32_t Offset;
721 {
722 llvm::OnDiskChainedHashTableGenerator<ObjCPropertyTableInfo> Generator;
723 for (auto &OP : ObjCProperties)
724 Generator.insert(OP.first, OP.second);
725
726 llvm::raw_svector_ostream BlobStream(HashTableBlob);
727 // Make sure that no bucket is at offset 0
728 llvm::support::endian::write<uint32_t>(BlobStream, 0,
729 llvm::endianness::little);
730 Offset = Generator.Emit(BlobStream);
731 }
732
733 objc_property_block::ObjCPropertyDataLayout ObjCPropertyData(Stream);
734 ObjCPropertyData.emit(Scratch, Offset, HashTableBlob);
735 }
736 }
737
738 namespace {
739 unsigned getFunctionInfoSize(const FunctionInfo &);
740 void emitFunctionInfo(llvm::raw_ostream &, const FunctionInfo &);
741 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI);
742
743 /// Used to serialize the on-disk Objective-C method table.
744 class ObjCMethodTableInfo
745 : public VersionedTableInfo<ObjCMethodTableInfo,
746 std::tuple<unsigned, unsigned, char>,
747 ObjCMethodInfo> {
748 public:
getKeyLength(key_type_ref)749 unsigned getKeyLength(key_type_ref) {
750 return sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
751 }
752
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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));
758 }
759
ComputeHash(key_type_ref key)760 hash_value_type ComputeHash(key_type_ref key) {
761 return static_cast<size_t>(llvm::hash_value(key));
762 }
763
getUnversionedInfoSize(const ObjCMethodInfo & OMI)764 unsigned getUnversionedInfoSize(const ObjCMethodInfo &OMI) {
765 auto size = getFunctionInfoSize(OMI) + 1;
766 if (OMI.Self)
767 size += getParamInfoSize(*OMI.Self);
768 return size;
769 }
770
emitUnversionedInfo(raw_ostream & OS,const ObjCMethodInfo & OMI)771 void emitUnversionedInfo(raw_ostream &OS, const ObjCMethodInfo &OMI) {
772 uint8_t flags = 0;
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);
778
779 emitFunctionInfo(OS, OMI);
780
781 if (OMI.Self)
782 emitParamInfo(OS, *OMI.Self);
783 }
784 };
785
786 /// Used to serialize the on-disk C++ method table.
787 class CXXMethodTableInfo
788 : public VersionedTableInfo<CXXMethodTableInfo, SingleDeclTableKey,
789 CXXMethodInfo> {
790 public:
getKeyLength(key_type_ref)791 unsigned getKeyLength(key_type_ref) {
792 return sizeof(uint32_t) + sizeof(uint32_t);
793 }
794
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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);
799 }
800
ComputeHash(key_type_ref key)801 hash_value_type ComputeHash(key_type_ref key) {
802 return static_cast<size_t>(key.hashValue());
803 }
804
getUnversionedInfoSize(const CXXMethodInfo & MI)805 unsigned getUnversionedInfoSize(const CXXMethodInfo &MI) {
806 auto size = getFunctionInfoSize(MI) + 1;
807 if (MI.This)
808 size += getParamInfoSize(*MI.This);
809 return size;
810 }
811
emitUnversionedInfo(raw_ostream & OS,const CXXMethodInfo & MI)812 void emitUnversionedInfo(raw_ostream &OS, const CXXMethodInfo &MI) {
813 uint8_t flags = 0;
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);
817
818 emitFunctionInfo(OS, MI);
819 if (MI.This)
820 emitParamInfo(OS, *MI.This);
821 }
822 };
823 } // namespace
824
writeObjCMethodBlock(llvm::BitstreamWriter & Stream)825 void APINotesWriter::Implementation::writeObjCMethodBlock(
826 llvm::BitstreamWriter &Stream) {
827 llvm::BCBlockRAII Scope(Stream, OBJC_METHOD_BLOCK_ID, 3);
828
829 if (ObjCMethods.empty())
830 return;
831
832 {
833 llvm::SmallString<4096> HashTableBlob;
834 uint32_t Offset;
835 {
836 llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> Generator;
837 for (auto &OM : ObjCMethods)
838 Generator.insert(OM.first, OM.second);
839
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);
845 }
846
847 objc_method_block::ObjCMethodDataLayout ObjCMethodData(Stream);
848 ObjCMethodData.emit(Scratch, Offset, HashTableBlob);
849 }
850 }
851
writeCXXMethodBlock(llvm::BitstreamWriter & Stream)852 void APINotesWriter::Implementation::writeCXXMethodBlock(
853 llvm::BitstreamWriter &Stream) {
854 llvm::BCBlockRAII Scope(Stream, CXX_METHOD_BLOCK_ID, 3);
855
856 if (CXXMethods.empty())
857 return;
858
859 {
860 llvm::SmallString<4096> HashTableBlob;
861 uint32_t Offset;
862 {
863 llvm::OnDiskChainedHashTableGenerator<CXXMethodTableInfo> Generator;
864 for (auto &MD : CXXMethods)
865 Generator.insert(MD.first, MD.second);
866
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);
872 }
873
874 cxx_method_block::CXXMethodDataLayout CXXMethodData(Stream);
875 CXXMethodData.emit(Scratch, Offset, HashTableBlob);
876 }
877 }
878
879 namespace {
880 /// Used to serialize the on-disk C field table.
881 class FieldTableInfo
882 : public VersionedTableInfo<FieldTableInfo, SingleDeclTableKey, FieldInfo> {
883 public:
getKeyLength(key_type_ref)884 unsigned getKeyLength(key_type_ref) {
885 return sizeof(uint32_t) + sizeof(uint32_t);
886 }
887
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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);
892 }
893
ComputeHash(key_type_ref key)894 hash_value_type ComputeHash(key_type_ref key) {
895 return static_cast<size_t>(key.hashValue());
896 }
897
getUnversionedInfoSize(const FieldInfo & FI)898 unsigned getUnversionedInfoSize(const FieldInfo &FI) {
899 return getVariableInfoSize(FI);
900 }
901
emitUnversionedInfo(raw_ostream & OS,const FieldInfo & FI)902 void emitUnversionedInfo(raw_ostream &OS, const FieldInfo &FI) {
903 emitVariableInfo(OS, FI);
904 }
905 };
906 } // namespace
907
writeFieldBlock(llvm::BitstreamWriter & Stream)908 void APINotesWriter::Implementation::writeFieldBlock(
909 llvm::BitstreamWriter &Stream) {
910 llvm::BCBlockRAII Scope(Stream, FIELD_BLOCK_ID, 3);
911
912 if (Fields.empty())
913 return;
914
915 {
916 llvm::SmallString<4096> HashTableBlob;
917 uint32_t Offset;
918 {
919 llvm::OnDiskChainedHashTableGenerator<FieldTableInfo> Generator;
920 for (auto &FD : Fields)
921 Generator.insert(FD.first, FD.second);
922
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);
928 }
929
930 field_block::FieldDataLayout FieldData(Stream);
931 FieldData.emit(Scratch, Offset, HashTableBlob);
932 }
933 }
934
935 namespace {
936 /// Used to serialize the on-disk Objective-C selector table.
937 class ObjCSelectorTableInfo {
938 public:
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;
945
ComputeHash(key_type_ref Key)946 hash_value_type ComputeHash(key_type_ref Key) {
947 return llvm::DenseMapInfo<StoredObjCSelector>::getHashValue(Key);
948 }
949
950 std::pair<unsigned, unsigned>
EmitKeyDataLength(raw_ostream & OS,key_type_ref Key,data_type_ref)951 EmitKeyDataLength(raw_ostream &OS, key_type_ref Key, data_type_ref) {
952 uint32_t KeyLength =
953 sizeof(uint16_t) + sizeof(uint32_t) * Key.Identifiers.size();
954 uint32_t DataLength = sizeof(uint32_t);
955
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};
960 }
961
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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);
967 }
968
EmitData(raw_ostream & OS,key_type_ref,data_type_ref Data,unsigned)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);
972 }
973 };
974 } // namespace
975
writeObjCSelectorBlock(llvm::BitstreamWriter & Stream)976 void APINotesWriter::Implementation::writeObjCSelectorBlock(
977 llvm::BitstreamWriter &Stream) {
978 llvm::BCBlockRAII Scope(Stream, OBJC_SELECTOR_BLOCK_ID, 3);
979
980 if (SelectorIDs.empty())
981 return;
982
983 {
984 llvm::SmallString<4096> HashTableBlob;
985 uint32_t Offset;
986 {
987 llvm::OnDiskChainedHashTableGenerator<ObjCSelectorTableInfo> Generator;
988 for (auto &S : SelectorIDs)
989 Generator.insert(S.first, S.second);
990
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);
996 }
997
998 objc_selector_block::ObjCSelectorDataLayout ObjCSelectorData(Stream);
999 ObjCSelectorData.emit(Scratch, Offset, HashTableBlob);
1000 }
1001 }
1002
1003 namespace {
1004 /// Used to serialize the on-disk global variable table.
1005 class GlobalVariableTableInfo
1006 : public VersionedTableInfo<GlobalVariableTableInfo, SingleDeclTableKey,
1007 GlobalVariableInfo> {
1008 public:
getKeyLength(key_type_ref)1009 unsigned getKeyLength(key_type_ref) {
1010 return sizeof(uint32_t) + sizeof(uint32_t);
1011 }
1012
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)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);
1017 }
1018
ComputeHash(key_type_ref Key)1019 hash_value_type ComputeHash(key_type_ref Key) {
1020 return static_cast<size_t>(Key.hashValue());
1021 }
1022
getUnversionedInfoSize(const GlobalVariableInfo & GVI)1023 unsigned getUnversionedInfoSize(const GlobalVariableInfo &GVI) {
1024 return getVariableInfoSize(GVI);
1025 }
1026
emitUnversionedInfo(raw_ostream & OS,const GlobalVariableInfo & GVI)1027 void emitUnversionedInfo(raw_ostream &OS, const GlobalVariableInfo &GVI) {
1028 emitVariableInfo(OS, GVI);
1029 }
1030 };
1031 } // namespace
1032
writeGlobalVariableBlock(llvm::BitstreamWriter & Stream)1033 void APINotesWriter::Implementation::writeGlobalVariableBlock(
1034 llvm::BitstreamWriter &Stream) {
1035 llvm::BCBlockRAII Scope(Stream, GLOBAL_VARIABLE_BLOCK_ID, 3);
1036
1037 if (GlobalVariables.empty())
1038 return;
1039
1040 {
1041 llvm::SmallString<4096> HashTableBlob;
1042 uint32_t Offset;
1043 {
1044 llvm::OnDiskChainedHashTableGenerator<GlobalVariableTableInfo> Generator;
1045 for (auto &GV : GlobalVariables)
1046 Generator.insert(GV.first, GV.second);
1047
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);
1053 }
1054
1055 global_variable_block::GlobalVariableDataLayout GlobalVariableData(Stream);
1056 GlobalVariableData.emit(Scratch, Offset, HashTableBlob);
1057 }
1058 }
1059
1060 namespace {
getParamInfoSize(const ParamInfo & PI)1061 unsigned getParamInfoSize(const ParamInfo &PI) {
1062 return getVariableInfoSize(PI) + 1;
1063 }
1064
emitParamInfo(raw_ostream & OS,const ParamInfo & PI)1065 void emitParamInfo(raw_ostream &OS, const ParamInfo &PI) {
1066 emitVariableInfo(OS, PI);
1067
1068 uint8_t flags = 0;
1069 if (auto noescape = PI.isNoEscape()) {
1070 flags |= 0x01;
1071 if (*noescape)
1072 flags |= 0x02;
1073 }
1074 flags <<= 2;
1075 if (auto lifetimebound = PI.isLifetimebound()) {
1076 flags |= 0x01;
1077 if (*lifetimebound)
1078 flags |= 0x02;
1079 }
1080 flags <<= 3;
1081 if (auto RCC = PI.getRetainCountConvention())
1082 flags |= static_cast<uint8_t>(RCC.value()) + 1;
1083
1084 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1085 writer.write<uint8_t>(flags);
1086 }
1087
1088 /// Retrieve the serialized size of the given FunctionInfo, for use in on-disk
1089 /// hash tables.
getFunctionInfoSize(const FunctionInfo & FI)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();
1097 return size;
1098 }
1099
1100 /// Emit a serialized representation of the function information.
emitFunctionInfo(raw_ostream & OS,const FunctionInfo & FI)1101 void emitFunctionInfo(raw_ostream &OS, const FunctionInfo &FI) {
1102 emitCommonEntityInfo(OS, FI);
1103
1104 uint8_t flags = 0;
1105 flags |= FI.NullabilityAudited;
1106 flags <<= 3;
1107 if (auto RCC = FI.getRetainCountConvention())
1108 flags |= static_cast<uint8_t>(RCC.value()) + 1;
1109
1110 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1111
1112 writer.write<uint8_t>(flags);
1113 writer.write<uint8_t>(FI.NumAdjustedNullable);
1114 writer.write<uint64_t>(FI.NullabilityPayload);
1115
1116 writer.write<uint16_t>(FI.Params.size());
1117 for (const auto &PI : FI.Params)
1118 emitParamInfo(OS, PI);
1119
1120 writer.write<uint16_t>(FI.ResultType.size());
1121 writer.write(ArrayRef<char>{FI.ResultType});
1122 writer.write<uint16_t>(FI.SwiftReturnOwnership.size());
1123 writer.write(ArrayRef<char>{FI.SwiftReturnOwnership});
1124 }
1125
1126 /// Used to serialize the on-disk global function table.
1127 class GlobalFunctionTableInfo
1128 : public VersionedTableInfo<GlobalFunctionTableInfo, SingleDeclTableKey,
1129 GlobalFunctionInfo> {
1130 public:
getKeyLength(key_type_ref)1131 unsigned getKeyLength(key_type_ref) {
1132 return sizeof(uint32_t) + sizeof(uint32_t);
1133 }
1134
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1135 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1136 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1137 writer.write<uint32_t>(Key.parentContextID);
1138 writer.write<uint32_t>(Key.nameID);
1139 }
1140
ComputeHash(key_type_ref Key)1141 hash_value_type ComputeHash(key_type_ref Key) {
1142 return static_cast<size_t>(Key.hashValue());
1143 }
1144
getUnversionedInfoSize(const GlobalFunctionInfo & GFI)1145 unsigned getUnversionedInfoSize(const GlobalFunctionInfo &GFI) {
1146 return getFunctionInfoSize(GFI);
1147 }
1148
emitUnversionedInfo(raw_ostream & OS,const GlobalFunctionInfo & GFI)1149 void emitUnversionedInfo(raw_ostream &OS, const GlobalFunctionInfo &GFI) {
1150 emitFunctionInfo(OS, GFI);
1151 }
1152 };
1153 } // namespace
1154
writeGlobalFunctionBlock(llvm::BitstreamWriter & Stream)1155 void APINotesWriter::Implementation::writeGlobalFunctionBlock(
1156 llvm::BitstreamWriter &Stream) {
1157 llvm::BCBlockRAII Scope(Stream, GLOBAL_FUNCTION_BLOCK_ID, 3);
1158
1159 if (GlobalFunctions.empty())
1160 return;
1161
1162 {
1163 llvm::SmallString<4096> HashTableBlob;
1164 uint32_t Offset;
1165 {
1166 llvm::OnDiskChainedHashTableGenerator<GlobalFunctionTableInfo> Generator;
1167 for (auto &F : GlobalFunctions)
1168 Generator.insert(F.first, F.second);
1169
1170 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1171 // Make sure that no bucket is at offset 0
1172 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1173 llvm::endianness::little);
1174 Offset = Generator.Emit(BlobStream);
1175 }
1176
1177 global_function_block::GlobalFunctionDataLayout GlobalFunctionData(Stream);
1178 GlobalFunctionData.emit(Scratch, Offset, HashTableBlob);
1179 }
1180 }
1181
1182 namespace {
1183 /// Used to serialize the on-disk global enum constant.
1184 class EnumConstantTableInfo
1185 : public VersionedTableInfo<EnumConstantTableInfo, unsigned,
1186 EnumConstantInfo> {
1187 public:
getKeyLength(key_type_ref)1188 unsigned getKeyLength(key_type_ref) { return sizeof(uint32_t); }
1189
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1190 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1191 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1192 writer.write<uint32_t>(Key);
1193 }
1194
ComputeHash(key_type_ref Key)1195 hash_value_type ComputeHash(key_type_ref Key) {
1196 return static_cast<size_t>(llvm::hash_value(Key));
1197 }
1198
getUnversionedInfoSize(const EnumConstantInfo & ECI)1199 unsigned getUnversionedInfoSize(const EnumConstantInfo &ECI) {
1200 return getCommonEntityInfoSize(ECI);
1201 }
1202
emitUnversionedInfo(raw_ostream & OS,const EnumConstantInfo & ECI)1203 void emitUnversionedInfo(raw_ostream &OS, const EnumConstantInfo &ECI) {
1204 emitCommonEntityInfo(OS, ECI);
1205 }
1206 };
1207 } // namespace
1208
writeEnumConstantBlock(llvm::BitstreamWriter & Stream)1209 void APINotesWriter::Implementation::writeEnumConstantBlock(
1210 llvm::BitstreamWriter &Stream) {
1211 llvm::BCBlockRAII Scope(Stream, ENUM_CONSTANT_BLOCK_ID, 3);
1212
1213 if (EnumConstants.empty())
1214 return;
1215
1216 {
1217 llvm::SmallString<4096> HashTableBlob;
1218 uint32_t Offset;
1219 {
1220 llvm::OnDiskChainedHashTableGenerator<EnumConstantTableInfo> Generator;
1221 for (auto &EC : EnumConstants)
1222 Generator.insert(EC.first, EC.second);
1223
1224 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1225 // Make sure that no bucket is at offset 0
1226 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1227 llvm::endianness::little);
1228 Offset = Generator.Emit(BlobStream);
1229 }
1230
1231 enum_constant_block::EnumConstantDataLayout EnumConstantData(Stream);
1232 EnumConstantData.emit(Scratch, Offset, HashTableBlob);
1233 }
1234 }
1235
1236 namespace {
1237 template <typename Derived, typename UnversionedDataType>
1238 class CommonTypeTableInfo
1239 : public VersionedTableInfo<Derived, SingleDeclTableKey,
1240 UnversionedDataType> {
1241 public:
1242 using key_type_ref = typename CommonTypeTableInfo::key_type_ref;
1243 using hash_value_type = typename CommonTypeTableInfo::hash_value_type;
1244
getKeyLength(key_type_ref)1245 unsigned getKeyLength(key_type_ref) {
1246 return sizeof(uint32_t) + sizeof(IdentifierID);
1247 }
1248
EmitKey(raw_ostream & OS,key_type_ref Key,unsigned)1249 void EmitKey(raw_ostream &OS, key_type_ref Key, unsigned) {
1250 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1251 writer.write<uint32_t>(Key.parentContextID);
1252 writer.write<IdentifierID>(Key.nameID);
1253 }
1254
ComputeHash(key_type_ref Key)1255 hash_value_type ComputeHash(key_type_ref Key) {
1256 return static_cast<size_t>(Key.hashValue());
1257 }
1258
getUnversionedInfoSize(const UnversionedDataType & UDT)1259 unsigned getUnversionedInfoSize(const UnversionedDataType &UDT) {
1260 return getCommonTypeInfoSize(UDT);
1261 }
1262
emitUnversionedInfo(raw_ostream & OS,const UnversionedDataType & UDT)1263 void emitUnversionedInfo(raw_ostream &OS, const UnversionedDataType &UDT) {
1264 emitCommonTypeInfo(OS, UDT);
1265 }
1266 };
1267
1268 /// Used to serialize the on-disk tag table.
1269 class TagTableInfo : public CommonTypeTableInfo<TagTableInfo, TagInfo> {
1270 public:
getUnversionedInfoSize(const TagInfo & TI)1271 unsigned getUnversionedInfoSize(const TagInfo &TI) {
1272 // clang-format off
1273 return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) +
1274 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) +
1275 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) +
1276 2 + (TI.SwiftDefaultOwnership ? TI.SwiftDefaultOwnership->size() : 0) +
1277 2 + (TI.SwiftConformance ? TI.SwiftConformance->size() : 0) +
1278 3 + getCommonTypeInfoSize(TI);
1279 // clang-format on
1280 }
1281
emitUnversionedInfo(raw_ostream & OS,const TagInfo & TI)1282 void emitUnversionedInfo(raw_ostream &OS, const TagInfo &TI) {
1283 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1284
1285 uint8_t Flags = 0;
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");
1289 }
1290
1291 Flags <<= 2;
1292 if (auto value = TI.isFlagEnum())
1293 Flags |= (value.value() << 1 | 1 << 0);
1294
1295 writer.write<uint8_t>(Flags);
1296
1297 if (auto Copyable = TI.isSwiftCopyable())
1298 writer.write<uint8_t>(*Copyable ? kSwiftConforms : kSwiftDoesNotConform);
1299 else
1300 writer.write<uint8_t>(0);
1301
1302 if (auto Escapable = TI.isSwiftEscapable())
1303 writer.write<uint8_t>(*Escapable ? kSwiftConforms : kSwiftDoesNotConform);
1304 else
1305 writer.write<uint8_t>(0);
1306
1307 if (auto ImportAs = TI.SwiftImportAs) {
1308 writer.write<uint16_t>(ImportAs->size() + 1);
1309 OS.write(ImportAs->c_str(), ImportAs->size());
1310 } else {
1311 writer.write<uint16_t>(0);
1312 }
1313 if (auto RetainOp = TI.SwiftRetainOp) {
1314 writer.write<uint16_t>(RetainOp->size() + 1);
1315 OS.write(RetainOp->c_str(), RetainOp->size());
1316 } else {
1317 writer.write<uint16_t>(0);
1318 }
1319 if (auto ReleaseOp = TI.SwiftReleaseOp) {
1320 writer.write<uint16_t>(ReleaseOp->size() + 1);
1321 OS.write(ReleaseOp->c_str(), ReleaseOp->size());
1322 } else {
1323 writer.write<uint16_t>(0);
1324 }
1325 if (auto DefaultOwnership = TI.SwiftDefaultOwnership) {
1326 writer.write<uint16_t>(DefaultOwnership->size() + 1);
1327 OS.write(DefaultOwnership->c_str(), DefaultOwnership->size());
1328 } else {
1329 writer.write<uint16_t>(0);
1330 }
1331 if (auto Conformance = TI.SwiftConformance) {
1332 writer.write<uint16_t>(Conformance->size() + 1);
1333 OS.write(Conformance->c_str(), Conformance->size());
1334 } else {
1335 writer.write<uint16_t>(0);
1336 }
1337
1338 emitCommonTypeInfo(OS, TI);
1339 }
1340 };
1341 } // namespace
1342
writeTagBlock(llvm::BitstreamWriter & Stream)1343 void APINotesWriter::Implementation::writeTagBlock(
1344 llvm::BitstreamWriter &Stream) {
1345 llvm::BCBlockRAII Scope(Stream, TAG_BLOCK_ID, 3);
1346
1347 if (Tags.empty())
1348 return;
1349
1350 {
1351 llvm::SmallString<4096> HashTableBlob;
1352 uint32_t Offset;
1353 {
1354 llvm::OnDiskChainedHashTableGenerator<TagTableInfo> Generator;
1355 for (auto &T : Tags)
1356 Generator.insert(T.first, T.second);
1357
1358 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1359 // Make sure that no bucket is at offset 0
1360 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1361 llvm::endianness::little);
1362 Offset = Generator.Emit(BlobStream);
1363 }
1364
1365 tag_block::TagDataLayout TagData(Stream);
1366 TagData.emit(Scratch, Offset, HashTableBlob);
1367 }
1368 }
1369
1370 namespace {
1371 /// Used to serialize the on-disk typedef table.
1372 class TypedefTableInfo
1373 : public CommonTypeTableInfo<TypedefTableInfo, TypedefInfo> {
1374 public:
getUnversionedInfoSize(const TypedefInfo & TI)1375 unsigned getUnversionedInfoSize(const TypedefInfo &TI) {
1376 return 1 + getCommonTypeInfoSize(TI);
1377 }
1378
emitUnversionedInfo(raw_ostream & OS,const TypedefInfo & TI)1379 void emitUnversionedInfo(raw_ostream &OS, const TypedefInfo &TI) {
1380 llvm::support::endian::Writer writer(OS, llvm::endianness::little);
1381
1382 uint8_t Flags = 0;
1383 if (auto swiftWrapper = TI.SwiftWrapper)
1384 Flags |= static_cast<uint8_t>(*swiftWrapper) + 1;
1385
1386 writer.write<uint8_t>(Flags);
1387
1388 emitCommonTypeInfo(OS, TI);
1389 }
1390 };
1391 } // namespace
1392
writeTypedefBlock(llvm::BitstreamWriter & Stream)1393 void APINotesWriter::Implementation::writeTypedefBlock(
1394 llvm::BitstreamWriter &Stream) {
1395 llvm::BCBlockRAII Scope(Stream, TYPEDEF_BLOCK_ID, 3);
1396
1397 if (Typedefs.empty())
1398 return;
1399
1400 {
1401 llvm::SmallString<4096> HashTableBlob;
1402 uint32_t Offset;
1403 {
1404 llvm::OnDiskChainedHashTableGenerator<TypedefTableInfo> Generator;
1405 for (auto &T : Typedefs)
1406 Generator.insert(T.first, T.second);
1407
1408 llvm::raw_svector_ostream BlobStream(HashTableBlob);
1409 // Make sure that no bucket is at offset 0
1410 llvm::support::endian::write<uint32_t>(BlobStream, 0,
1411 llvm::endianness::little);
1412 Offset = Generator.Emit(BlobStream);
1413 }
1414
1415 typedef_block::TypedefDataLayout TypedefData(Stream);
1416 TypedefData.emit(Scratch, Offset, HashTableBlob);
1417 }
1418 }
1419
1420 // APINotesWriter
1421
APINotesWriter(llvm::StringRef ModuleName,const FileEntry * SF)1422 APINotesWriter::APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF)
1423 : Implementation(new class Implementation(ModuleName, SF)) {}
1424
1425 APINotesWriter::~APINotesWriter() = default;
1426
writeToStream(llvm::raw_ostream & OS)1427 void APINotesWriter::writeToStream(llvm::raw_ostream &OS) {
1428 Implementation->writeToStream(OS);
1429 }
1430
addContext(std::optional<ContextID> ParentCtxID,llvm::StringRef Name,ContextKind Kind,const ContextInfo & Info,llvm::VersionTuple SwiftVersion)1431 ContextID APINotesWriter::addContext(std::optional<ContextID> ParentCtxID,
1432 llvm::StringRef Name, ContextKind Kind,
1433 const ContextInfo &Info,
1434 llvm::VersionTuple SwiftVersion) {
1435 IdentifierID NameID = Implementation->getIdentifier(Name);
1436
1437 uint32_t RawParentCtxID = ParentCtxID ? ParentCtxID->Value : -1;
1438 ContextTableKey Key(RawParentCtxID, static_cast<uint8_t>(Kind), NameID);
1439 auto Known = Implementation->Contexts.find(Key);
1440 if (Known == Implementation->Contexts.end()) {
1441 unsigned NextID = Implementation->Contexts.size() + 1;
1442
1443 Implementation::VersionedSmallVector<ContextInfo> EmptyVersionedInfo;
1444 Known = Implementation->Contexts
1445 .insert(std::make_pair(
1446 Key, std::make_pair(NextID, EmptyVersionedInfo)))
1447 .first;
1448
1449 Implementation->ContextNames[NextID] = NameID;
1450 Implementation->ParentContexts[NextID] = RawParentCtxID;
1451 }
1452
1453 // Add this version information.
1454 auto &VersionedVec = Known->second.second;
1455 bool Found = false;
1456 for (auto &Versioned : VersionedVec) {
1457 if (Versioned.first == SwiftVersion) {
1458 Versioned.second |= Info;
1459 Found = true;
1460 break;
1461 }
1462 }
1463
1464 if (!Found)
1465 VersionedVec.push_back({SwiftVersion, Info});
1466
1467 return ContextID(Known->second.first);
1468 }
1469
addObjCProperty(ContextID CtxID,StringRef Name,bool IsInstanceProperty,const ObjCPropertyInfo & Info,VersionTuple SwiftVersion)1470 void APINotesWriter::addObjCProperty(ContextID CtxID, StringRef Name,
1471 bool IsInstanceProperty,
1472 const ObjCPropertyInfo &Info,
1473 VersionTuple SwiftVersion) {
1474 IdentifierID NameID = Implementation->getIdentifier(Name);
1475 Implementation
1476 ->ObjCProperties[std::make_tuple(CtxID.Value, NameID, IsInstanceProperty)]
1477 .push_back({SwiftVersion, Info});
1478 }
1479
addObjCMethod(ContextID CtxID,ObjCSelectorRef Selector,bool IsInstanceMethod,const ObjCMethodInfo & Info,VersionTuple SwiftVersion)1480 void APINotesWriter::addObjCMethod(ContextID CtxID, ObjCSelectorRef Selector,
1481 bool IsInstanceMethod,
1482 const ObjCMethodInfo &Info,
1483 VersionTuple SwiftVersion) {
1484 SelectorID SelID = Implementation->getSelector(Selector);
1485 auto Key = std::tuple<unsigned, unsigned, char>{CtxID.Value, SelID,
1486 IsInstanceMethod};
1487 Implementation->ObjCMethods[Key].push_back({SwiftVersion, Info});
1488
1489 // If this method is a designated initializer, update the class to note that
1490 // it has designated initializers.
1491 if (Info.DesignatedInit) {
1492 assert(Implementation->ParentContexts.contains(CtxID.Value));
1493 uint32_t ParentCtxID = Implementation->ParentContexts[CtxID.Value];
1494 ContextTableKey CtxKey(ParentCtxID,
1495 static_cast<uint8_t>(ContextKind::ObjCClass),
1496 Implementation->ContextNames[CtxID.Value]);
1497 assert(Implementation->Contexts.contains(CtxKey));
1498 auto &VersionedVec = Implementation->Contexts[CtxKey].second;
1499 bool Found = false;
1500 for (auto &Versioned : VersionedVec) {
1501 if (Versioned.first == SwiftVersion) {
1502 Versioned.second.setHasDesignatedInits(true);
1503 Found = true;
1504 break;
1505 }
1506 }
1507
1508 if (!Found) {
1509 VersionedVec.push_back({SwiftVersion, ContextInfo()});
1510 VersionedVec.back().second.setHasDesignatedInits(true);
1511 }
1512 }
1513 }
1514
addCXXMethod(ContextID CtxID,llvm::StringRef Name,const CXXMethodInfo & Info,VersionTuple SwiftVersion)1515 void APINotesWriter::addCXXMethod(ContextID CtxID, llvm::StringRef Name,
1516 const CXXMethodInfo &Info,
1517 VersionTuple SwiftVersion) {
1518 IdentifierID NameID = Implementation->getIdentifier(Name);
1519 SingleDeclTableKey Key(CtxID.Value, NameID);
1520 Implementation->CXXMethods[Key].push_back({SwiftVersion, Info});
1521 }
1522
addField(ContextID CtxID,llvm::StringRef Name,const FieldInfo & Info,VersionTuple SwiftVersion)1523 void APINotesWriter::addField(ContextID CtxID, llvm::StringRef Name,
1524 const FieldInfo &Info,
1525 VersionTuple SwiftVersion) {
1526 IdentifierID NameID = Implementation->getIdentifier(Name);
1527 SingleDeclTableKey Key(CtxID.Value, NameID);
1528 Implementation->Fields[Key].push_back({SwiftVersion, Info});
1529 }
1530
addGlobalVariable(std::optional<Context> Ctx,llvm::StringRef Name,const GlobalVariableInfo & Info,VersionTuple SwiftVersion)1531 void APINotesWriter::addGlobalVariable(std::optional<Context> Ctx,
1532 llvm::StringRef Name,
1533 const GlobalVariableInfo &Info,
1534 VersionTuple SwiftVersion) {
1535 IdentifierID VariableID = Implementation->getIdentifier(Name);
1536 SingleDeclTableKey Key(Ctx, VariableID);
1537 Implementation->GlobalVariables[Key].push_back({SwiftVersion, Info});
1538 }
1539
addGlobalFunction(std::optional<Context> Ctx,llvm::StringRef Name,const GlobalFunctionInfo & Info,VersionTuple SwiftVersion)1540 void APINotesWriter::addGlobalFunction(std::optional<Context> Ctx,
1541 llvm::StringRef Name,
1542 const GlobalFunctionInfo &Info,
1543 VersionTuple SwiftVersion) {
1544 IdentifierID NameID = Implementation->getIdentifier(Name);
1545 SingleDeclTableKey Key(Ctx, NameID);
1546 Implementation->GlobalFunctions[Key].push_back({SwiftVersion, Info});
1547 }
1548
addEnumConstant(llvm::StringRef Name,const EnumConstantInfo & Info,VersionTuple SwiftVersion)1549 void APINotesWriter::addEnumConstant(llvm::StringRef Name,
1550 const EnumConstantInfo &Info,
1551 VersionTuple SwiftVersion) {
1552 IdentifierID EnumConstantID = Implementation->getIdentifier(Name);
1553 Implementation->EnumConstants[EnumConstantID].push_back({SwiftVersion, Info});
1554 }
1555
addTag(std::optional<Context> Ctx,llvm::StringRef Name,const TagInfo & Info,VersionTuple SwiftVersion)1556 void APINotesWriter::addTag(std::optional<Context> Ctx, llvm::StringRef Name,
1557 const TagInfo &Info, VersionTuple SwiftVersion) {
1558 IdentifierID TagID = Implementation->getIdentifier(Name);
1559 SingleDeclTableKey Key(Ctx, TagID);
1560 Implementation->Tags[Key].push_back({SwiftVersion, Info});
1561 }
1562
addTypedef(std::optional<Context> Ctx,llvm::StringRef Name,const TypedefInfo & Info,VersionTuple SwiftVersion)1563 void APINotesWriter::addTypedef(std::optional<Context> Ctx,
1564 llvm::StringRef Name, const TypedefInfo &Info,
1565 VersionTuple SwiftVersion) {
1566 IdentifierID TypedefID = Implementation->getIdentifier(Name);
1567 SingleDeclTableKey Key(Ctx, TypedefID);
1568 Implementation->Typedefs[Key].push_back({SwiftVersion, Info});
1569 }
1570 } // namespace api_notes
1571 } // namespace clang
1572