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