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