Introduce the mechanism for building an AST on-disk hash table for name lookup inside a DeclContext but don't use it yet.

llvm-svn: 111635
This commit is contained in:
Argyrios Kyrtzidis 2010-08-20 16:04:27 +00:00
parent 082e4613eb
commit 07347321c6
6 changed files with 362 additions and 35 deletions

View File

@ -124,8 +124,9 @@ class OnDiskChainedHashTableGenerator {
Item *next;
const uint32_t hash;
Item(typename Info::key_type_ref k, typename Info::data_type_ref d)
: key(k), data(d), next(0), hash(Info::ComputeHash(k)) {}
Item(typename Info::key_type_ref k, typename Info::data_type_ref d,
Info &InfoObj)
: key(k), data(d), next(0), hash(InfoObj.ComputeHash(k)) {}
};
class Bucket {
@ -168,10 +169,17 @@ public:
void insert(typename Info::key_type_ref key,
typename Info::data_type_ref data) {
Info InfoObj;
insert(key, data, InfoObj);
}
void insert(typename Info::key_type_ref key,
typename Info::data_type_ref data, Info &InfoObj) {
++NumEntries;
if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2);
insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data));
insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data,
InfoObj));
}
io::Offset Emit(llvm::raw_ostream &out) {
@ -278,8 +286,8 @@ public:
InfoPtr = &InfoObj;
using namespace io;
const internal_key_type& iKey = Info::GetInternalKey(eKey);
unsigned key_hash = Info::ComputeHash(iKey);
const internal_key_type& iKey = InfoObj.GetInternalKey(eKey);
unsigned key_hash = InfoObj.ComputeHash(iKey);
// Each bucket is just a 32-bit offset into the hash table file.
unsigned idx = key_hash & (NumBuckets - 1);

View File

@ -20,6 +20,7 @@
#include "clang/AST/Type.h"
#include "llvm/Bitcode/BitCodes.h"
#include "llvm/System/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
namespace serialization {
@ -81,6 +82,36 @@ namespace clang {
}
};
/// A structure for putting "fast"-unqualified QualTypes into a
/// DenseMap. This uses the standard pointer hash function.
struct UnsafeQualTypeDenseMapInfo {
static inline bool isEqual(QualType A, QualType B) { return A == B; }
static inline QualType getEmptyKey() {
return QualType::getFromOpaquePtr((void*) 1);
}
static inline QualType getTombstoneKey() {
return QualType::getFromOpaquePtr((void*) 2);
}
static inline unsigned getHashValue(QualType T) {
assert(!T.getLocalFastQualifiers() &&
"hash invalid for types with fast quals");
uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
return (unsigned(v) >> 4) ^ (unsigned(v) >> 9);
}
};
/// \brief Map that provides the ID numbers of each type within the
/// output stream, plus those deserialized from a chained PCH.
///
/// The ID numbers of types are consecutive (in order of discovery)
/// and start at 1. 0 is reserved for NULL. When types are actually
/// stored in the stream, the ID number is shifted by 2 bits to
/// allow for the const/volatile qualifiers.
///
/// Keys in the map never have const/volatile qualifiers.
typedef llvm::DenseMap<QualType, TypeIdx, UnsafeQualTypeDenseMapInfo>
TypeIdxMap;
/// \brief An ID number that refers to an identifier in an AST
/// file.
typedef uint32_t IdentID;

View File

@ -27,7 +27,6 @@
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@ -315,6 +314,17 @@ private:
/// ID = (I + 1) << FastQual::Width has already been loaded
std::vector<QualType> TypesLoaded;
/// \brief Map that provides the ID numbers of each type within the
/// output stream, plus those deserialized from a chained PCH.
///
/// The ID numbers of types are consecutive (in order of discovery)
/// and start at 1. 0 is reserved for NULL. When types are actually
/// stored in the stream, the ID number is shifted by 2 bits to
/// allow for the const/volatile qualifiers.
///
/// Keys in the map never have const/volatile qualifiers.
serialization::TypeIdxMap TypeIdxs;
/// \brief Declarations that have already been loaded from the chain.
///
/// When the pointer at index I is non-NULL, the declaration with ID
@ -720,6 +730,16 @@ public:
/// type.
QualType GetType(serialization::TypeID ID);
/// \brief Returns the type ID associated with the given type.
/// If the type didn't come from the AST file the ID that is returned is
/// marked as "doesn't exist in AST".
serialization::TypeID GetTypeID(QualType T) const;
/// \brief Returns the type index associated with the given type.
/// If the type didn't come from the AST file the index that is returned is
/// marked as "doesn't exist in AST".
serialization::TypeIdx GetTypeIdx(QualType T) const;
/// \brief Resolve a declaration ID into a declaration, potentially
/// building a new declaration.
Decl *GetDecl(serialization::DeclID ID);

View File

@ -20,7 +20,6 @@
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Sema/SemaConsumer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamWriter.h"
@ -50,24 +49,6 @@ class SourceManager;
class SwitchCase;
class TargetInfo;
/// A structure for putting "fast"-unqualified QualTypes into a
/// DenseMap. This uses the standard pointer hash function.
struct UnsafeQualTypeDenseMapInfo {
static inline bool isEqual(QualType A, QualType B) { return A == B; }
static inline QualType getEmptyKey() {
return QualType::getFromOpaquePtr((void*) 1);
}
static inline QualType getTombstoneKey() {
return QualType::getFromOpaquePtr((void*) 2);
}
static inline unsigned getHashValue(QualType T) {
assert(!T.getLocalFastQualifiers() &&
"hash invalid for types with fast quals");
uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
return (unsigned(v) >> 4) ^ (unsigned(v) >> 9);
}
};
/// \brief Writes an AST file containing the contents of a translation unit.
///
/// The ASTWriter class produces a bitstream containing the serialized
@ -146,8 +127,7 @@ private:
/// allow for the const/volatile qualifiers.
///
/// Keys in the map never have const/volatile qualifiers.
llvm::DenseMap<QualType, serialization::TypeIdx, UnsafeQualTypeDenseMapInfo>
TypeIdxs;
serialization::TypeIdxMap TypeIdxs;
/// \brief Offset of each type in the bitstream, indexed by
/// the type's ID.
@ -368,13 +348,13 @@ public:
serialization::TypeID GetOrCreateTypeID(QualType T);
/// \brief Determine the type ID of an already-emitted type.
serialization::TypeID getTypeID(QualType T);
serialization::TypeID getTypeID(QualType T) const;
/// \brief Force a type to be emitted and get its index.
serialization::TypeIdx GetOrCreateTypeIdx(QualType T);
/// \brief Determine the type index of an already-emitted type.
serialization::TypeIdx getTypeIdx(QualType T);
serialization::TypeIdx getTypeIdx(QualType T) const;
/// \brief Emits a reference to a declarator info.
void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record);

