|  | //===- ASTReaderInternals.h - AST Reader Internals --------------*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //  This file provides internal definitions used in the AST reader. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H | 
|  | #define LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H | 
|  |  | 
|  | #include "MultiOnDiskHashTable.h" | 
|  | #include "clang/AST/DeclarationName.h" | 
|  | #include "clang/Basic/LLVM.h" | 
|  | #include "clang/Serialization/ASTBitCodes.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/Support/OnDiskHashTable.h" | 
|  | #include <ctime> | 
|  | #include <utility> | 
|  |  | 
|  | namespace clang { | 
|  |  | 
|  | class ASTReader; | 
|  | class FileEntry; | 
|  | struct HeaderFileInfo; | 
|  | class HeaderSearch; | 
|  | class ObjCMethodDecl; | 
|  | class Module; | 
|  |  | 
|  | namespace serialization { | 
|  |  | 
|  | class ModuleFile; | 
|  |  | 
|  | namespace reader { | 
|  |  | 
|  | class ASTDeclContextNameLookupTraitBase { | 
|  | protected: | 
|  | ASTReader &Reader; | 
|  | ModuleFile &F; | 
|  |  | 
|  | public: | 
|  | // Maximum number of lookup tables we allow before condensing the tables. | 
|  | static const int MaxTables = 4; | 
|  |  | 
|  | /// The lookup result is a list of global declaration IDs. | 
|  | using data_type = SmallVector<GlobalDeclID, 4>; | 
|  |  | 
|  | struct data_type_builder { | 
|  | data_type &Data; | 
|  | llvm::DenseSet<GlobalDeclID> Found; | 
|  |  | 
|  | data_type_builder(data_type &D) : Data(D) {} | 
|  |  | 
|  | void insert(GlobalDeclID ID) { | 
|  | // Just use a linear scan unless we have more than a few IDs. | 
|  | if (Found.empty() && !Data.empty()) { | 
|  | if (Data.size() <= 4) { | 
|  | for (auto I : Found) | 
|  | if (I == ID) | 
|  | return; | 
|  | Data.push_back(ID); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Switch to tracking found IDs in the set. | 
|  | Found.insert_range(Data); | 
|  | } | 
|  |  | 
|  | if (Found.insert(ID).second) | 
|  | Data.push_back(ID); | 
|  | } | 
|  | }; | 
|  | using hash_value_type = unsigned; | 
|  | using offset_type = unsigned; | 
|  | using file_type = ModuleFile *; | 
|  |  | 
|  | protected: | 
|  | explicit ASTDeclContextNameLookupTraitBase(ASTReader &Reader, ModuleFile &F) | 
|  | : Reader(Reader), F(F) {} | 
|  |  | 
|  | public: | 
|  | static std::pair<unsigned, unsigned> | 
|  | ReadKeyDataLength(const unsigned char *&d); | 
|  |  | 
|  | void ReadDataIntoImpl(const unsigned char *d, unsigned DataLen, | 
|  | data_type_builder &Val); | 
|  |  | 
|  | static void MergeDataInto(const data_type &From, data_type_builder &To) { | 
|  | To.Data.reserve(To.Data.size() + From.size()); | 
|  | for (GlobalDeclID ID : From) | 
|  | To.insert(ID); | 
|  | } | 
|  |  | 
|  | file_type ReadFileRef(const unsigned char *&d); | 
|  |  | 
|  | DeclarationNameKey ReadKeyBase(const unsigned char *&d); | 
|  | }; | 
|  |  | 
|  | /// Class that performs name lookup into a DeclContext stored | 
|  | /// in an AST file. | 
|  | class ASTDeclContextNameLookupTrait : public ASTDeclContextNameLookupTraitBase { | 
|  | public: | 
|  | explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F) | 
|  | : ASTDeclContextNameLookupTraitBase(Reader, F) {} | 
|  |  | 
|  | using external_key_type = DeclarationName; | 
|  | using internal_key_type = DeclarationNameKey; | 
|  |  | 
|  | static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { | 
|  | return a == b; | 
|  | } | 
|  |  | 
|  | static hash_value_type ComputeHash(const internal_key_type &Key) { | 
|  | return Key.getHash(); | 
|  | } | 
|  |  | 
|  | static internal_key_type GetInternalKey(const external_key_type &Name) { | 
|  | return Name; | 
|  | } | 
|  |  | 
|  | internal_key_type ReadKey(const unsigned char *d, unsigned); | 
|  |  | 
|  | void ReadDataInto(internal_key_type, const unsigned char *d, | 
|  | unsigned DataLen, data_type_builder &Val); | 
|  | }; | 
|  |  | 
|  | struct DeclContextLookupTable { | 
|  | MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table; | 
|  | }; | 
|  |  | 
|  | class ModuleLocalNameLookupTrait : public ASTDeclContextNameLookupTraitBase { | 
|  | public: | 
|  | explicit ModuleLocalNameLookupTrait(ASTReader &Reader, ModuleFile &F) | 
|  | : ASTDeclContextNameLookupTraitBase(Reader, F) {} | 
|  |  | 
|  | using external_key_type = std::pair<DeclarationName, const Module *>; | 
|  | using internal_key_type = std::pair<DeclarationNameKey, unsigned>; | 
|  |  | 
|  | static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { | 
|  | return a == b; | 
|  | } | 
|  |  | 
|  | static hash_value_type ComputeHash(const internal_key_type &Key); | 
|  | static internal_key_type GetInternalKey(const external_key_type &Key); | 
|  |  | 
|  | internal_key_type ReadKey(const unsigned char *d, unsigned); | 
|  |  | 
|  | void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, | 
|  | data_type_builder &Val); | 
|  | }; | 
|  |  | 
|  | struct ModuleLocalLookupTable { | 
|  | MultiOnDiskHashTable<ModuleLocalNameLookupTrait> Table; | 
|  | }; | 
|  |  | 
|  | using LazySpecializationInfo = GlobalDeclID; | 
|  |  | 
|  | /// Class that performs lookup to specialized decls. | 
|  | class LazySpecializationInfoLookupTrait { | 
|  | ASTReader &Reader; | 
|  | ModuleFile &F; | 
|  |  | 
|  | public: | 
|  | // Maximum number of lookup tables we allow before condensing the tables. | 
|  | static const int MaxTables = 4; | 
|  |  | 
|  | /// The lookup result is a list of global declaration IDs. | 
|  | using data_type = SmallVector<LazySpecializationInfo, 4>; | 
|  |  | 
|  | struct data_type_builder { | 
|  | data_type &Data; | 
|  | llvm::DenseSet<LazySpecializationInfo> Found; | 
|  |  | 
|  | data_type_builder(data_type &D) : Data(D) {} | 
|  |  | 
|  | void insert(LazySpecializationInfo Info) { | 
|  | // Just use a linear scan unless we have more than a few IDs. | 
|  | if (Found.empty() && !Data.empty()) { | 
|  | if (Data.size() <= 4) { | 
|  | for (auto I : Found) | 
|  | if (I == Info) | 
|  | return; | 
|  | Data.push_back(Info); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Switch to tracking found IDs in the set. | 
|  | Found.insert_range(Data); | 
|  | } | 
|  |  | 
|  | if (Found.insert(Info).second) | 
|  | Data.push_back(Info); | 
|  | } | 
|  | }; | 
|  | using hash_value_type = unsigned; | 
|  | using offset_type = unsigned; | 
|  | using file_type = ModuleFile *; | 
|  |  | 
|  | using external_key_type = unsigned; | 
|  | using internal_key_type = unsigned; | 
|  |  | 
|  | explicit LazySpecializationInfoLookupTrait(ASTReader &Reader, ModuleFile &F) | 
|  | : Reader(Reader), F(F) {} | 
|  |  | 
|  | static bool EqualKey(const internal_key_type &a, const internal_key_type &b) { | 
|  | return a == b; | 
|  | } | 
|  |  | 
|  | static hash_value_type ComputeHash(const internal_key_type &Key) { | 
|  | return Key; | 
|  | } | 
|  |  | 
|  | static internal_key_type GetInternalKey(const external_key_type &Name) { | 
|  | return Name; | 
|  | } | 
|  |  | 
|  | static std::pair<unsigned, unsigned> | 
|  | ReadKeyDataLength(const unsigned char *&d); | 
|  |  | 
|  | internal_key_type ReadKey(const unsigned char *d, unsigned); | 
|  |  | 
|  | void ReadDataInto(internal_key_type, const unsigned char *d, unsigned DataLen, | 
|  | data_type_builder &Val); | 
|  |  | 
|  | static void MergeDataInto(const data_type &From, data_type_builder &To) { | 
|  | To.Data.reserve(To.Data.size() + From.size()); | 
|  | for (LazySpecializationInfo Info : From) | 
|  | To.insert(Info); | 
|  | } | 
|  |  | 
|  | file_type ReadFileRef(const unsigned char *&d); | 
|  | }; | 
|  |  | 
|  | struct LazySpecializationInfoLookupTable { | 
|  | MultiOnDiskHashTable<LazySpecializationInfoLookupTrait> Table; | 
|  | }; | 
|  |  | 
|  | /// Base class for the trait describing the on-disk hash table for the | 
|  | /// identifiers in an AST file. | 
|  | /// | 
|  | /// This class is not useful by itself; rather, it provides common | 
|  | /// functionality for accessing the on-disk hash table of identifiers | 
|  | /// in an AST file. Different subclasses customize that functionality | 
|  | /// based on what information they are interested in. Those subclasses | 
|  | /// must provide the \c data_type type and the ReadData operation, only. | 
|  | class ASTIdentifierLookupTraitBase { | 
|  | public: | 
|  | using external_key_type = StringRef; | 
|  | using internal_key_type = StringRef; | 
|  | using hash_value_type = unsigned; | 
|  | using offset_type = unsigned; | 
|  |  | 
|  | static bool EqualKey(const internal_key_type& a, const internal_key_type& b) { | 
|  | return a == b; | 
|  | } | 
|  |  | 
|  | static hash_value_type ComputeHash(const internal_key_type& a); | 
|  |  | 
|  | static std::pair<unsigned, unsigned> | 
|  | ReadKeyDataLength(const unsigned char*& d); | 
|  |  | 
|  | // This hopefully will just get inlined and removed by the optimizer. | 
|  | static const internal_key_type& | 
|  | GetInternalKey(const external_key_type& x) { return x; } | 
|  |  | 
|  | // This hopefully will just get inlined and removed by the optimizer. | 
|  | static const external_key_type& | 
|  | GetExternalKey(const internal_key_type& x) { return x; } | 
|  |  | 
|  | static internal_key_type ReadKey(const unsigned char* d, unsigned n); | 
|  | }; | 
|  |  | 
|  | /// Class that performs lookup for an identifier stored in an AST file. | 
|  | class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { | 
|  | ASTReader &Reader; | 
|  | ModuleFile &F; | 
|  |  | 
|  | // If we know the IdentifierInfo in advance, it is here and we will | 
|  | // not build a new one. Used when deserializing information about an | 
|  | // identifier that was constructed before the AST file was read. | 
|  | IdentifierInfo *KnownII; | 
|  |  | 
|  | bool hasMacroDefinitionInDependencies = false; | 
|  |  | 
|  | public: | 
|  | using data_type = IdentifierInfo *; | 
|  |  | 
|  | ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F, | 
|  | IdentifierInfo *II = nullptr) | 
|  | : Reader(Reader), F(F), KnownII(II) {} | 
|  |  | 
|  | data_type ReadData(const internal_key_type& k, | 
|  | const unsigned char* d, | 
|  | unsigned DataLen); | 
|  |  | 
|  | IdentifierID ReadIdentifierID(const unsigned char *d); | 
|  |  | 
|  | ASTReader &getReader() const { return Reader; } | 
|  |  | 
|  | bool hasMoreInformationInDependencies() const { | 
|  | return hasMacroDefinitionInDependencies; | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// The on-disk hash table used to contain information about | 
|  | /// all of the identifiers in the program. | 
|  | using ASTIdentifierLookupTable = | 
|  | llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>; | 
|  |  | 
|  | /// Class that performs lookup for a selector's entries in the global | 
|  | /// method pool stored in an AST file. | 
|  | class ASTSelectorLookupTrait { | 
|  | ASTReader &Reader; | 
|  | ModuleFile &F; | 
|  |  | 
|  | public: | 
|  | struct data_type { | 
|  | SelectorID ID; | 
|  | unsigned InstanceBits; | 
|  | unsigned FactoryBits; | 
|  | bool InstanceHasMoreThanOneDecl; | 
|  | bool FactoryHasMoreThanOneDecl; | 
|  | SmallVector<ObjCMethodDecl *, 2> Instance; | 
|  | SmallVector<ObjCMethodDecl *, 2> Factory; | 
|  | }; | 
|  |  | 
|  | using external_key_type = Selector; | 
|  | using internal_key_type = external_key_type; | 
|  | using hash_value_type = unsigned; | 
|  | using offset_type = unsigned; | 
|  |  | 
|  | ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F) | 
|  | : Reader(Reader), F(F) {} | 
|  |  | 
|  | static bool EqualKey(const internal_key_type& a, | 
|  | const internal_key_type& b) { | 
|  | return a == b; | 
|  | } | 
|  |  | 
|  | static hash_value_type ComputeHash(Selector Sel); | 
|  |  | 
|  | static const internal_key_type& | 
|  | GetInternalKey(const external_key_type& x) { return x; } | 
|  |  | 
|  | static std::pair<unsigned, unsigned> | 
|  | ReadKeyDataLength(const unsigned char*& d); | 
|  |  | 
|  | internal_key_type ReadKey(const unsigned char* d, unsigned); | 
|  | data_type ReadData(Selector, const unsigned char* d, unsigned DataLen); | 
|  | }; | 
|  |  | 
|  | /// The on-disk hash table used for the global method pool. | 
|  | using ASTSelectorLookupTable = | 
|  | llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>; | 
|  |  | 
|  | /// Trait class used to search the on-disk hash table containing all of | 
|  | /// the header search information. | 
|  | /// | 
|  | /// The on-disk hash table contains a mapping from each header path to | 
|  | /// information about that header (how many times it has been included, its | 
|  | /// controlling macro, etc.). Note that we actually hash based on the size | 
|  | /// and mtime, and support "deep" comparisons of file names based on current | 
|  | /// inode numbers, so that the search can cope with non-normalized path names | 
|  | /// and symlinks. | 
|  | class HeaderFileInfoTrait { | 
|  | ASTReader &Reader; | 
|  | ModuleFile &M; | 
|  |  | 
|  | public: | 
|  | using external_key_type = FileEntryRef; | 
|  |  | 
|  | struct internal_key_type { | 
|  | off_t Size; | 
|  | time_t ModTime; | 
|  | StringRef Filename; | 
|  | bool Imported; | 
|  | }; | 
|  |  | 
|  | using internal_key_ref = const internal_key_type &; | 
|  |  | 
|  | using data_type = HeaderFileInfo; | 
|  | using hash_value_type = unsigned; | 
|  | using offset_type = unsigned; | 
|  |  | 
|  | HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M) | 
|  | : Reader(Reader), M(M) {} | 
|  |  | 
|  | static hash_value_type ComputeHash(internal_key_ref ikey); | 
|  | internal_key_type GetInternalKey(external_key_type ekey); | 
|  | bool EqualKey(internal_key_ref a, internal_key_ref b); | 
|  |  | 
|  | static std::pair<unsigned, unsigned> | 
|  | ReadKeyDataLength(const unsigned char*& d); | 
|  |  | 
|  | static internal_key_type ReadKey(const unsigned char *d, unsigned); | 
|  |  | 
|  | data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen); | 
|  |  | 
|  | private: | 
|  | OptionalFileEntryRef getFile(const internal_key_type &Key); | 
|  | }; | 
|  |  | 
|  | /// The on-disk hash table used for known header files. | 
|  | using HeaderFileInfoLookupTable = | 
|  | llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>; | 
|  |  | 
|  | } // namespace reader | 
|  |  | 
|  | } // namespace serialization | 
|  |  | 
|  | } // namespace clang | 
|  |  | 
|  | #endif // LLVM_CLANG_LIB_SERIALIZATION_ASTREADERINTERNALS_H |