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 58 data_type_builder(data_type &D) : Data(D) {} 59 60 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(Data.begin(), Data.end()); 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: 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 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: 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 115 static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { 116 return a == b; 117 } 118 119 static hash_value_type ComputeHash(const internal_key_type &Key) { 120 return Key.getHash(); 121 } 122 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: 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 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 180 data_type_builder(data_type &D) : Data(D) {} 181 182 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(Data.begin(), Data.end()); 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 208 explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F) 209 : Reader(Reader), F(F) {} 210 211 static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { 212 return a == b; 213 } 214 215 static hash_value_type ComputeHash(const internal_key_type &Key) { 216 return Key; 217 } 218 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 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 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& 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& 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 public: 290 using data_type = IdentifierInfo *; 291 292 ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F, 293 IdentifierInfo *II = nullptr) 294 : Reader(Reader), F(F), KnownII(II) {} 295 296 data_type ReadData(const internal_key_type& k, 297 const unsigned char* d, 298 unsigned DataLen); 299 300 IdentifierID ReadIdentifierID(const unsigned char *d); 301 302 ASTReader &getReader() const { return Reader; } 303 }; 304 305 /// The on-disk hash table used to contain information about 306 /// all of the identifiers in the program. 307 using ASTIdentifierLookupTable = 308 llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>; 309 310 /// Class that performs lookup for a selector's entries in the global 311 /// method pool stored in an AST file. 312 class ASTSelectorLookupTrait { 313 ASTReader &Reader; 314 ModuleFile &F; 315 316 public: 317 struct data_type { 318 SelectorID ID; 319 unsigned InstanceBits; 320 unsigned FactoryBits; 321 bool InstanceHasMoreThanOneDecl; 322 bool FactoryHasMoreThanOneDecl; 323 SmallVector<ObjCMethodDecl *, 2> Instance; 324 SmallVector<ObjCMethodDecl *, 2> Factory; 325 }; 326 327 using external_key_type = Selector; 328 using internal_key_type = external_key_type; 329 using hash_value_type = unsigned; 330 using offset_type = unsigned; 331 332 ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F) 333 : Reader(Reader), F(F) {} 334 335 static bool EqualKey(const internal_key_type& a, 336 const internal_key_type& b) { 337 return a == b; 338 } 339 340 static hash_value_type ComputeHash(Selector Sel); 341 342 static const internal_key_type& 343 GetInternalKey(const external_key_type& x) { return x; } 344 345 static std::pair<unsigned, unsigned> 346 ReadKeyDataLength(const unsigned char*& d); 347 348 internal_key_type ReadKey(const unsigned char* d, unsigned); 349 data_type ReadData(Selector, const unsigned char* d, unsigned DataLen); 350 }; 351 352 /// The on-disk hash table used for the global method pool. 353 using ASTSelectorLookupTable = 354 llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>; 355 356 /// Trait class used to search the on-disk hash table containing all of 357 /// the header search information. 358 /// 359 /// The on-disk hash table contains a mapping from each header path to 360 /// information about that header (how many times it has been included, its 361 /// controlling macro, etc.). Note that we actually hash based on the size 362 /// and mtime, and support "deep" comparisons of file names based on current 363 /// inode numbers, so that the search can cope with non-normalized path names 364 /// and symlinks. 365 class HeaderFileInfoTrait { 366 ASTReader &Reader; 367 ModuleFile &M; 368 369 public: 370 using external_key_type = FileEntryRef; 371 372 struct internal_key_type { 373 off_t Size; 374 time_t ModTime; 375 StringRef Filename; 376 bool Imported; 377 }; 378 379 using internal_key_ref = const internal_key_type &; 380 381 using data_type = HeaderFileInfo; 382 using hash_value_type = unsigned; 383 using offset_type = unsigned; 384 385 HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M) 386 : Reader(Reader), M(M) {} 387 388 static hash_value_type ComputeHash(internal_key_ref ikey); 389 internal_key_type GetInternalKey(external_key_type ekey); 390 bool EqualKey(internal_key_ref a, internal_key_ref b); 391 392 static std::pair<unsigned, unsigned> 393 ReadKeyDataLength(const unsigned char*& d); 394 395 static internal_key_type ReadKey(const unsigned char *d, unsigned); 396 397 data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen); 398 399 private: 400 OptionalFileEntryRef getFile(const internal_key_type &Key); 401 }; 402 403 /// The on-disk hash table used for known header files. 404 using HeaderFileInfoLookupTable = 405 llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>; 406 407 } // namespace reader 408 409 } // namespace serialization 410 411 } // namespace clang 412 413 #endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H 414