View File

@ -704,6 +704,148 @@ public:
typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
ASTIdentifierLookupTable;
namespace {
class ASTDeclContextNameLookupTrait {
ASTReader &Reader;
public:
/// \brief Pair of begin/end iterators for DeclIDs.
typedef std::pair<DeclID *, DeclID *> 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) : Reader(Reader) { }
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::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
ID.AddInteger((TypeID)Key.Data);
break;
case DeclarationName::CXXOperatorName:
ID.AddInteger((OverloadedOperatorKind)Key.Data);
break;
case DeclarationName::CXXUsingDirective:
break;
}
return ID.ComputeHash();
}
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::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
Key.Data = Reader.GetTypeID(Name.getCXXNameType());
break;
case DeclarationName::CXXOperatorName:
Key.Data = Name.getCXXOverloadedOperator();
break;
case DeclarationName::CXXLiteralOperatorName:
Key.Data = (uint64_t)Name.getCXXLiteralIdentifier();
break;
case DeclarationName::CXXUsingDirective:
break;
}
return Key;
}
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d) {
using namespace clang::io;
unsigned KeyLen = ReadUnalignedLE16(d);
unsigned DataLen = ReadUnalignedLE16(d);
return std::make_pair(KeyLen, DataLen);
}
internal_key_type ReadKey(const unsigned char* d, unsigned) {
using namespace clang::io;
DeclNameKey Key;
Key.Kind = (DeclarationName::NameKind)*d++;
switch (Key.Kind) {
case DeclarationName::Identifier:
Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Key.Data =
(uint64_t)Reader.DecodeSelector(ReadUnalignedLE32(d)).getAsOpaquePtr();
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
Key.Data = ReadUnalignedLE32(d); // TypeID
break;
case DeclarationName::CXXOperatorName:
Key.Data = *d++; // OverloadedOperatorKind
break;
case DeclarationName::CXXLiteralOperatorName:
Key.Data = (uint64_t)Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d));
break;
case DeclarationName::CXXUsingDirective:
break;
}
return Key;
}
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);
}
};
} // end anonymous namespace
/// \brief The on-disk hash table used for the DeclContext's Name lookup table.
typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
ASTDeclContextNameLookupTable;
void ASTReader::Error(const char *Msg) {
Diag(diag::err_fe_pch_malformed) << Msg;
}
@ -2825,6 +2967,7 @@ QualType ASTReader::GetType(TypeID ID) {
if (TypesLoaded[Index].isNull()) {
TypesLoaded[Index] = ReadTypeRecord(Index);
TypesLoaded[Index]->setFromAST();
TypeIdxs[TypesLoaded[Index]] = TypeIdx::fromTypeID(ID);
if (DeserializationListener)
DeserializationListener->TypeRead(TypeIdx::fromTypeID(ID),
TypesLoaded[Index]);
@ -2833,6 +2976,27 @@ QualType ASTReader::GetType(TypeID ID) {
return TypesLoaded[Index].withFastQualifiers(FastQuals);
}
TypeID ASTReader::GetTypeID(QualType T) const {
return MakeTypeID(T,
std::bind1st(std::mem_fun(&ASTReader::GetTypeIdx), this));
}
TypeIdx ASTReader::GetTypeIdx(QualType T) const {
if (T.isNull())
return TypeIdx();
assert(!T.getLocalFastQualifiers());
TypeIdxMap::const_iterator I = TypeIdxs.find(T);
// GetTypeIdx is mostly used for computing the hash of DeclarationNames and
// comparing keys of ASTDeclContextNameLookupTable.
// If the type didn't come from the AST file use a specially marked index
// so that any hash/key comparison fail since no such index is stored
// in a AST file.
if (I == TypeIdxs.end())
return TypeIdx(-1);
return I->second;
}
TemplateArgumentLocInfo
ASTReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
llvm::BitstreamCursor &DeclsCursor,

View File

@ -1653,6 +1653,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
// Create and write out the blob that contains selectors and the method pool.
{
OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
ASTMethodPoolTrait Trait(*this);
// Create the on-disk hash table representation. We walk through every
// selector we've seen and look it up in the method pool.
@ -1692,7 +1693,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
// A new method pool entry.
++NumTableEntries;
}
Generator.insert(S, Data);
Generator.insert(S, Data, Trait);
}
// Create the on-disk hash table in a buffer.
@ -1877,6 +1878,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
// strings.
{
OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
ASTIdentifierTableTrait Trait(*this, PP);
// Look for any identifiers that were named while processing the
// headers, but are otherwise not needed. We add these to the hash
@ -1896,7 +1898,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
ID != IDEnd; ++ID) {
assert(ID->first && "NULL identifier in identifier table");
if (!Chain || !ID->first->isFromAST())
Generator.insert(ID->first, ID->second);
Generator.insert(ID->first, ID->second, Trait);
}
// Create the on-disk hash table in a buffer.
@ -1939,6 +1941,127 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
IdentifierOffsets.size() * sizeof(uint32_t));
}
//===----------------------------------------------------------------------===//
// DeclContext's Name Lookup Table Serialization
//===----------------------------------------------------------------------===//
namespace {
// Trait used for the on-disk hash table used in the method pool.
class ASTDeclContextNameLookupTrait {
ASTWriter &Writer;
public:
typedef DeclarationName key_type;
typedef key_type key_type_ref;
typedef DeclContext::lookup_result data_type;
typedef const data_type& data_type_ref;
explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
unsigned ComputeHash(DeclarationName Name) {
llvm::FoldingSetNodeID ID;
ID.AddInteger(Name.getNameKind());
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
ID.AddString(Name.getAsIdentifierInfo()->getName());
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
ID.AddInteger(serialization::ComputeHash(Name.getObjCSelector()));
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
ID.AddInteger(Writer.GetOrCreateTypeID(Name.getCXXNameType()));
break;
case DeclarationName::CXXOperatorName:
ID.AddInteger(Name.getCXXOverloadedOperator());
break;
case DeclarationName::CXXLiteralOperatorName:
ID.AddString(Name.getCXXLiteralIdentifier()->getName());
case DeclarationName::CXXUsingDirective:
break;
}
return ID.ComputeHash();
}
std::pair<unsigned,unsigned>
EmitKeyDataLength(llvm::raw_ostream& Out, DeclarationName Name,
data_type_ref Lookup) {
unsigned KeyLen = 1;
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXLiteralOperatorName:
KeyLen += 4;
break;
case DeclarationName::CXXOperatorName:
KeyLen += 1;
break;
case DeclarationName::CXXUsingDirective:
break;
}
clang::io::Emit16(Out, KeyLen);
// 2 bytes for num of decls and 4 for each DeclID.
unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
clang::io::Emit16(Out, DataLen);
return std::make_pair(KeyLen, DataLen);
}
void EmitKey(llvm::raw_ostream& Out, DeclarationName Name, unsigned) {
using namespace clang::io;
assert(Name.getNameKind() < 0x100 && "Invalid name kind ?");
Emit8(Out, Name.getNameKind());
switch (Name.getNameKind()) {
case DeclarationName::Identifier:
Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo()));
break;
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector()));
break;
case DeclarationName::CXXConstructorName:
case DeclarationName::CXXDestructorName:
case DeclarationName::CXXConversionFunctionName:
Emit32(Out, Writer.getTypeID(Name.getCXXNameType()));
break;
case DeclarationName::CXXOperatorName:
assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?");
Emit8(Out, Name.getCXXOverloadedOperator());
break;
case DeclarationName::CXXLiteralOperatorName:
Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier()));
break;
case DeclarationName::CXXUsingDirective:
break;
}
}
void EmitData(llvm::raw_ostream& Out, key_type_ref,
data_type Lookup, unsigned DataLen) {
uint64_t Start = Out.tell(); (void)Start;
clang::io::Emit16(Out, Lookup.second - Lookup.first);
for (; Lookup.first != Lookup.second; ++Lookup.first)
clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// General Serialization Routines
//===----------------------------------------------------------------------===//
@ -2587,7 +2710,7 @@ TypeID ASTWriter::GetOrCreateTypeID(QualType T) {
std::bind1st(std::mem_fun(&ASTWriter::GetOrCreateTypeIdx), this));
}
TypeID ASTWriter::getTypeID(QualType T) {
TypeID ASTWriter::getTypeID(QualType T) const {
return MakeTypeID(T,
std::bind1st(std::mem_fun(&ASTWriter::getTypeIdx), this));
}
@ -2607,13 +2730,14 @@ TypeIdx ASTWriter::GetOrCreateTypeIdx(QualType T) {
return Idx;
}
TypeIdx ASTWriter::getTypeIdx(QualType T) {
TypeIdx ASTWriter::getTypeIdx(QualType T) const {
if (T.isNull())
return TypeIdx();
assert(!T.getLocalFastQualifiers());
assert(TypeIdxs.find(T) != TypeIdxs.end() && "Type not emitted!");
return TypeIdxs[T];
TypeIdxMap::const_iterator I = TypeIdxs.find(T);
assert(I != TypeIdxs.end() && "Type not emitted!");
return I->second;
}
void ASTWriter::AddDeclRef(const Decl *D, RecordData &Record) {