From: Douglas Gregor Date: Thu, 25 Aug 2011 20:47:51 +0000 (+0000) Subject: Factor the Module and ModuleManager classes out into separate headers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=98339b96a8089a6da715487e432c5abfca0ca0df;p=clang Factor the Module and ModuleManager classes out into separate headers and .cpp files, since ASTReader.cpp was getting way too large. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138582 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 9eb4320d55..c8a72551be 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -16,6 +16,8 @@ #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleManager.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DeclObjC.h" @@ -32,7 +34,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Bitcode/BitstreamReader.h" @@ -73,7 +74,6 @@ class ASTWriter; class ASTReader; class ASTDeclReader; class ASTStmtReader; -class ASTIdentifierLookupTrait; class TypeLocReader; struct HeaderFileInfo; class VersionTuple; @@ -161,421 +161,14 @@ private: void Error(const char *Msg); }; -namespace serialization { - -/// \brief Specifies the kind of module that has been loaded. -enum ModuleKind { - MK_Module, ///< File is a module proper. - MK_PCH, ///< File is a PCH file treated as such. - MK_Preamble, ///< File is a PCH file treated as the preamble. - MK_MainFile ///< File is a PCH file treated as the actual main file. -}; - -/// \brief Information about the contents of a DeclContext. -struct DeclContextInfo { - DeclContextInfo() - : NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {} - - void *NameLookupTableData; // an ASTDeclContextNameLookupTable. - const KindDeclIDPair *LexicalDecls; - unsigned NumLexicalDecls; -}; - -/// \brief Information about a module that has been loaded by the ASTReader. -/// -/// Each instance of the Module class corresponds to a single AST file, which -/// may be a precompiled header, precompiled preamble, or an AST file of some -/// sort loaded as the main file, all of which are specific formulations of -/// the general notion of a "module". A module may depend on another module. -class Module { -public: - Module(ModuleKind Kind); - ~Module(); - - // === General information === - - /// \brief The type of this module. - ModuleKind Kind; - - /// \brief The file name of the module file. - std::string FileName; - - /// \brief Whether this module has been directly imported by the - /// user. - bool DirectlyImported; - - /// \brief The memory buffer that stores the data associated with - /// this AST file. - llvm::OwningPtr Buffer; - - /// \brief The size of this file, in bits. - uint64_t SizeInBits; - - /// \brief The global bit offset (or base) of this module - uint64_t GlobalBitOffset; - - /// \brief The bitstream reader from which we'll read the AST file. - llvm::BitstreamReader StreamFile; - - /// \brief The main bitstream cursor for the main block. - llvm::BitstreamCursor Stream; - - /// \brief The source location where this module was first imported. - SourceLocation ImportLoc; - - /// \brief The first source location in this module. - SourceLocation FirstLoc; - - // === Source Locations === - - /// \brief Cursor used to read source location entries. - llvm::BitstreamCursor SLocEntryCursor; - - /// \brief The number of source location entries in this AST file. - unsigned LocalNumSLocEntries; - - /// \brief The base ID in the source manager's view of this module. - int SLocEntryBaseID; - - /// \brief The base offset in the source manager's view of this module. - unsigned SLocEntryBaseOffset; - - /// \brief Offsets for all of the source location entries in the - /// AST file. - const uint32_t *SLocEntryOffsets; - - /// \brief The number of source location file entries in this AST file. - unsigned LocalNumSLocFileEntries; - - /// \brief Offsets for all of the source location file entries in the - /// AST file. - const uint32_t *SLocFileOffsets; - - /// \brief Remapping table for source locations in this module. - ContinuousRangeMap SLocRemap; - - // === Identifiers === - - /// \brief The number of identifiers in this AST file. - unsigned LocalNumIdentifiers; - - /// \brief Offsets into the identifier table data. - /// - /// This array is indexed by the identifier ID (-1), and provides - /// the offset into IdentifierTableData where the string data is - /// stored. - const uint32_t *IdentifierOffsets; - - /// \brief Base identifier ID for identifiers local to this module. - serialization::IdentID BaseIdentifierID; - - /// \brief Remapping table for identifier IDs in this module. - ContinuousRangeMap IdentifierRemap; - - /// \brief Actual data for the on-disk hash table of identifiers. - /// - /// This pointer points into a memory buffer, where the on-disk hash - /// table for identifiers actually lives. - const char *IdentifierTableData; - - /// \brief A pointer to an on-disk hash table of opaque type - /// IdentifierHashTable. - void *IdentifierLookupTable; - - // === Macros === - - /// \brief The cursor to the start of the preprocessor block, which stores - /// all of the macro definitions. - llvm::BitstreamCursor MacroCursor; - - /// \brief The offset of the start of the set of defined macros. - uint64_t MacroStartOffset; - - // === Detailed PreprocessingRecord === - - /// \brief The cursor to the start of the (optional) detailed preprocessing - /// record block. - llvm::BitstreamCursor PreprocessorDetailCursor; - - /// \brief The offset of the start of the preprocessor detail cursor. - uint64_t PreprocessorDetailStartOffset; - - /// \brief Base preprocessed entity ID for preprocessed entities local to - /// this module. - serialization::PreprocessedEntityID BasePreprocessedEntityID; - - /// \brief Remapping table for preprocessed entity IDs in this module. - ContinuousRangeMap PreprocessedEntityRemap; - - /// \brief The number of macro definitions in this file. - unsigned LocalNumMacroDefinitions; - - /// \brief Offsets of all of the macro definitions in the preprocessing - /// record in the AST file. - const uint32_t *MacroDefinitionOffsets; - - /// \brief Base macro definition ID for macro definitions local to this - /// module. - serialization::MacroID BaseMacroDefinitionID; - - /// \brief Remapping table for macro definition IDs in this module. - ContinuousRangeMap MacroDefinitionRemap; - - // === Header search information === - - /// \brief The number of local HeaderFileInfo structures. - unsigned LocalNumHeaderFileInfos; - - /// \brief Actual data for the on-disk hash table of header file - /// information. - /// - /// This pointer points into a memory buffer, where the on-disk hash - /// table for header file information actually lives. - const char *HeaderFileInfoTableData; - - /// \brief The on-disk hash table that contains information about each of - /// the header files. - void *HeaderFileInfoTable; - - /// \brief Actual data for the list of framework names used in the header - /// search information. - const char *HeaderFileFrameworkStrings; - - // === Selectors === - - /// \brief The number of selectors new to this file. - /// - /// This is the number of entries in SelectorOffsets. - unsigned LocalNumSelectors; - - /// \brief Offsets into the selector lookup table's data array - /// where each selector resides. - const uint32_t *SelectorOffsets; - - /// \brief Base selector ID for selectors local to this module. - serialization::SelectorID BaseSelectorID; - - /// \brief Remapping table for selector IDs in this module. - ContinuousRangeMap SelectorRemap; - - /// \brief A pointer to the character data that comprises the selector table - /// - /// The SelectorOffsets table refers into this memory. - const unsigned char *SelectorLookupTableData; - - /// \brief A pointer to an on-disk hash table of opaque type - /// ASTSelectorLookupTable. - /// - /// This hash table provides the IDs of all selectors, and the associated - /// instance and factory methods. - void *SelectorLookupTable; - - // === Declarations === - - /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It - /// has read all the abbreviations at the start of the block and is ready to - /// jump around with these in context. - llvm::BitstreamCursor DeclsCursor; - - /// \brief The number of declarations in this AST file. - unsigned LocalNumDecls; - - /// \brief Offset of each declaration within the bitstream, indexed - /// by the declaration ID (-1). - const uint32_t *DeclOffsets; - - /// \brief Base declaration ID for declarations local to this module. - serialization::DeclID BaseDeclID; - - /// \brief Remapping table for declaration IDs in this module. - ContinuousRangeMap DeclRemap; - - /// \brief The number of C++ base specifier sets in this AST file. - unsigned LocalNumCXXBaseSpecifiers; - - /// \brief Offset of each C++ base specifier set within the bitstream, - /// indexed by the C++ base specifier set ID (-1). - const uint32_t *CXXBaseSpecifiersOffsets; - - typedef llvm::DenseMap - DeclContextInfosMap; - - /// \brief Information about the lexical and visible declarations - /// for each DeclContext. - DeclContextInfosMap DeclContextInfos; - - // === Types === - - /// \brief The number of types in this AST file. - unsigned LocalNumTypes; - - /// \brief Offset of each type within the bitstream, indexed by the - /// type ID, or the representation of a Type*. - const uint32_t *TypeOffsets; - - /// \brief Base type ID for types local to this module as represented in - /// the global type ID space. - serialization::TypeID BaseTypeIndex; - - /// \brief Remapping table for type IDs in this module. - ContinuousRangeMap TypeRemap; - - // === Miscellaneous === - - /// \brief Diagnostic IDs and their mappings that the user changed. - SmallVector PragmaDiagMappings; - - /// \brief The AST stat cache installed for this file, if any. - /// - /// The dynamic type of this stat cache is always ASTStatCache - void *StatCache; - - /// \brief The number of preallocated preprocessing entities in the - /// preprocessing record. - unsigned NumPreallocatedPreprocessingEntities; - - /// \brief List of modules which depend on this module - llvm::SetVector ImportedBy; - - /// \brief List of modules which this module depends on - llvm::SetVector Imports; - - /// \brief Determine whether this module was directly imported at - /// any point during translation. - bool isDirectlyImported() const { return DirectlyImported; } - - /// \brief Dump debugging output for this module. - void dump(); -}; - -/// \brief The manager for modules loaded by the ASTReader. -class ModuleManager { - /// \brief The chain of AST files. The first entry is the one named by the - /// user, the last one is the one that doesn't depend on anything further. - SmallVector Chain; - - /// \brief All loaded modules, indexed by name. - llvm::DenseMap Modules; - - /// \brief FileManager that handles translating between filenames and - /// FileEntry *. - FileManager FileMgr; - - /// \brief A lookup of in-memory (virtual file) buffers - llvm::DenseMap InMemoryBuffers; - -public: - typedef SmallVector::iterator ModuleIterator; - typedef SmallVector::const_iterator ModuleConstIterator; - typedef SmallVector::reverse_iterator ModuleReverseIterator; - typedef std::pair ModuleOffset; - - ModuleManager(const FileSystemOptions &FSO); - ~ModuleManager(); - - /// \brief Forward iterator to traverse all loaded modules. This is reverse - /// source-order. - ModuleIterator begin() { return Chain.begin(); } - /// \brief Forward iterator end-point to traverse all loaded modules - ModuleIterator end() { return Chain.end(); } - - /// \brief Const forward iterator to traverse all loaded modules. This is - /// in reverse source-order. - ModuleConstIterator begin() const { return Chain.begin(); } - /// \brief Const forward iterator end-point to traverse all loaded modules - ModuleConstIterator end() const { return Chain.end(); } - - /// \brief Reverse iterator to traverse all loaded modules. This is in - /// source order. - ModuleReverseIterator rbegin() { return Chain.rbegin(); } - /// \brief Reverse iterator end-point to traverse all loaded modules. - ModuleReverseIterator rend() { return Chain.rend(); } - - /// \brief Returns the primary module associated with the manager, that is, - /// the first module loaded - Module &getPrimaryModule() { return *Chain[0]; } - - /// \brief Returns the primary module associated with the manager, that is, - /// the first module loaded. - Module &getPrimaryModule() const { return *Chain[0]; } - - /// \brief Returns the module associated with the given index - Module &operator[](unsigned Index) const { return *Chain[Index]; } - - /// \brief Returns the module associated with the given name - Module *lookup(StringRef Name); - - /// \brief Returns the in-memory (virtual file) buffer with the given name - llvm::MemoryBuffer *lookupBuffer(StringRef Name); - - /// \brief Number of modules loaded - unsigned size() const { return Chain.size(); } - - /// \brief Attempts to create a new module and add it to the list of known - /// modules. - /// - /// \param FileName The file name of the module to be loaded. - /// - /// \param Type The kind of module being loaded. - /// - /// \param ImportedBy The module that is importing this module, or NULL if - /// this module is imported directly by the user. - /// - /// \param ErrorStr Will be set to a non-empty string if any errors occurred - /// while trying to load the module. - /// - /// \return A pointer to the module that corresponds to this file name, - /// and a boolean indicating whether the module was newly added. - std::pair - addModule(StringRef FileName, ModuleKind Type, Module *ImportedBy, - std::string &ErrorStr); - - /// \brief Add an in-memory buffer the list of known buffers - void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer); - - /// \brief Visit each of the modules. - /// - /// This routine visits each of the modules, starting with the - /// "root" modules that no other loaded modules depend on, and - /// proceeding to the leaf modules, visiting each module only once - /// during the traversal. - /// - /// This traversal is intended to support various "lookup" - /// operations that can find data in any of the loaded modules. - /// - /// \param Visitor A visitor function that will be invoked with each - /// module and the given user data pointer. The return value must be - /// convertible to bool; when false, the visitation continues to - /// modules that the current module depends on. When true, the - /// visitation skips any modules that the current module depends on. - /// - /// \param UserData User data associated with the visitor object, which - /// will be passed along to the visitor. - void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData); - - /// \brief Visit each of the modules with a depth-first traversal. - /// - /// This routine visits each of the modules known to the module - /// manager using a depth-first search, starting with the first - /// loaded module. The traversal invokes the callback both before - /// traversing the children (preorder traversal) and after - /// traversing the children (postorder traversal). - /// - /// \param Visitor A visitor function that will be invoked with each - /// module and given a \c Preorder flag that indicates whether we're - /// visiting the module before or after visiting its children. The - /// visitor may return true at any time to abort the depth-first - /// visitation. - /// - /// \param UserData User data ssociated with the visitor object, - /// which will be passed along to the user. - void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, - void *UserData), - void *UserData); -}; +namespace serialization { class ReadMethodPoolVisitor; +namespace reader { + class ASTIdentifierLookupTrait; +} + } // end namespace serialization /// \brief Reads an AST files chain containing the contents of a translation @@ -606,7 +199,7 @@ public: friend class ASTDeclReader; friend class ASTStmtReader; friend class ASTIdentifierIterator; - friend class ASTIdentifierLookupTrait; + friend class serialization::reader::ASTIdentifierLookupTrait; friend class TypeLocReader; friend class ASTWriter; friend class ASTUnit; // ASTUnit needs to remap source locations. diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h new file mode 100644 index 0000000000..a6a7da4fbd --- /dev/null +++ b/include/clang/Serialization/Module.h @@ -0,0 +1,322 @@ +//===--- Module.h - Module description --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module that has +// been loaded from an AST file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H +#define LLVM_CLANG_SERIALIZATION_MODULE_H + +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include + +namespace clang { + +class DeclContext; + +namespace serialization { + +/// \brief Specifies the kind of module that has been loaded. +enum ModuleKind { + MK_Module, ///< File is a module proper. + MK_PCH, ///< File is a PCH file treated as such. + MK_Preamble, ///< File is a PCH file treated as the preamble. + MK_MainFile ///< File is a PCH file treated as the actual main file. +}; + +/// \brief Information about the contents of a DeclContext. +struct DeclContextInfo { + DeclContextInfo() + : NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {} + + void *NameLookupTableData; // an ASTDeclContextNameLookupTable. + const KindDeclIDPair *LexicalDecls; + unsigned NumLexicalDecls; +}; + +/// \brief Information about a module that has been loaded by the ASTReader. +/// +/// Each instance of the Module class corresponds to a single AST file, which +/// may be a precompiled header, precompiled preamble, a module, or an AST file +/// of some sort loaded as the main file, all of which are specific formulations of +/// the general notion of a "module". A module may depend on any number of +/// other modules. +class Module { +public: + Module(ModuleKind Kind); + ~Module(); + + // === General information === + + /// \brief The type of this module. + ModuleKind Kind; + + /// \brief The file name of the module file. + std::string FileName; + + /// \brief Whether this module has been directly imported by the + /// user. + bool DirectlyImported; + + /// \brief The memory buffer that stores the data associated with + /// this AST file. + llvm::OwningPtr Buffer; + + /// \brief The size of this file, in bits. + uint64_t SizeInBits; + + /// \brief The global bit offset (or base) of this module + uint64_t GlobalBitOffset; + + /// \brief The bitstream reader from which we'll read the AST file. + llvm::BitstreamReader StreamFile; + + /// \brief The main bitstream cursor for the main block. + llvm::BitstreamCursor Stream; + + /// \brief The source location where this module was first imported. + SourceLocation ImportLoc; + + /// \brief The first source location in this module. + SourceLocation FirstLoc; + + // === Source Locations === + + /// \brief Cursor used to read source location entries. + llvm::BitstreamCursor SLocEntryCursor; + + /// \brief The number of source location entries in this AST file. + unsigned LocalNumSLocEntries; + + /// \brief The base ID in the source manager's view of this module. + int SLocEntryBaseID; + + /// \brief The base offset in the source manager's view of this module. + unsigned SLocEntryBaseOffset; + + /// \brief Offsets for all of the source location entries in the + /// AST file. + const uint32_t *SLocEntryOffsets; + + /// \brief The number of source location file entries in this AST file. + unsigned LocalNumSLocFileEntries; + + /// \brief Offsets for all of the source location file entries in the + /// AST file. + const uint32_t *SLocFileOffsets; + + /// \brief Remapping table for source locations in this module. + ContinuousRangeMap SLocRemap; + + // === Identifiers === + + /// \brief The number of identifiers in this AST file. + unsigned LocalNumIdentifiers; + + /// \brief Offsets into the identifier table data. + /// + /// This array is indexed by the identifier ID (-1), and provides + /// the offset into IdentifierTableData where the string data is + /// stored. + const uint32_t *IdentifierOffsets; + + /// \brief Base identifier ID for identifiers local to this module. + serialization::IdentID BaseIdentifierID; + + /// \brief Remapping table for identifier IDs in this module. + ContinuousRangeMap IdentifierRemap; + + /// \brief Actual data for the on-disk hash table of identifiers. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for identifiers actually lives. + const char *IdentifierTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// IdentifierHashTable. + void *IdentifierLookupTable; + + // === Macros === + + /// \brief The cursor to the start of the preprocessor block, which stores + /// all of the macro definitions. + llvm::BitstreamCursor MacroCursor; + + /// \brief The offset of the start of the set of defined macros. + uint64_t MacroStartOffset; + + // === Detailed PreprocessingRecord === + + /// \brief The cursor to the start of the (optional) detailed preprocessing + /// record block. + llvm::BitstreamCursor PreprocessorDetailCursor; + + /// \brief The offset of the start of the preprocessor detail cursor. + uint64_t PreprocessorDetailStartOffset; + + /// \brief Base preprocessed entity ID for preprocessed entities local to + /// this module. + serialization::PreprocessedEntityID BasePreprocessedEntityID; + + /// \brief Remapping table for preprocessed entity IDs in this module. + ContinuousRangeMap PreprocessedEntityRemap; + + /// \brief The number of macro definitions in this file. + unsigned LocalNumMacroDefinitions; + + /// \brief Offsets of all of the macro definitions in the preprocessing + /// record in the AST file. + const uint32_t *MacroDefinitionOffsets; + + /// \brief Base macro definition ID for macro definitions local to this + /// module. + serialization::MacroID BaseMacroDefinitionID; + + /// \brief Remapping table for macro definition IDs in this module. + ContinuousRangeMap MacroDefinitionRemap; + + // === Header search information === + + /// \brief The number of local HeaderFileInfo structures. + unsigned LocalNumHeaderFileInfos; + + /// \brief Actual data for the on-disk hash table of header file + /// information. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for header file information actually lives. + const char *HeaderFileInfoTableData; + + /// \brief The on-disk hash table that contains information about each of + /// the header files. + void *HeaderFileInfoTable; + + /// \brief Actual data for the list of framework names used in the header + /// search information. + const char *HeaderFileFrameworkStrings; + + // === Selectors === + + /// \brief The number of selectors new to this file. + /// + /// This is the number of entries in SelectorOffsets. + unsigned LocalNumSelectors; + + /// \brief Offsets into the selector lookup table's data array + /// where each selector resides. + const uint32_t *SelectorOffsets; + + /// \brief Base selector ID for selectors local to this module. + serialization::SelectorID BaseSelectorID; + + /// \brief Remapping table for selector IDs in this module. + ContinuousRangeMap SelectorRemap; + + /// \brief A pointer to the character data that comprises the selector table + /// + /// The SelectorOffsets table refers into this memory. + const unsigned char *SelectorLookupTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// ASTSelectorLookupTable. + /// + /// This hash table provides the IDs of all selectors, and the associated + /// instance and factory methods. + void *SelectorLookupTable; + + // === Declarations === + + /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It + /// has read all the abbreviations at the start of the block and is ready to + /// jump around with these in context. + llvm::BitstreamCursor DeclsCursor; + + /// \brief The number of declarations in this AST file. + unsigned LocalNumDecls; + + /// \brief Offset of each declaration within the bitstream, indexed + /// by the declaration ID (-1). + const uint32_t *DeclOffsets; + + /// \brief Base declaration ID for declarations local to this module. + serialization::DeclID BaseDeclID; + + /// \brief Remapping table for declaration IDs in this module. + ContinuousRangeMap DeclRemap; + + /// \brief The number of C++ base specifier sets in this AST file. + unsigned LocalNumCXXBaseSpecifiers; + + /// \brief Offset of each C++ base specifier set within the bitstream, + /// indexed by the C++ base specifier set ID (-1). + const uint32_t *CXXBaseSpecifiersOffsets; + + typedef llvm::DenseMap + DeclContextInfosMap; + + /// \brief Information about the lexical and visible declarations + /// for each DeclContext. + DeclContextInfosMap DeclContextInfos; + + // === Types === + + /// \brief The number of types in this AST file. + unsigned LocalNumTypes; + + /// \brief Offset of each type within the bitstream, indexed by the + /// type ID, or the representation of a Type*. + const uint32_t *TypeOffsets; + + /// \brief Base type ID for types local to this module as represented in + /// the global type ID space. + serialization::TypeID BaseTypeIndex; + + /// \brief Remapping table for type IDs in this module. + ContinuousRangeMap TypeRemap; + + // === Miscellaneous === + + /// \brief Diagnostic IDs and their mappings that the user changed. + SmallVector PragmaDiagMappings; + + /// \brief The AST stat cache installed for this file, if any. + /// + /// The dynamic type of this stat cache is always ASTStatCache + void *StatCache; + + /// \brief The number of preallocated preprocessing entities in the + /// preprocessing record. + unsigned NumPreallocatedPreprocessingEntities; + + /// \brief List of modules which depend on this module + llvm::SetVector ImportedBy; + + /// \brief List of modules which this module depends on + llvm::SetVector Imports; + + /// \brief Determine whether this module was directly imported at + /// any point during translation. + bool isDirectlyImported() const { return DirectlyImported; } + + /// \brief Dump debugging output for this module. + void dump(); +}; + +} // end namespace serialization + +} // end namespace clang + +#endif diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h new file mode 100644 index 0000000000..65a5d5e2ec --- /dev/null +++ b/include/clang/Serialization/ModuleManager.h @@ -0,0 +1,153 @@ +//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleManager class, which manages a set of loaded +// modules for the ASTReader. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H +#define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H + +#include "clang/Serialization/Module.h" +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +namespace serialization { + +/// \brief Manages the set of modules loaded by an AST reader. +class ModuleManager { + /// \brief The chain of AST files. The first entry is the one named by the + /// user, the last one is the one that doesn't depend on anything further. + llvm::SmallVector Chain; + + /// \brief All loaded modules, indexed by name. + llvm::DenseMap Modules; + + /// \brief FileManager that handles translating between filenames and + /// FileEntry *. + FileManager FileMgr; + + /// \brief A lookup of in-memory (virtual file) buffers + llvm::DenseMap InMemoryBuffers; + +public: + typedef SmallVector::iterator ModuleIterator; + typedef SmallVector::const_iterator ModuleConstIterator; + typedef SmallVector::reverse_iterator ModuleReverseIterator; + typedef std::pair ModuleOffset; + + ModuleManager(const FileSystemOptions &FSO); + ~ModuleManager(); + + /// \brief Forward iterator to traverse all loaded modules. This is reverse + /// source-order. + ModuleIterator begin() { return Chain.begin(); } + /// \brief Forward iterator end-point to traverse all loaded modules + ModuleIterator end() { return Chain.end(); } + + /// \brief Const forward iterator to traverse all loaded modules. This is + /// in reverse source-order. + ModuleConstIterator begin() const { return Chain.begin(); } + /// \brief Const forward iterator end-point to traverse all loaded modules + ModuleConstIterator end() const { return Chain.end(); } + + /// \brief Reverse iterator to traverse all loaded modules. This is in + /// source order. + ModuleReverseIterator rbegin() { return Chain.rbegin(); } + /// \brief Reverse iterator end-point to traverse all loaded modules. + ModuleReverseIterator rend() { return Chain.rend(); } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded + Module &getPrimaryModule() { return *Chain[0]; } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded. + Module &getPrimaryModule() const { return *Chain[0]; } + + /// \brief Returns the module associated with the given index + Module &operator[](unsigned Index) const { return *Chain[Index]; } + + /// \brief Returns the module associated with the given name + Module *lookup(StringRef Name); + + /// \brief Returns the in-memory (virtual file) buffer with the given name + llvm::MemoryBuffer *lookupBuffer(StringRef Name); + + /// \brief Number of modules loaded + unsigned size() const { return Chain.size(); } + /// \brief Attempts to create a new module and add it to the list of known + /// modules. + /// + /// \param FileName The file name of the module to be loaded. + /// + /// \param Type The kind of module being loaded. + /// + /// \param ImportedBy The module that is importing this module, or NULL if + /// this module is imported directly by the user. + /// + /// \param ErrorStr Will be set to a non-empty string if any errors occurred + /// while trying to load the module. + /// + /// \return A pointer to the module that corresponds to this file name, + /// and a boolean indicating whether the module was newly added. + std::pair + addModule(StringRef FileName, ModuleKind Type, Module *ImportedBy, + std::string &ErrorStr); + + /// \brief Add an in-memory buffer the list of known buffers + void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer); + + /// \brief Visit each of the modules. + /// + /// This routine visits each of the modules, starting with the + /// "root" modules that no other loaded modules depend on, and + /// proceeding to the leaf modules, visiting each module only once + /// during the traversal. + /// + /// This traversal is intended to support various "lookup" + /// operations that can find data in any of the loaded modules. + /// + /// \param Visitor A visitor function that will be invoked with each + /// module and the given user data pointer. The return value must be + /// convertible to bool; when false, the visitation continues to + /// modules that the current module depends on. When true, the + /// visitation skips any modules that the current module depends on. + /// + /// \param UserData User data associated with the visitor object, which + /// will be passed along to the visitor. + void visit(bool (*Visitor)(Module &M, void *UserData), void *UserData); + + /// \brief Visit each of the modules with a depth-first traversal. + /// + /// This routine visits each of the modules known to the module + /// manager using a depth-first search, starting with the first + /// loaded module. The traversal invokes the callback both before + /// traversing the children (preorder traversal) and after + /// traversing the children (postorder traversal). + /// + /// \param Visitor A visitor function that will be invoked with each + /// module and given a \c Preorder flag that indicates whether we're + /// visiting the module before or after visiting its children. The + /// visitor may return true at any time to abort the depth-first + /// visitation. + /// + /// \param UserData User data ssociated with the visitor object, + /// which will be passed along to the user. + void visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData); +}; + +} } // end namespace clang::serialization + +#endif diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 31b96ea7d6..3f4b9cf5fb 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -13,7 +13,9 @@ #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ModuleManager.h" #include "ASTCommon.h" +#include "ASTReaderInternals.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Sema/Sema.h" @@ -52,6 +54,7 @@ using namespace clang; using namespace clang::serialization; +using namespace clang::serialization::reader; //===----------------------------------------------------------------------===// // PCH validator implementation @@ -479,425 +482,321 @@ ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { } -namespace { -class ASTSelectorLookupTrait { - ASTReader &Reader; - Module &F; - -public: - struct data_type { - SelectorID ID; - llvm::SmallVector Instance; - llvm::SmallVector Factory; - }; - - typedef Selector external_key_type; - typedef external_key_type internal_key_type; - - ASTSelectorLookupTrait(ASTReader &Reader, Module &F) - : Reader(Reader), F(F) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a == b; - } - - static unsigned ComputeHash(Selector Sel) { - return serialization::ComputeHash(Sel); - } - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } - - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } +unsigned ASTSelectorLookupTrait::ComputeHash(Selector Sel) { + return serialization::ComputeHash(Sel); +} - internal_key_type ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; - SelectorTable &SelTable = Reader.getContext()->Selectors; - unsigned N = ReadUnalignedLE16(d); - IdentifierInfo *FirstII - = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - if (N == 0) - return SelTable.getNullarySelector(FirstII); - else if (N == 1) - return SelTable.getUnarySelector(FirstII); - SmallVector Args; - Args.push_back(FirstII); - for (unsigned I = 1; I != N; ++I) - Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d))); +std::pair +ASTSelectorLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - return SelTable.getSelector(N, Args.data()); - } +ASTSelectorLookupTrait::internal_key_type +ASTSelectorLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext()->Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + if (N == 0) + return SelTable.getNullarySelector(FirstII); + else if (N == 1) + return SelTable.getUnarySelector(FirstII); - data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { - using namespace clang::io; + SmallVector Args; + Args.push_back(FirstII); + for (unsigned I = 1; I != N; ++I) + Args.push_back(Reader.getLocalIdentifier(F, ReadUnalignedLE32(d))); - data_type Result; + return SelTable.getSelector(N, Args.data()); +} - Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); +ASTSelectorLookupTrait::data_type +ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; - // Load instance methods - ObjCMethodList *Prev = 0; - for (unsigned I = 0; I != NumInstanceMethods; ++I) { - if (ObjCMethodDecl *Method - = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) - Result.Instance.push_back(Method); - } + data_type Result; - // Load factory methods - Prev = 0; - for (unsigned I = 0; I != NumFactoryMethods; ++I) { - if (ObjCMethodDecl *Method - = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) - Result.Factory.push_back(Method); - } + Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); - return Result; + // Load instance methods + ObjCMethodList *Prev = 0; + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) + Result.Instance.push_back(Method); } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used for the global method pool. -typedef OnDiskChainedHashTable - ASTSelectorLookupTable; - -namespace clang { -class ASTIdentifierLookupTrait { - ASTReader &Reader; - Module &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; - -public: - typedef IdentifierInfo * data_type; - typedef const std::pair external_key_type; - - typedef external_key_type internal_key_type; - - ASTIdentifierLookupTrait(ASTReader &Reader, Module &F, - IdentifierInfo *II = 0) - : Reader(Reader), F(F), KnownII(II) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 - : false; + // Load factory methods + Prev = 0; + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + if (ObjCMethodDecl *Method + = Reader.GetLocalDeclAs(F, ReadUnalignedLE32(d))) + Result.Factory.push_back(Method); } - static unsigned ComputeHash(const internal_key_type& a) { - return llvm::HashString(StringRef(a.first, a.second)); - } + return Result; +} - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } +unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) { + return llvm::HashString(StringRef(a.first, a.second)); +} - // This hopefully will just get inlined and removed by the optimizer. - static const external_key_type& - GetExternalKey(const internal_key_type& x) { return x; } +std::pair +ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned DataLen = ReadUnalignedLE16(d); + unsigned KeyLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned DataLen = ReadUnalignedLE16(d); - unsigned KeyLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } +std::pair +ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) { + assert(n >= 2 && d[n-1] == '\0'); + return std::make_pair((const char*) d, n-1); +} - static std::pair - ReadKey(const unsigned char* d, unsigned n) { - assert(n >= 2 && d[n-1] == '\0'); - return std::make_pair((const char*) d, n-1); - } +IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned RawID = ReadUnalignedLE32(d); + bool IsInteresting = RawID & 0x01; - IdentifierInfo *ReadData(const internal_key_type& k, - const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - unsigned RawID = ReadUnalignedLE32(d); - bool IsInteresting = RawID & 0x01; - - // Wipe out the "is interesting" bit. - RawID = RawID >> 1; - - IdentID ID = Reader.getGlobalIdentifierID(F, RawID); - if (!IsInteresting) { - // For uninteresting identifiers, just build the IdentifierInfo - // and associate it with the persistent ID. - IdentifierInfo *II = KnownII; - if (!II) - II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); - Reader.SetIdentifierInfo(ID, II); - II->setIsFromAST(); - return II; - } + // Wipe out the "is interesting" bit. + RawID = RawID >> 1; - unsigned Bits = ReadUnalignedLE16(d); - bool CPlusPlusOperatorKeyword = Bits & 0x01; - Bits >>= 1; - bool HasRevertedTokenIDToIdentifier = Bits & 0x01; - Bits >>= 1; - bool Poisoned = Bits & 0x01; - Bits >>= 1; - bool ExtensionToken = Bits & 0x01; - Bits >>= 1; - bool hasMacroDefinition = Bits & 0x01; - Bits >>= 1; - unsigned ObjCOrBuiltinID = Bits & 0x3FF; - Bits >>= 10; - - assert(Bits == 0 && "Extra bits in the identifier?"); - DataLen -= 6; - - // Build the IdentifierInfo itself and link the identifier ID with - // the new IdentifierInfo. + IdentID ID = Reader.getGlobalIdentifierID(F, RawID); + if (!IsInteresting) { + // For uninteresting identifiers, just build the IdentifierInfo + // and associate it with the persistent ID. IdentifierInfo *II = KnownII; if (!II) II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); Reader.SetIdentifierInfo(ID, II); - - // Set or check the various bits in the IdentifierInfo structure. - // Token IDs are read-only. - if (HasRevertedTokenIDToIdentifier) - II->RevertTokenIDToIdentifier(); - II->setObjCOrBuiltinID(ObjCOrBuiltinID); - assert(II->isExtensionToken() == ExtensionToken && - "Incorrect extension token flag"); - (void)ExtensionToken; - if (Poisoned) - II->setIsPoisoned(true); - assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && - "Incorrect C++ operator keyword flag"); - (void)CPlusPlusOperatorKeyword; - - // If this identifier is a macro, deserialize the macro - // definition. - if (hasMacroDefinition) { - // FIXME: Check for conflicts? - uint32_t Offset = ReadUnalignedLE32(d); - Reader.SetIdentifierIsMacro(II, F, Offset); - DataLen -= 4; - } - - // Read all of the declarations visible at global scope with this - // name. - if (Reader.getContext() == 0) return II; - if (DataLen > 0) { - SmallVector DeclIDs; - for (; DataLen > 0; DataLen -= 4) - DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d))); - Reader.SetGloballyVisibleDecls(II, DeclIDs); - } - II->setIsFromAST(); return II; } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used to contain information about -/// all of the identifiers in the program. -typedef OnDiskChainedHashTable - ASTIdentifierLookupTable; - -namespace { -class ASTDeclContextNameLookupTrait { - ASTReader &Reader; - Module &F; - -public: - /// \brief Pair of begin/end iterators for DeclIDs. - /// - /// Note that these declaration IDs are local to the module that contains this - /// particular lookup t - typedef std::pair data_type; - - /// \brief Special internal key for declaration names. - /// The hash table creates keys for comparison; we do not create - /// a DeclarationName for the internal key to avoid deserializing types. - struct DeclNameKey { - DeclarationName::NameKind Kind; - uint64_t Data; - DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { } - }; - - typedef DeclarationName external_key_type; - typedef DeclNameKey internal_key_type; - - explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, - Module &F) - : Reader(Reader), F(F) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a.Kind == b.Kind && a.Data == b.Data; - } - unsigned ComputeHash(const DeclNameKey &Key) const { - llvm::FoldingSetNodeID ID; - ID.AddInteger(Key.Kind); - - switch (Key.Kind) { - case DeclarationName::Identifier: - case DeclarationName::CXXLiteralOperatorName: - ID.AddString(((IdentifierInfo*)Key.Data)->getName()); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); - break; - case DeclarationName::CXXOperatorName: - ID.AddInteger((OverloadedOperatorKind)Key.Data); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - break; - } - - return ID.ComputeHash(); + unsigned Bits = ReadUnalignedLE16(d); + bool CPlusPlusOperatorKeyword = Bits & 0x01; + Bits >>= 1; + bool HasRevertedTokenIDToIdentifier = Bits & 0x01; + Bits >>= 1; + bool Poisoned = Bits & 0x01; + Bits >>= 1; + bool ExtensionToken = Bits & 0x01; + Bits >>= 1; + bool hasMacroDefinition = Bits & 0x01; + Bits >>= 1; + unsigned ObjCOrBuiltinID = Bits & 0x3FF; + Bits >>= 10; + + assert(Bits == 0 && "Extra bits in the identifier?"); + DataLen -= 6; + + // Build the IdentifierInfo itself and link the identifier ID with + // the new IdentifierInfo. + IdentifierInfo *II = KnownII; + if (!II) + II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); + Reader.SetIdentifierInfo(ID, II); + + // Set or check the various bits in the IdentifierInfo structure. + // Token IDs are read-only. + if (HasRevertedTokenIDToIdentifier) + II->RevertTokenIDToIdentifier(); + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + assert(II->isExtensionToken() == ExtensionToken && + "Incorrect extension token flag"); + (void)ExtensionToken; + if (Poisoned) + II->setIsPoisoned(true); + assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && + "Incorrect C++ operator keyword flag"); + (void)CPlusPlusOperatorKeyword; + + // If this identifier is a macro, deserialize the macro + // definition. + if (hasMacroDefinition) { + // FIXME: Check for conflicts? + uint32_t Offset = ReadUnalignedLE32(d); + Reader.SetIdentifierIsMacro(II, F, Offset); + DataLen -= 4; + } + + // Read all of the declarations visible at global scope with this + // name. + if (Reader.getContext() == 0) return II; + if (DataLen > 0) { + SmallVector DeclIDs; + for (; DataLen > 0; DataLen -= 4) + DeclIDs.push_back(Reader.getGlobalDeclID(F, ReadUnalignedLE32(d))); + Reader.SetGloballyVisibleDecls(II, DeclIDs); + } + + II->setIsFromAST(); + return II; +} + +unsigned +ASTDeclContextNameLookupTrait::ComputeHash(const DeclNameKey &Key) const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(Key.Kind); + + switch (Key.Kind) { + case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + ID.AddString(((IdentifierInfo*)Key.Data)->getName()); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + ID.AddInteger(serialization::ComputeHash(Selector(Key.Data))); + break; + case DeclarationName::CXXOperatorName: + ID.AddInteger((OverloadedOperatorKind)Key.Data); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + break; } - internal_key_type GetInternalKey(const external_key_type& Name) const { - DeclNameKey Key; - Key.Kind = Name.getNameKind(); - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Name.getAsIdentifierInfo(); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); - break; - case DeclarationName::CXXOperatorName: - Key.Data = Name.getCXXOverloadedOperator(); - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - Key.Data = 0; - break; - } + return ID.ComputeHash(); +} - return Key; +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::GetInternalKey( + const external_key_type& Name) const { + DeclNameKey Key; + Key.Kind = Name.getNameKind(); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Name.getAsIdentifierInfo(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = (uint64_t)Name.getObjCSelector().getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = Name.getCXXOverloadedOperator(); + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Name.getCXXLiteralIdentifier(); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; } - external_key_type GetExternalKey(const internal_key_type& Key) const { - ASTContext *Context = Reader.getContext(); - switch (Key.Kind) { - case DeclarationName::Identifier: - return DeclarationName((IdentifierInfo*)Key.Data); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(Selector(Key.Data)); + return Key; +} - case DeclarationName::CXXConstructorName: - return Context->DeclarationNames.getCXXConstructorName( - Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); +ASTDeclContextNameLookupTrait::external_key_type +ASTDeclContextNameLookupTrait::GetExternalKey( + const internal_key_type& Key) const { + ASTContext *Context = Reader.getContext(); + switch (Key.Kind) { + case DeclarationName::Identifier: + return DeclarationName((IdentifierInfo*)Key.Data); - case DeclarationName::CXXDestructorName: - return Context->DeclarationNames.getCXXDestructorName( - Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return DeclarationName(Selector(Key.Data)); - case DeclarationName::CXXConversionFunctionName: - return Context->DeclarationNames.getCXXConversionFunctionName( - Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); + case DeclarationName::CXXConstructorName: + return Context->DeclarationNames.getCXXConstructorName( + Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXOperatorName: - return Context->DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Key.Data); + case DeclarationName::CXXDestructorName: + return Context->DeclarationNames.getCXXDestructorName( + Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXLiteralOperatorName: - return Context->DeclarationNames.getCXXLiteralOperatorName( - (IdentifierInfo*)Key.Data); + case DeclarationName::CXXConversionFunctionName: + return Context->DeclarationNames.getCXXConversionFunctionName( + Context->getCanonicalType(Reader.getLocalType(F, Key.Data))); - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } + case DeclarationName::CXXOperatorName: + return Context->DeclarationNames.getCXXOperatorName( + (OverloadedOperatorKind)Key.Data); - llvm_unreachable("Invalid Name Kind ?"); - } + case DeclarationName::CXXLiteralOperatorName: + return Context->DeclarationNames.getCXXLiteralOperatorName( + (IdentifierInfo*)Key.Data); - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); + case DeclarationName::CXXUsingDirective: + return DeclarationName::getUsingDirectiveName(); } - internal_key_type ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; + llvm_unreachable("Invalid Name Kind ?"); +} - DeclNameKey Key; - Key.Kind = (DeclarationName::NameKind)*d++; - switch (Key.Kind) { - case DeclarationName::Identifier: - Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - break; - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - Key.Data = - (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) - .getAsOpaquePtr(); - break; - case DeclarationName::CXXOperatorName: - Key.Data = *d++; // OverloadedOperatorKind - break; - case DeclarationName::CXXLiteralOperatorName: - Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); - break; - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - case DeclarationName::CXXUsingDirective: - Key.Data = 0; - break; - } +std::pair +ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); +} - return Key; - } +ASTDeclContextNameLookupTrait::internal_key_type +ASTDeclContextNameLookupTrait::ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; - data_type ReadData(internal_key_type, const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - unsigned NumDecls = ReadUnalignedLE16(d); - DeclID *Start = (DeclID *)d; - return std::make_pair(Start, Start + NumDecls); + DeclNameKey Key; + Key.Kind = (DeclarationName::NameKind)*d++; + switch (Key.Kind) { + case DeclarationName::Identifier: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + Key.Data = + (uint64_t)Reader.getLocalSelector(F, ReadUnalignedLE32(d)) + .getAsOpaquePtr(); + break; + case DeclarationName::CXXOperatorName: + Key.Data = *d++; // OverloadedOperatorKind + break; + case DeclarationName::CXXLiteralOperatorName: + Key.Data = (uint64_t)Reader.getLocalIdentifier(F, ReadUnalignedLE32(d)); + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXUsingDirective: + Key.Data = 0; + break; } -}; -} // end anonymous namespace + return Key; +} -/// \brief The on-disk hash table used for the DeclContext's Name lookup table. -typedef OnDiskChainedHashTable - ASTDeclContextNameLookupTable; +ASTDeclContextNameLookupTrait::data_type +ASTDeclContextNameLookupTrait::ReadData(internal_key_type, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + unsigned NumDecls = ReadUnalignedLE16(d); + DeclID *Start = (DeclID *)d; + return std::make_pair(Start, Start + NumDecls); +} bool ASTReader::ReadDeclContextStorage(Module &M, llvm::BitstreamCursor &Cursor, @@ -1631,116 +1530,65 @@ ASTReader::getGlobalPreprocessedEntityID(Module &M, unsigned LocalID) { return LocalID + I->second; } -namespace { - /// \brief 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 - /// filename, 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; - Module &M; - HeaderSearch *HS; - const char *FrameworkStrings; - const char *SearchPath; - struct stat SearchPathStatBuf; - llvm::Optional SearchPathStatResult; - - int StatSimpleCache(const char *Path, struct stat *StatBuf) { - if (Path == SearchPath) { - if (!SearchPathStatResult) - SearchPathStatResult = stat(Path, &SearchPathStatBuf); - - *StatBuf = SearchPathStatBuf; - return *SearchPathStatResult; - } - - return stat(Path, StatBuf); - } - - public: - typedef const char *external_key_type; - typedef const char *internal_key_type; - - typedef HeaderFileInfo data_type; - - HeaderFileInfoTrait(ASTReader &Reader, Module &M, HeaderSearch *HS, - const char *FrameworkStrings, - const char *SearchPath = 0) - : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings), - SearchPath(SearchPath) { } - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(llvm::sys::path::filename(path)); - } - - static internal_key_type GetInternalKey(const char *path) { return path; } +unsigned HeaderFileInfoTrait::ComputeHash(const char *path) { + return llvm::HashString(llvm::sys::path::filename(path)); +} - bool EqualKey(internal_key_type a, internal_key_type b) { - if (strcmp(a, b) == 0) - return true; - - if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) - return false; - - // The file names match, but the path names don't. stat() the files to - // see if they are the same. - struct stat StatBufA, StatBufB; - if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB)) - return false; - - return StatBufA.st_ino == StatBufB.st_ino; - } +HeaderFileInfoTrait::internal_key_type +HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; } - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); - unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); - } +bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) { + if (strcmp(a, b) == 0) + return true; + + if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b)) + return false; + + // The file names match, but the path names don't. stat() the files to + // see if they are the same. + struct stat StatBufA, StatBufB; + if (StatSimpleCache(a, &StatBufA) || StatSimpleCache(b, &StatBufB)) + return false; + + return StatBufA.st_ino == StatBufB.st_ino; +} - static internal_key_type ReadKey(const unsigned char *d, unsigned) { - return (const char *)d; - } +std::pair +HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) { + unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); + unsigned DataLen = (unsigned) *d++; + return std::make_pair(KeyLen + 1, DataLen); +} - data_type ReadData(const internal_key_type, const unsigned char *d, - unsigned DataLen) { - const unsigned char *End = d + DataLen; - using namespace clang::io; - HeaderFileInfo HFI; - unsigned Flags = *d++; - HFI.isImport = (Flags >> 5) & 0x01; - HFI.isPragmaOnce = (Flags >> 4) & 0x01; - HFI.DirInfo = (Flags >> 2) & 0x03; - HFI.Resolved = (Flags >> 1) & 0x01; - HFI.IndexHeaderMapHeader = Flags & 0x01; - HFI.NumIncludes = ReadUnalignedLE16(d); - HFI.ControllingMacroID = Reader.getGlobalDeclID(M, ReadUnalignedLE32(d)); - if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) { - // The framework offset is 1 greater than the actual offset, - // since 0 is used as an indicator for "no framework name". - StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); - HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); - } - - assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); - (void)End; - - // This HeaderFileInfo was externally loaded. - HFI.External = true; - return HFI; - } - }; +HeaderFileInfoTrait::data_type +HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, + unsigned DataLen) { + const unsigned char *End = d + DataLen; + using namespace clang::io; + HeaderFileInfo HFI; + unsigned Flags = *d++; + HFI.isImport = (Flags >> 5) & 0x01; + HFI.isPragmaOnce = (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 2) & 0x03; + HFI.Resolved = (Flags >> 1) & 0x01; + HFI.IndexHeaderMapHeader = Flags & 0x01; + HFI.NumIncludes = ReadUnalignedLE16(d); + HFI.ControllingMacroID = Reader.getGlobalDeclID(M, ReadUnalignedLE32(d)); + if (unsigned FrameworkOffset = ReadUnalignedLE32(d)) { + // The framework offset is 1 greater than the actual offset, + // since 0 is used as an indicator for "no framework name". + StringRef FrameworkName(FrameworkStrings + FrameworkOffset - 1); + HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); + } + + assert(End == d && "Wrong data length in HeaderFileInfo deserialization"); + (void)End; + + // This HeaderFileInfo was externally loaded. + HFI.External = true; + return HFI; } -/// \brief The on-disk hash table used for the global method pool. -typedef OnDiskChainedHashTable - HeaderFileInfoLookupTable; - void ASTReader::SetIdentifierIsMacro(IdentifierInfo *II, Module &F, uint64_t LocalOffset) { // Note that this identifier has a macro definition. @@ -5718,291 +5566,3 @@ ASTReader::~ASTReader() { delete static_cast(J->first); } } - -//===----------------------------------------------------------------------===// -// Module implementation -//===----------------------------------------------------------------------===// -Module::Module(ModuleKind Kind) - : Kind(Kind), DirectlyImported(false), SizeInBits(0), - LocalNumSLocEntries(0), SLocEntryBaseID(0), - SLocEntryBaseOffset(0), SLocEntryOffsets(0), - SLocFileOffsets(0), LocalNumIdentifiers(0), - IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0), - IdentifierLookupTable(0), BasePreprocessedEntityID(0), - LocalNumMacroDefinitions(0), MacroDefinitionOffsets(0), - BaseMacroDefinitionID(0), LocalNumHeaderFileInfos(0), - HeaderFileInfoTableData(0), HeaderFileInfoTable(0), - HeaderFileFrameworkStrings(0), - LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0), - SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), - DeclOffsets(0), BaseDeclID(0), - LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), - LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0), - NumPreallocatedPreprocessingEntities(0) -{} - -Module::~Module() { - for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(), - E = DeclContextInfos.end(); - I != E; ++I) { - if (I->second.NameLookupTableData) - delete static_cast( - I->second.NameLookupTableData); - } - - delete static_cast(IdentifierLookupTable); - delete static_cast(HeaderFileInfoTable); - delete static_cast(SelectorLookupTable); -} - -template -static void -dumpLocalRemap(StringRef Name, - const ContinuousRangeMap &Map) { - if (Map.begin() == Map.end()) - return; - - typedef ContinuousRangeMap MapType; - llvm::errs() << " " << Name << ":\n"; - for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); - I != IEnd; ++I) { - llvm::errs() << " " << I->first << " -> " << I->second - << "\n"; - } -} - -void Module::dump() { - llvm::errs() << "\nModule: " << FileName << "\n"; - if (!Imports.empty()) { - llvm::errs() << " Imports: "; - for (unsigned I = 0, N = Imports.size(); I != N; ++I) { - if (I) - llvm::errs() << ", "; - llvm::errs() << Imports[I]->FileName; - } - llvm::errs() << "\n"; - } - - // Remapping tables. - llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset - << '\n'; - dumpLocalRemap("Source location offset local -> global map", SLocRemap); - - llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n' - << " Number of identifiers: " << LocalNumIdentifiers << '\n'; - dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap); - - llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n' - << " Number of selectors: " << LocalNumSelectors << '\n'; - dumpLocalRemap("Selector ID local -> global map", SelectorRemap); - - llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID - << '\n' - << " Number of preprocessed entities: " - << NumPreallocatedPreprocessingEntities << '\n'; - dumpLocalRemap("Preprocessed entity ID local -> global map", - PreprocessedEntityRemap); - - llvm::errs() << " Base macro definition ID: " << BaseMacroDefinitionID - << '\n' - << " Number of macro definitions: " << LocalNumMacroDefinitions - << '\n'; - dumpLocalRemap("Macro definition ID local -> global map", - MacroDefinitionRemap); - - llvm::errs() << " Base type index: " << BaseTypeIndex << '\n' - << " Number of types: " << LocalNumTypes << '\n'; - dumpLocalRemap("Type index local -> global map", TypeRemap); - - llvm::errs() << " Base decl ID: " << BaseDeclID << '\n' - << " Number of decls: " << LocalNumDecls << '\n'; - dumpLocalRemap("Decl ID local -> global map", DeclRemap); -} - -//===----------------------------------------------------------------------===// -// Module manager implementation -//===----------------------------------------------------------------------===// - -Module *ModuleManager::lookup(StringRef Name) { - const FileEntry *Entry = FileMgr.getFile(Name); - return Modules[Entry]; -} - -llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { - const FileEntry *Entry = FileMgr.getFile(Name); - return InMemoryBuffers[Entry]; -} - -std::pair -ModuleManager::addModule(StringRef FileName, ModuleKind Type, - Module *ImportedBy, std::string &ErrorStr) { - const FileEntry *Entry = FileMgr.getFile(FileName); - if (!Entry && FileName != "-") { - ErrorStr = "file not found"; - return std::make_pair(static_cast(0), false); - } - - // Check whether we already loaded this module, before - Module *&ModuleEntry = Modules[Entry]; - bool NewModule = false; - if (!ModuleEntry) { - // Allocate a new module. - Module *New = new Module(Type); - New->FileName = FileName.str(); - Chain.push_back(New); - NewModule = true; - ModuleEntry = New; - - // Load the contents of the module - if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { - // The buffer was already provided for us. - assert(Buffer && "Passed null buffer"); - New->Buffer.reset(Buffer); - } else { - // Open the AST file. - llvm::error_code ec; - if (FileName == "-") { - ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); - if (ec) - ErrorStr = ec.message(); - } else - New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); - - if (!New->Buffer) - return std::make_pair(static_cast(0), false); - } - - // Initialize the stream - New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), - (const unsigned char *)New->Buffer->getBufferEnd()); } - - if (ImportedBy) { - ModuleEntry->ImportedBy.insert(ImportedBy); - ImportedBy->Imports.insert(ModuleEntry); - } else { - ModuleEntry->DirectlyImported = true; - } - - return std::make_pair(ModuleEntry, NewModule); -} - -void ModuleManager::addInMemoryBuffer(StringRef FileName, - llvm::MemoryBuffer *Buffer) { - - const FileEntry *Entry = FileMgr.getVirtualFile(FileName, - Buffer->getBufferSize(), 0); - InMemoryBuffers[Entry] = Buffer; -} - -ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } - -ModuleManager::~ModuleManager() { - for (unsigned i = 0, e = Chain.size(); i != e; ++i) - delete Chain[e - i - 1]; -} - -void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData), - void *UserData) { - unsigned N = size(); - - // Record the number of incoming edges for each module. When we - // encounter a module with no incoming edges, push it into the queue - // to seed the queue. - SmallVector Queue; - Queue.reserve(N); - llvm::DenseMap UnusedIncomingEdges; - for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { - if (unsigned Size = (*M)->ImportedBy.size()) - UnusedIncomingEdges[*M] = Size; - else - Queue.push_back(*M); - } - - llvm::SmallPtrSet Skipped; - unsigned QueueStart = 0; - while (QueueStart < Queue.size()) { - Module *CurrentModule = Queue[QueueStart++]; - - // Check whether this module should be skipped. - if (Skipped.count(CurrentModule)) - continue; - - if (Visitor(*CurrentModule, UserData)) { - // The visitor has requested that cut off visitation of any - // module that the current module depends on. To indicate this - // behavior, we mark all of the reachable modules as having N - // incoming edges (which is impossible otherwise). - SmallVector Stack; - Stack.push_back(CurrentModule); - Skipped.insert(CurrentModule); - while (!Stack.empty()) { - Module *NextModule = Stack.back(); - Stack.pop_back(); - - // For any module that this module depends on, push it on the - // stack (if it hasn't already been marked as visited). - for (llvm::SetVector::iterator - M = NextModule->Imports.begin(), - MEnd = NextModule->Imports.end(); - M != MEnd; ++M) { - if (Skipped.insert(*M)) - Stack.push_back(*M); - } - } - continue; - } - - // For any module that this module depends on, push it on the - // stack (if it hasn't already been marked as visited). - for (llvm::SetVector::iterator M = CurrentModule->Imports.begin(), - MEnd = CurrentModule->Imports.end(); - M != MEnd; ++M) { - - // Remove our current module as an impediment to visiting the - // module we depend on. If we were the last unvisited module - // that depends on this particular module, push it into the - // queue to be visited. - unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; - if (NumUnusedEdges && (--NumUnusedEdges == 0)) - Queue.push_back(*M); - } - } -} - -/// \brief Perform a depth-first visit of the current module. -static bool visitDepthFirst(Module &M, - bool (*Visitor)(Module &M, bool Preorder, - void *UserData), - void *UserData, - llvm::SmallPtrSet &Visited) { - // Preorder visitation - if (Visitor(M, /*Preorder=*/true, UserData)) - return true; - - // Visit children - for (llvm::SetVector::iterator IM = M.Imports.begin(), - IMEnd = M.Imports.end(); - IM != IMEnd; ++IM) { - if (!Visited.insert(*IM)) - continue; - - if (visitDepthFirst(**IM, Visitor, UserData, Visited)) - return true; - } - - // Postorder visitation - return Visitor(M, /*Preorder=*/false, UserData); -} - -void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, - void *UserData), - void *UserData) { - llvm::SmallPtrSet Visited; - for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (!Visited.insert(Chain[I])) - continue; - - if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) - return; - } -} diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h new file mode 100644 index 0000000000..14ff744716 --- /dev/null +++ b/lib/Serialization/ASTReaderInternals.h @@ -0,0 +1,243 @@ +//===--- ASTReaderInternals.h - AST Reader Internals ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides internal definitions used in the AST reader. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H +#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H + +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/AST/DeclarationName.h" +#include +#include + +namespace clang { + +class ASTReader; +class HeaderSearch; +struct HeaderFileInfo; + +namespace serialization { + +class Module; + +namespace reader { + +/// \brief Class that performs name lookup into a DeclContext stored +/// in an AST file. +class ASTDeclContextNameLookupTrait { + ASTReader &Reader; + Module &F; + +public: + /// \brief Pair of begin/end iterators for DeclIDs. + /// + /// Note that these declaration IDs are local to the module that contains this + /// particular lookup t + typedef std::pair data_type; + + /// \brief Special internal key for declaration names. + /// The hash table creates keys for comparison; we do not create + /// a DeclarationName for the internal key to avoid deserializing types. + struct DeclNameKey { + DeclarationName::NameKind Kind; + uint64_t Data; + DeclNameKey() : Kind((DeclarationName::NameKind)0), Data(0) { } + }; + + typedef DeclarationName external_key_type; + typedef DeclNameKey internal_key_type; + + explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, + Module &F) + : Reader(Reader), F(F) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a.Kind == b.Kind && a.Data == b.Data; + } + + unsigned ComputeHash(const DeclNameKey &Key) const; + internal_key_type GetInternalKey(const external_key_type& Name) const; + external_key_type GetExternalKey(const internal_key_type& Key) const; + + static std::pair + ReadKeyDataLength(const unsigned char*& d); + + internal_key_type ReadKey(const unsigned char* d, unsigned); + + data_type ReadData(internal_key_type, const unsigned char* d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used for the DeclContext's Name lookup table. +typedef OnDiskChainedHashTable + ASTDeclContextNameLookupTable; + +/// \brief Class that performs lookup for an identifier stored in an AST file. +class ASTIdentifierLookupTrait { + ASTReader &Reader; + Module &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; + +public: + typedef IdentifierInfo * data_type; + + typedef const std::pair external_key_type; + + typedef external_key_type internal_key_type; + + ASTIdentifierLookupTrait(ASTReader &Reader, Module &F, + IdentifierInfo *II = 0) + : Reader(Reader), F(F), KnownII(II) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 + : false; + } + + static unsigned ComputeHash(const internal_key_type& a); + + // 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 std::pair + ReadKeyDataLength(const unsigned char*& d); + + static std::pair + ReadKey(const unsigned char* d, unsigned n); + + IdentifierInfo *ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used to contain information about +/// all of the identifiers in the program. +typedef OnDiskChainedHashTable + ASTIdentifierLookupTable; + +/// \brief Class that performs lookup for a selector's entries in the global +/// method pool stored in an AST file. +class ASTSelectorLookupTrait { + ASTReader &Reader; + Module &F; + +public: + struct data_type { + SelectorID ID; + llvm::SmallVector Instance; + llvm::SmallVector Factory; + }; + + typedef Selector external_key_type; + typedef external_key_type internal_key_type; + + ASTSelectorLookupTrait(ASTReader &Reader, Module &F) + : Reader(Reader), F(F) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(Selector Sel); + + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; }; + + static std::pair + ReadKeyDataLength(const unsigned char*& d); + + internal_key_type ReadKey(const unsigned char* d, unsigned); + data_type ReadData(Selector, const unsigned char* d, unsigned DataLen); +}; + +/// \brief The on-disk hash table used for the global method pool. +typedef OnDiskChainedHashTable + ASTSelectorLookupTable; + +/// \brief 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 +/// filename, 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; + Module &M; + HeaderSearch *HS; + const char *FrameworkStrings; + const char *SearchPath; + struct stat SearchPathStatBuf; + llvm::Optional SearchPathStatResult; + + int StatSimpleCache(const char *Path, struct stat *StatBuf) { + if (Path == SearchPath) { + if (!SearchPathStatResult) + SearchPathStatResult = stat(Path, &SearchPathStatBuf); + + *StatBuf = SearchPathStatBuf; + return *SearchPathStatResult; + } + + return stat(Path, StatBuf); + } + +public: + typedef const char *external_key_type; + typedef const char *internal_key_type; + + typedef HeaderFileInfo data_type; + + HeaderFileInfoTrait(ASTReader &Reader, Module &M, HeaderSearch *HS, + const char *FrameworkStrings, + const char *SearchPath = 0) + : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings), + SearchPath(SearchPath) { } + + static unsigned ComputeHash(const char *path); + static internal_key_type GetInternalKey(const char *path); + bool EqualKey(internal_key_type a, internal_key_type b); + + static std::pair + ReadKeyDataLength(const unsigned char*& d); + + static internal_key_type ReadKey(const unsigned char *d, unsigned) { + return (const char *)d; + } + + data_type ReadData(const internal_key_type, const unsigned char *d, + unsigned DataLen); +}; + +/// \brief The on-disk hash table used for known header files. +typedef OnDiskChainedHashTable + HeaderFileInfoLookupTable; + +} // end namespace clang::serialization::reader +} // end namespace clang::serialization +} // end namespace clang + + +#endif diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt index 66a72ee19d..5611056f01 100644 --- a/lib/Serialization/CMakeLists.txt +++ b/lib/Serialization/CMakeLists.txt @@ -2,6 +2,8 @@ #set(LLVM_USED_LIBS ???) add_clang_library(clangSerialization + ASTCommon.h + ASTReaderInternals.h ASTCommon.cpp ASTReader.cpp ASTReaderDecl.cpp @@ -11,6 +13,8 @@ add_clang_library(clangSerialization ASTWriterStmt.cpp ChainedIncludesSource.cpp GeneratePCH.cpp + Module.cpp + ModuleManager.cpp ) add_dependencies(clangSerialization diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp new file mode 100644 index 0000000000..b5a96bb98b --- /dev/null +++ b/lib/Serialization/Module.cpp @@ -0,0 +1,117 @@ +//===--- Module.cpp - Module description ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Module class, which describes a module that has +// been loaded from an AST file. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/Module.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "ASTReaderInternals.h" + +using namespace clang; +using namespace serialization; +using namespace reader; + +Module::Module(ModuleKind Kind) + : Kind(Kind), DirectlyImported(false), SizeInBits(0), + LocalNumSLocEntries(0), SLocEntryBaseID(0), + SLocEntryBaseOffset(0), SLocEntryOffsets(0), + SLocFileOffsets(0), LocalNumIdentifiers(0), + IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0), + IdentifierLookupTable(0), BasePreprocessedEntityID(0), + LocalNumMacroDefinitions(0), MacroDefinitionOffsets(0), + BaseMacroDefinitionID(0), LocalNumHeaderFileInfos(0), + HeaderFileInfoTableData(0), HeaderFileInfoTable(0), + HeaderFileFrameworkStrings(0), + LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0), + SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), + DeclOffsets(0), BaseDeclID(0), + LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), + LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0), + NumPreallocatedPreprocessingEntities(0) +{} + +Module::~Module() { + for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(), + E = DeclContextInfos.end(); + I != E; ++I) { + if (I->second.NameLookupTableData) + delete static_cast( + I->second.NameLookupTableData); + } + + delete static_cast(IdentifierLookupTable); + delete static_cast(HeaderFileInfoTable); + delete static_cast(SelectorLookupTable); +} + +template +static void +dumpLocalRemap(StringRef Name, + const ContinuousRangeMap &Map) { + if (Map.begin() == Map.end()) + return; + + typedef ContinuousRangeMap MapType; + llvm::errs() << " " << Name << ":\n"; + for (typename MapType::const_iterator I = Map.begin(), IEnd = Map.end(); + I != IEnd; ++I) { + llvm::errs() << " " << I->first << " -> " << I->second << "\n"; + } +} + +void Module::dump() { + llvm::errs() << "\nModule: " << FileName << "\n"; + if (!Imports.empty()) { + llvm::errs() << " Imports: "; + for (unsigned I = 0, N = Imports.size(); I != N; ++I) { + if (I) + llvm::errs() << ", "; + llvm::errs() << Imports[I]->FileName; + } + llvm::errs() << "\n"; + } + + // Remapping tables. + llvm::errs() << " Base source location offset: " << SLocEntryBaseOffset + << '\n'; + dumpLocalRemap("Source location offset local -> global map", SLocRemap); + + llvm::errs() << " Base identifier ID: " << BaseIdentifierID << '\n' + << " Number of identifiers: " << LocalNumIdentifiers << '\n'; + dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap); + + llvm::errs() << " Base selector ID: " << BaseSelectorID << '\n' + << " Number of selectors: " << LocalNumSelectors << '\n'; + dumpLocalRemap("Selector ID local -> global map", SelectorRemap); + + llvm::errs() << " Base preprocessed entity ID: " << BasePreprocessedEntityID + << '\n' + << " Number of preprocessed entities: " + << NumPreallocatedPreprocessingEntities << '\n'; + dumpLocalRemap("Preprocessed entity ID local -> global map", + PreprocessedEntityRemap); + + llvm::errs() << " Base macro definition ID: " << BaseMacroDefinitionID + << '\n' + << " Number of macro definitions: " << LocalNumMacroDefinitions + << '\n'; + dumpLocalRemap("Macro definition ID local -> global map", + MacroDefinitionRemap); + + llvm::errs() << " Base type index: " << BaseTypeIndex << '\n' + << " Number of types: " << LocalNumTypes << '\n'; + dumpLocalRemap("Type index local -> global map", TypeRemap); + + llvm::errs() << " Base decl ID: " << BaseDeclID << '\n' + << " Number of decls: " << LocalNumDecls << '\n'; + dumpLocalRemap("Decl ID local -> global map", DeclRemap); +} diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp new file mode 100644 index 0000000000..a9fe64d42b --- /dev/null +++ b/lib/Serialization/ModuleManager.cpp @@ -0,0 +1,204 @@ +//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleManager class, which manages a set of loaded +// modules for the ASTReader. +// +//===----------------------------------------------------------------------===// +#include "clang/Serialization/ModuleManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +using namespace clang; +using namespace serialization; + +Module *ModuleManager::lookup(StringRef Name) { + const FileEntry *Entry = FileMgr.getFile(Name); + return Modules[Entry]; +} + +llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { + const FileEntry *Entry = FileMgr.getFile(Name); + return InMemoryBuffers[Entry]; +} + +std::pair +ModuleManager::addModule(StringRef FileName, ModuleKind Type, + Module *ImportedBy, std::string &ErrorStr) { + const FileEntry *Entry = FileMgr.getFile(FileName); + if (!Entry && FileName != "-") { + ErrorStr = "file not found"; + return std::make_pair(static_cast(0), false); + } + + // Check whether we already loaded this module, before + Module *&ModuleEntry = Modules[Entry]; + bool NewModule = false; + if (!ModuleEntry) { + // Allocate a new module. + Module *New = new Module(Type); + New->FileName = FileName.str(); + Chain.push_back(New); + NewModule = true; + ModuleEntry = New; + + // Load the contents of the module + if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { + // The buffer was already provided for us. + assert(Buffer && "Passed null buffer"); + New->Buffer.reset(Buffer); + } else { + // Open the AST file. + llvm::error_code ec; + if (FileName == "-") { + ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); + if (ec) + ErrorStr = ec.message(); + } else + New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); + + if (!New->Buffer) + return std::make_pair(static_cast(0), false); + } + + // Initialize the stream + New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), + (const unsigned char *)New->Buffer->getBufferEnd()); } + + if (ImportedBy) { + ModuleEntry->ImportedBy.insert(ImportedBy); + ImportedBy->Imports.insert(ModuleEntry); + } else { + ModuleEntry->DirectlyImported = true; + } + + return std::make_pair(ModuleEntry, NewModule); +} + +void ModuleManager::addInMemoryBuffer(StringRef FileName, + llvm::MemoryBuffer *Buffer) { + + const FileEntry *Entry = FileMgr.getVirtualFile(FileName, + Buffer->getBufferSize(), 0); + InMemoryBuffers[Entry] = Buffer; +} + +ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } + +ModuleManager::~ModuleManager() { + for (unsigned i = 0, e = Chain.size(); i != e; ++i) + delete Chain[e - i - 1]; +} + +void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData), + void *UserData) { + unsigned N = size(); + + // Record the number of incoming edges for each module. When we + // encounter a module with no incoming edges, push it into the queue + // to seed the queue. + SmallVector Queue; + Queue.reserve(N); + llvm::DenseMap UnusedIncomingEdges; + for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { + if (unsigned Size = (*M)->ImportedBy.size()) + UnusedIncomingEdges[*M] = Size; + else + Queue.push_back(*M); + } + + llvm::SmallPtrSet Skipped; + unsigned QueueStart = 0; + while (QueueStart < Queue.size()) { + Module *CurrentModule = Queue[QueueStart++]; + + // Check whether this module should be skipped. + if (Skipped.count(CurrentModule)) + continue; + + if (Visitor(*CurrentModule, UserData)) { + // The visitor has requested that cut off visitation of any + // module that the current module depends on. To indicate this + // behavior, we mark all of the reachable modules as having N + // incoming edges (which is impossible otherwise). + SmallVector Stack; + Stack.push_back(CurrentModule); + Skipped.insert(CurrentModule); + while (!Stack.empty()) { + Module *NextModule = Stack.back(); + Stack.pop_back(); + + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector::iterator + M = NextModule->Imports.begin(), + MEnd = NextModule->Imports.end(); + M != MEnd; ++M) { + if (Skipped.insert(*M)) + Stack.push_back(*M); + } + } + continue; + } + + // For any module that this module depends on, push it on the + // stack (if it hasn't already been marked as visited). + for (llvm::SetVector::iterator M = CurrentModule->Imports.begin(), + MEnd = CurrentModule->Imports.end(); + M != MEnd; ++M) { + + // Remove our current module as an impediment to visiting the + // module we depend on. If we were the last unvisited module + // that depends on this particular module, push it into the + // queue to be visited. + unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; + if (NumUnusedEdges && (--NumUnusedEdges == 0)) + Queue.push_back(*M); + } + } +} + +/// \brief Perform a depth-first visit of the current module. +static bool visitDepthFirst(Module &M, + bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData, + llvm::SmallPtrSet &Visited) { + // Preorder visitation + if (Visitor(M, /*Preorder=*/true, UserData)) + return true; + + // Visit children + for (llvm::SetVector::iterator IM = M.Imports.begin(), + IMEnd = M.Imports.end(); + IM != IMEnd; ++IM) { + if (!Visited.insert(*IM)) + continue; + + if (visitDepthFirst(**IM, Visitor, UserData, Visited)) + return true; + } + + // Postorder visitation + return Visitor(M, /*Preorder=*/false, UserData); +} + +void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, + void *UserData), + void *UserData) { + llvm::SmallPtrSet Visited; + for (unsigned I = 0, N = Chain.size(); I != N; ++I) { + if (!Visited.insert(Chain[I])) + continue; + + if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) + return; + } +}