1 //===- ASTReaderInternals.h - AST Reader Internals --------------*- 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 // This file provides internal definitions used in the AST reader. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H 14 #define LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H 15 16 #include "MultiOnDiskHashTable.h" 17 #include "clang/AST/DeclarationName.h" 18 #include "clang/Basic/LLVM.h" 19 #include "clang/Serialization/ASTBitCodes.h" 20 #include "llvm/ADT/DenseSet.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/Support/OnDiskHashTable.h" 24 #include <ctime> 25 #include <utility> 26 27 namespace clang { 28 29 class ASTReader; 30 class FileEntry; 31 struct HeaderFileInfo; 32 class HeaderSearch; 33 class ObjCMethodDecl; 34 class Module; 35 36 namespace serialization { 37 38 class ModuleFile; 39 40 namespace reader { 41 42 class ASTDeclContextNameLookupTraitBase { 43 protected: 44 ASTReader &Reader; 45 ModuleFile &F; 46 47 public: 48 // Maximum number of lookup tables we allow before condensing the tables. 49 static const int MaxTables = 4; 50 51 /// The lookup result is a list of global declaration IDs. 52 using data_type = SmallVector<GlobalDeclID, 4>; 53 54 struct data_type_builder { 55 data_type &Data; 56 llvm::DenseSet<GlobalDeclID> Found; 57 data_type_builderdata_type_builder58 data_type_builder(data_type &D) : Data(D) {} 59 insertdata_type_builder60 void insert(GlobalDeclID ID) { 61 // Just use a linear scan unless we have more than a few IDs. 62 if (Found.empty() && !Data.empty()) { 63 if (Data.size() <= 4) { 64 for (auto I : Found) 65 if (I == ID) 66 return; 67 Data.push_back(ID); 68 return; 69 } 70 71 // Switch to tracking found IDs in the set. 72 Found.insert_range(Data); 73 } 74 75 if (Found.insert(ID).second) 76 Data.push_back(ID); 77 } 78 }; 79 using hash_value_type = unsigned; 80 using offset_type = unsigned; 81 using file_type = ModuleFile *; 82 83 protected: ASTDeclContextNameLookupTraitBase(ASTReader & Reader,ModuleFile & F)84 explicit ASTDeclContextNameLookupTraitBase(ASTReader &Reader, ModuleFile &F) 85 : Reader(Reader), F(F) {} 86 87 public: 88 static std::pair<unsigned, unsigned> 89 ReadKeyDataLength(const unsigned char *&d); 90 91 void ReadDataIntoImpl(const unsigned char *d, unsigned DataLen, 92 data_type_builder &Val); 93 MergeDataInto(const data_type & From,data_type_builder & To)94 static void MergeDataInto(const data_type &From, data_type_builder &To) { 95 To.Data.reserve(To.Data.size() + From.size()); 96 for (GlobalDeclID ID : From) 97 To.insert(ID); 98 } 99 100 file_type ReadFileRef(const unsigned char *&d); 101 102 DeclarationNameKey ReadKeyBase(const unsigned char *&d); 103 }; 104 105 /// Class that performs name lookup into a DeclContext stored 106 /// in an AST file. 107 class ASTDeclContextNameLookupTrait : public ASTDeclContextNameLookupTraitBase { 108 public: ASTDeclContextNameLookupTrait(ASTReader & Reader,ModuleFile & F)109 explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) 110 : ASTDeclContextNameLookupTraitBase(Reader, F) {} 111 112 using external_key_type = DeclarationName; 113 using internal_key_type = DeclarationNameKey; 114 EqualKey(const internal_key_type & a,const internal_key_type & b)115 static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { 116 return a == b; 117 } 118 ComputeHash(const internal_key_type & Key)119 static hash_value_type ComputeHash(const internal_key_type &Key) { 120 return Key.getHash(); 121 } 122 GetInternalKey(const external_key_type & Name)123 static internal_key_type GetInternalKey(const external_key_type &Name) { 124 return Name; 125 } 126 127 internal_key_type ReadKey(const unsigned char *d, unsigned); 128 129 void ReadDataInto(internal_key_type, const unsigned char *d, 130 unsigned DataLen, data_type_builder &Val); 131 }; 132 133 struct DeclContextLookupTable { 134 MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table; 135 }; 136 137 class ModuleLocalNameLookupTrait : public ASTDeclContextNameLookupTraitBase { 138 public: ModuleLocalNameLookupTrait(ASTReader & Reader,ModuleFile & F)139 explicit ModuleLocalNameLookupTrait(ASTReader &Reader, ModuleFile &F) 140 : ASTDeclContextNameLookupTraitBase(Reader, F) {} 141 142 using external_key_type = std::pair<DeclarationName, const Module *>; 143 using internal_key_type = std::pair<DeclarationNameKey, unsigned>; 144 EqualKey(const internal_key_type & a,const internal_key_type & b)145 static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { 146 return a == b; 147 } 148 149 static hash_value_type ComputeHash(const internal_key_type &Key); 150 static internal_key_type GetInternalKey(const external_key_type &Key); 151 152 internal_key_type ReadKey(const unsigned char *d, unsigned); 153 154 void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, 155 data_type_builder &Val); 156 }; 157 158 struct ModuleLocalLookupTable { 159 MultiOnDiskHashTable<ModuleLocalNameLookupTrait> Table; 160 }; 161 162 using LazySpecializationInfo = GlobalDeclID; 163 164 /// Class that performs lookup to specialized decls. 165 class LazySpecializationInfoLookupTrait { 166 ASTReader &Reader; 167 ModuleFile &F; 168 169 public: 170 // Maximum number of lookup tables we allow before condensing the tables. 171 static const int MaxTables = 4; 172 173 /// The lookup result is a list of global declaration IDs. 174 using data_type = SmallVector<LazySpecializationInfo, 4>; 175 176 struct data_type_builder { 177 data_type &Data; 178 llvm::DenseSet<LazySpecializationInfo> Found; 179 data_type_builderdata_type_builder180 data_type_builder(data_type &D) : Data(D) {} 181 insertdata_type_builder182 void insert(LazySpecializationInfo Info) { 183 // Just use a linear scan unless we have more than a few IDs. 184 if (Found.empty() && !Data.empty()) { 185 if (Data.size() <= 4) { 186 for (auto I : Found) 187 if (I == Info) 188 return; 189 Data.push_back(Info); 190 return; 191 } 192 193 // Switch to tracking found IDs in the set. 194 Found.insert_range(Data); 195 } 196 197 if (Found.insert(Info).second) 198 Data.push_back(Info); 199 } 200 }; 201 using hash_value_type = unsigned; 202 using offset_type = unsigned; 203 using file_type = ModuleFile *; 204 205 using external_key_type = unsigned; 206 using internal_key_type = unsigned; 207 LazySpecializationInfoLookupTrait(ASTReader & Reader,ModuleFile & F)208 explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F) 209 : Reader(Reader), F(F) {} 210 EqualKey(const internal_key_type & a,const internal_key_type & b)211 static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { 212 return a == b; 213 } 214 ComputeHash(const internal_key_type & Key)215 static hash_value_type ComputeHash(const internal_key_type &Key) { 216 return Key; 217 } 218 GetInternalKey(const external_key_type & Name)219 static internal_key_type GetInternalKey(const external_key_type &Name) { 220 return Name; 221 } 222 223 static std::pair<unsigned, unsigned> 224 ReadKeyDataLength(const unsigned char *&d); 225 226 internal_key_type ReadKey(const unsigned char *d, unsigned); 227 228 void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, 229 data_type_builder &Val); 230 MergeDataInto(const data_type & From,data_type_builder & To)231 static void MergeDataInto(const data_type &From, data_type_builder &To) { 232 To.Data.reserve(To.Data.size() + From.size()); 233 for (LazySpecializationInfo Info : From) 234 To.insert(Info); 235 } 236 237 file_type ReadFileRef(const unsigned char *&d); 238 }; 239 240 struct LazySpecializationInfoLookupTable { 241 MultiOnDiskHashTable<LazySpecializationInfoLookupTrait> Table; 242 }; 243 244 /// Base class for the trait describing the on-disk hash table for the 245 /// identifiers in an AST file. 246 /// 247 /// This class is not useful by itself; rather, it provides common 248 /// functionality for accessing the on-disk hash table of identifiers 249 /// in an AST file. Different subclasses customize that functionality 250 /// based on what information they are interested in. Those subclasses 251 /// must provide the \c data_type type and the ReadData operation, only. 252 class ASTIdentifierLookupTraitBase { 253 public: 254 using external_key_type = StringRef; 255 using internal_key_type = StringRef; 256 using hash_value_type = unsigned; 257 using offset_type = unsigned; 258 EqualKey(const internal_key_type & a,const internal_key_type & b)259 static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { 260 return a == b; 261 } 262 263 static hash_value_type ComputeHash(const internal_key_type& a); 264 265 static std::pair<unsigned, unsigned> 266 ReadKeyDataLength(const unsigned char*& d); 267 268 // This hopefully will just get inlined and removed by the optimizer. 269 static const internal_key_type& GetInternalKey(const external_key_type & x)270 GetInternalKey(const external_key_type& x) { return x; } 271 272 // This hopefully will just get inlined and removed by the optimizer. 273 static const external_key_type& GetExternalKey(const internal_key_type & x)274 GetExternalKey(const internal_key_type& x) { return x; } 275 276 static internal_key_type ReadKey(const unsigned char* d, unsigned n); 277 }; 278 279 /// Class that performs lookup for an identifier stored in an AST file. 280 class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { 281 ASTReader &Reader; 282 ModuleFile &F; 283 284 // If we know the IdentifierInfo in advance, it is here and we will 285 // not build a new one. Used when deserializing information about an 286 // identifier that was constructed before the AST file was read. 287 IdentifierInfo *KnownII; 288 289 bool hasMacroDefinitionInDependencies = false; 290 291 public: 292 using data_type = IdentifierInfo *; 293 294 ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F, 295 IdentifierInfo *II = nullptr) Reader(Reader)296 : Reader(Reader), F(F), KnownII(II) {} 297 298 data_type ReadData(const internal_key_type& k, 299 const unsigned char* d, 300 unsigned DataLen); 301 302 IdentifierID ReadIdentifierID(const unsigned char *d); 303 getReader()304 ASTReader &getReader() const { return Reader; } 305 hasMoreInformationInDependencies()306 bool hasMoreInformationInDependencies() const { 307 return hasMacroDefinitionInDependencies; 308 } 309 }; 310 311 /// The on-disk hash table used to contain information about 312 /// all of the identifiers in the program. 313 using ASTIdentifierLookupTable = 314 llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>; 315 316 /// Class that performs lookup for a selector's entries in the global 317 /// method pool stored in an AST file. 318 class ASTSelectorLookupTrait { 319 ASTReader &Reader; 320 ModuleFile &F; 321 322 public: 323 struct data_type { 324 SelectorID ID; 325 unsigned InstanceBits; 326 unsigned FactoryBits; 327 bool InstanceHasMoreThanOneDecl; 328 bool FactoryHasMoreThanOneDecl; 329 SmallVector<ObjCMethodDecl *, 2> Instance; 330 SmallVector<ObjCMethodDecl *, 2> Factory; 331 }; 332 333 using external_key_type = Selector; 334 using internal_key_type = external_key_type; 335 using hash_value_type = unsigned; 336 using offset_type = unsigned; 337 ASTSelectorLookupTrait(ASTReader & Reader,ModuleFile & F)338 ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F) 339 : Reader(Reader), F(F) {} 340 EqualKey(const internal_key_type & a,const internal_key_type & b)341 static bool EqualKey(const internal_key_type& a, 342 const internal_key_type& b) { 343 return a == b; 344 } 345 346 static hash_value_type ComputeHash(Selector Sel); 347 348 static const internal_key_type& GetInternalKey(const external_key_type & x)349 GetInternalKey(const external_key_type& x) { return x; } 350 351 static std::pair<unsigned, unsigned> 352 ReadKeyDataLength(const unsigned char*& d); 353 354 internal_key_type ReadKey(const unsigned char* d, unsigned); 355 data_type ReadData(Selector, const unsigned char* d, unsigned DataLen); 356 }; 357 358 /// The on-disk hash table used for the global method pool. 359 using ASTSelectorLookupTable = 360 llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>; 361 362 /// Trait class used to search the on-disk hash table containing all of 363 /// the header search information. 364 /// 365 /// The on-disk hash table contains a mapping from each header path to 366 /// information about that header (how many times it has been included, its 367 /// controlling macro, etc.). Note that we actually hash based on the size 368 /// and mtime, and support "deep" comparisons of file names based on current 369 /// inode numbers, so that the search can cope with non-normalized path names 370 /// and symlinks. 371 class HeaderFileInfoTrait { 372 ASTReader &Reader; 373 ModuleFile &M; 374 375 public: 376 using external_key_type = FileEntryRef; 377 378 struct internal_key_type { 379 off_t Size; 380 time_t ModTime; 381 StringRef Filename; 382 bool Imported; 383 }; 384 385 using internal_key_ref = const internal_key_type &; 386 387 using data_type = HeaderFileInfo; 388 using hash_value_type = unsigned; 389 using offset_type = unsigned; 390 HeaderFileInfoTrait(ASTReader & Reader,ModuleFile & M)391 HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M) 392 : Reader(Reader), M(M) {} 393 394 static hash_value_type ComputeHash(internal_key_ref ikey); 395 internal_key_type GetInternalKey(external_key_type ekey); 396 bool EqualKey(internal_key_ref a, internal_key_ref b); 397 398 static std::pair<unsigned, unsigned> 399 ReadKeyDataLength(const unsigned char*& d); 400 401 static internal_key_type ReadKey(const unsigned char *d, unsigned); 402 403 data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen); 404 405 private: 406 OptionalFileEntryRef getFile(const internal_key_type &Key); 407 }; 408 409 /// The on-disk hash table used for known header files. 410 using HeaderFileInfoLookupTable = 411 llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>; 412 413 } // namespace reader 414 415 } // namespace serialization 416 417 } // namespace clang 418 419 #endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H 420