Skip to content
Snippets Groups Projects
Commit f25f4a3d authored by Ted Kremenek's avatar Ted Kremenek
Browse files

Implemented serialization for IdentifierInfo and IdentifierTable.

Updated serialization test code in the driver to test serialization of
these types.

llvm-svn: 43266
parent 97e3be79
No related branches found
No related tags found
No related merge requests found
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "clang/Basic/LangOptions.h" #include "clang/Basic/LangOptions.h"
#include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/Bitcode/Serialization.h"
using namespace clang; using namespace clang;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
...@@ -48,6 +50,9 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts) ...@@ -48,6 +50,9 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts)
AddKeywords(LangOpts); AddKeywords(LangOpts);
} }
// This cstor is intended to be used only for serialization.
IdentifierTable::IdentifierTable() : HashTable(8192) {}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Language Keyword Implementation // Language Keyword Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
...@@ -93,7 +98,7 @@ static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, ...@@ -93,7 +98,7 @@ static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen,
IdentifierTable &Table) { IdentifierTable &Table) {
IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen);
Info.setTokenID(TokenCode); Info.setTokenID(TokenCode);
Info.setIsCPlusplusOperatorKeyword(); Info.setIsCPlusPlusOperatorKeyword();
} }
/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or /// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or
...@@ -372,4 +377,63 @@ SelectorTable::~SelectorTable() { ...@@ -372,4 +377,63 @@ SelectorTable::~SelectorTable() {
delete static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl); delete static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
} }
//===----------------------------------------------------------------------===//
// Serialization for IdentifierInfo and IdentifierTable.
//===----------------------------------------------------------------------===//
void llvm::SerializeTrait<IdentifierInfo>::Serialize(llvm::Serializer& S,
const IdentifierInfo& I) {
S.Emit<tok::TokenKind>(I.getTokenID());
S.EmitInt(I.getBuiltinID(),9);
S.Emit<tok::ObjCKeywordKind>(I.getObjCKeywordID());
S.Emit(I.hasMacroDefinition());
S.Emit(I.isExtensionToken());
S.Emit(I.isPoisoned());
S.Emit(I.isOtherTargetMacro());
S.Emit(I.isCPlusPlusOperatorKeyword());
S.Emit(I.isNonPortableBuiltin());
}
void llvm::SerializeTrait<IdentifierInfo>::Deserialize(llvm::Deserializer& D,
IdentifierInfo& I) {
tok::TokenKind X;
I.setTokenID(D.Read<tok::TokenKind>(X));
I.setBuiltinID(D.ReadInt(9));
tok::ObjCKeywordKind Y;
I.setObjCKeywordID(D.Read<tok::ObjCKeywordKind>(Y));
I.setHasMacroDefinition(D.ReadBool());
I.setIsExtensionToken(D.ReadBool());
I.setIsPoisoned(D.ReadBool());
I.setIsOtherTargetMacro(D.ReadBool());
I.setIsCPlusPlusOperatorKeyword(D.ReadBool());
I.setNonPortableBuiltin(D.ReadBool());
}
void llvm::SerializeTrait<IdentifierTable>::Serialize(llvm::Serializer& S,
const IdentifierTable& T){
S.Emit<unsigned>(T.size());
for (clang::IdentifierTable::iterator I=T.begin(), E=T.end(); I != E; ++I) {
S.EmitCString(I->getKeyData());
S.Emit(I->getValue());
}
}
void llvm::SerializeTrait<IdentifierTable>::Deserialize(llvm::Deserializer& D,
IdentifierTable& T) {
unsigned len = D.ReadInt();
std::vector<char> buff;
buff.reserve(200);
for (unsigned i = 0; i < len; ++i) {
D.ReadCString(buff);
IdentifierInfo& Info = T.get(&buff[0],&buff[0]+buff.size());
D.Read(Info);
}
}
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "clang/Basic/TokenKinds.h" #include "clang/Basic/TokenKinds.h"
#include "llvm/Bitcode/Serialization.h"
#include <cassert> #include <cassert>
using namespace clang; using namespace clang;
...@@ -26,3 +27,37 @@ const char *tok::getTokenName(enum TokenKind Kind) { ...@@ -26,3 +27,37 @@ const char *tok::getTokenName(enum TokenKind Kind) {
assert(Kind < tok::NUM_TOKENS); assert(Kind < tok::NUM_TOKENS);
return TokNames[Kind]; return TokNames[Kind];
} }
// Serialization traits for TokenKind, PPKeywordKind, and ObjCKeywordKind
void llvm::SerializeTrait<tok::TokenKind>::Serialize(llvm::Serializer& S,
tok::TokenKind X) {
S.EmitEnum(X,0,tok::NUM_TOKENS-1);
}
void llvm::SerializeTrait<tok::TokenKind>::Deserialize(llvm::Deserializer& D,
tok::TokenKind& X) {
X = D.ReadEnum<tok::TokenKind>(0,tok::NUM_TOKENS-1);
}
void llvm::SerializeTrait<tok::PPKeywordKind>::Serialize(llvm::Serializer& S,
tok::PPKeywordKind X) {
S.EmitEnum(X,0,tok::NUM_PP_KEYWORDS-1);
}
void llvm::SerializeTrait<tok::PPKeywordKind>::Deserialize(llvm::Deserializer& D,
tok::PPKeywordKind& X) {
X = D.ReadEnum<tok::PPKeywordKind>(0,tok::NUM_PP_KEYWORDS-1);
}
void
llvm::SerializeTrait<tok::ObjCKeywordKind>::Serialize(llvm::Serializer& S,
tok::ObjCKeywordKind X) {
S.EmitEnum(X,0,tok::NUM_OBJC_KEYWORDS-1);
}
void
llvm::SerializeTrait<tok::ObjCKeywordKind>::Deserialize(llvm::Deserializer& D,
tok::ObjCKeywordKind& X) {
X = D.ReadEnum<tok::ObjCKeywordKind>(0,tok::NUM_OBJC_KEYWORDS-1);
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ CXXFLAGS = -fno-rtti ...@@ -5,6 +5,7 @@ CXXFLAGS = -fno-rtti
TOOLNAME = clang TOOLNAME = clang
USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \ USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.a \
clangAST.a clangParse.a clangLex.a clangBasic.a \ clangAST.a clangParse.a clangLex.a clangBasic.a \
LLVMCore.a LLVMSupport.a LLVMSystem.a LLVMCore.a LLVMSupport.a LLVMSystem.a \
LLVMBitWriter.a LLVMBitReader.a
include $(LEVEL)/Makefile.common include $(LEVEL)/Makefile.common
...@@ -19,226 +19,148 @@ ...@@ -19,226 +19,148 @@
#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "llvm/System/Path.h" #include "llvm/System/Path.h"
#include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/Streams.h"
#include <fstream> #include "llvm/Support/MemoryBuffer.h"
#include <iostream> #include "llvm/Bitcode/Serialization.h"
#include <stdio.h>
//===----------------------------------------------------------------------===//
// Driver code.
//===----------------------------------------------------------------------===//
using namespace clang; using namespace clang;
using llvm::BitstreamWriter;
using std::cerr;
using std::cout;
using std::endl;
using std::flush;
namespace llvm { namespace {
template<typename T> struct IntrospectionTrait { template<typename T>
struct Flags { struct Janitor {
enum { isPod = false, UniqueInstances = false, UniqueRefs = false }; T* Obj;
}; Janitor(T* obj) : Obj(obj) {}
~Janitor() { delete Obj; }
template<typename Introspector>
struct Ops {
static inline void Introspect(T& X, Introspector& I) {
assert (false && "Introspect not implemented.");
}
}; };
}; } // end anonymous namespace
}
namespace { namespace {
class SerializationTest : public ASTConsumer { class SerializationTest : public ASTConsumer {
IdentifierTable* IdTable; IdentifierTable* IdTable;
unsigned MainFileID; unsigned MainFileID;
public: public:
void Initialize(ASTContext& Context, unsigned mainFileID) { void Initialize(ASTContext& Context, unsigned mainFileID) {
IdTable = &Context.Idents; IdTable = &Context.Idents;
MainFileID = mainFileID; MainFileID = mainFileID;
RunSerializationTest(); }
}
void RunSerializationTest();
bool WriteAll(llvm::sys::Path& Filename);
virtual void HandleTopLevelDecl(Decl *D) {}
};
class Writer {
std::vector<unsigned char> Buffer;
BitstreamWriter Stream;
std::ostream& Out;
public:
enum { IdentifierTableBID = 0x8 };
Writer(std::ostream& out) : Stream(Buffer), Out(out) {
Buffer.reserve(256*1024);
// Emit the file header. ~SerializationTest() {
Stream.Emit((unsigned)'B', 8); RunSerializationTest();
Stream.Emit((unsigned)'C', 8); }
Stream.Emit(0xC, 4);
Stream.Emit(0xF, 4);
Stream.Emit(0xE, 4);
Stream.Emit(0x0, 4);
}
~Writer() {
Out.write((char*)&Buffer.front(), Buffer.size());
Out.flush();
}
template <typename T> inline void operator()(T& x) {
llvm::IntrospectionTrait<T>::template Ops<Writer>::Introspect(x,*this);
}
template <typename T> inline void operator()(T& x, unsigned bits) { void RunSerializationTest();
llvm::IntrospectionTrait<T>::template Ops<Writer>::Introspect(x,bits,*this); bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T);
} IdentifierTable* ReadTable(llvm::sys::Path& Filename);
template <typename T> inline void operator()(const T& x) { virtual void HandleTopLevelDecl(Decl *D) {}
operator()(const_cast<T&>(x)); };
} } // end anonymous namespace
template <typename T> inline void operator()(const T& x, unsigned bits) {
operator()(const_cast<T&>(x),bits);
}
inline void operator()(bool X) { Stream.Emit(X,1); }
inline void operator()(unsigned X) { Stream.Emit(X,32); }
inline void operator()(unsigned X, unsigned bits, bool VBR=false) {
if (VBR) Stream.Emit(X,bits);
else Stream.Emit(X,bits);
}
inline BitstreamWriter& getStream() {
return Stream;
}
template <typename T> inline void EnterSubblock(unsigned CodeLen) {
Stream.EnterSubblock(8,CodeLen);
}
inline void ExitBlock() { Stream.ExitBlock(); }
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// External Interface.
//===----------------------------------------------------------------------===//
ASTConsumer* clang::CreateSerializationTest() { ASTConsumer* clang::CreateSerializationTest() {
return new SerializationTest(); return new SerializationTest();
} }
//===----------------------------------------------------------------------===//
// Serialization "Driver" code.
//===----------------------------------------------------------------------===//
void SerializationTest::RunSerializationTest() { void SerializationTest::RunSerializationTest() {
std::string ErrMsg; std::string ErrMsg;
llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
if (Filename.isEmpty()) { if (Filename.isEmpty()) {
cerr << "Error: " << ErrMsg << "\n"; llvm::cerr << "Error: " << ErrMsg << "\n";
return; return;
} }
Filename.appendComponent("test.cfe_bc"); Filename.appendComponent("test.ast");
if (Filename.makeUnique(true,&ErrMsg)) { if (Filename.makeUnique(true,&ErrMsg)) {
cerr << "Error: " << ErrMsg << "\n"; llvm::cerr << "Error: " << ErrMsg << "\n";
return; return;
} }
if (!WriteAll(Filename)) llvm::cerr << "Writing out Identifier table\n";
return; WriteTable(Filename,IdTable);
llvm::cerr << "Reading in Identifier Table\n";
cout << "Wrote file: " << Filename.c_str() << "\n"; IdentifierTable* T = ReadTable(Filename);
Janitor<IdentifierTable> roger(T);
Filename.appendSuffix("2");
llvm::cerr << "Writing out Identifier table (2)\n";
WriteTable(Filename,T);
llvm::cerr << "Reading in Identifier Table (2)\n";
Janitor<IdentifierTable> wilco(ReadTable(Filename));
} }
bool SerializationTest::WriteAll(llvm::sys::Path& Filename) { bool SerializationTest::WriteTable(llvm::sys::Path& Filename,
std::ofstream Out(Filename.c_str()); IdentifierTable* T) {
if (!T)
return false;
if (!Out) { std::vector<unsigned char> Buffer;
cerr << "Error: Cannot open " << Filename.c_str() << "\n"; Buffer.reserve(256*1024);
llvm::BitstreamWriter Stream(Buffer);
Stream.Emit((unsigned)'B', 8);
Stream.Emit((unsigned)'C', 8);
Stream.Emit(0xC, 4);
Stream.Emit(0xF, 4);
Stream.Emit(0xE, 4);
Stream.Emit(0x0, 4);
llvm::Serializer S(Stream);
S.Emit(*T);
S.Flush();
if (FILE *fp = fopen(Filename.c_str(),"wb")) {
fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
fclose(fp);
}
else {
llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
return false; return false;
} }
Writer W(Out); llvm::cerr << "Wrote file: " << Filename.c_str() << "\n";
W(*IdTable);
W.getStream().FlushToWord();
return true; return true;
} }
//===----------------------------------------------------------------------===//
// Serialization Methods.
//===----------------------------------------------------------------------===//
namespace llvm {
struct IntrospectionPrimitivesFlags { IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) {
enum { isPod = true, UniqueInstances = false, UniqueRefs = false }; llvm::MemoryBuffer* Buffer =
}; llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str()));
if(!Buffer) {
template<> struct llvm::cerr << "Error reading file\n";
IntrospectionTrait<bool>::Flags : public IntrospectionPrimitivesFlags {}; return NULL;
}
template<> struct Janitor<llvm::MemoryBuffer> AutoReleaseBuffer(Buffer);
IntrospectionTrait<unsigned>::Flags : public IntrospectionPrimitivesFlags {};
if (Buffer->getBufferSize() & 0x3) {
template<> struct llvm::cerr << "AST file should be a multiple of 4 bytes in length\n";
IntrospectionTrait<short>::Flags : public IntrospectionPrimitivesFlags {}; return NULL;
template<>
struct IntrospectionTrait<clang::IdentifierInfo> {
struct Flags {
enum { isPod = false, // Cannot copy via memcpy. Must use copy-ctor.
hasUniqueInstances = true, // Two pointers with different
// addreses point to objects
// that are not equal to each other.
hasUniqueReferences = true // Two (non-temporary) pointers
// will point to distinct instances.
};
};
template<typename Introspector>
struct Ops {
static void Introspect(clang::IdentifierInfo& X, Introspector& I) {
// I(X.getTokenID());
I(X.getBuiltinID(),9); // FIXME: do 9 bit specialization.
// I(X.getObjCKeywordID());
I(X.hasMacroDefinition());
I(X.isExtensionToken());
I(X.isPoisoned());
I(X.isOtherTargetMacro());
I(X.isCPlusPlusOperatorKeyword());
I(X.isNonPortableBuiltin());
}
};
};
template<> template<>
struct IntrospectionTrait<clang::IdentifierTable>::Ops<Writer> {
static void Introspect(clang::IdentifierTable& X, Writer& W) {
W.EnterSubblock<clang::IdentifierTable>(1);
/*
for (clang::IdentifierTable::iterator I = X.begin(), E = X.end();
I != E; ++I)
W(I->getValue());
*/
W.ExitBlock();
} }
};
unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
llvm::BitstreamReader Stream(BufPtr,BufPtr+Buffer->getBufferSize());
// Sniff for the signature.
if (Stream.Read(8) != 'B' ||
Stream.Read(8) != 'C' ||
Stream.Read(4) != 0xC ||
Stream.Read(4) != 0xF ||
Stream.Read(4) != 0xE ||
Stream.Read(4) != 0x0) {
llvm::cerr << "Invalid AST-bitcode signature\n";
return NULL;
}
} // end namespace llvm llvm::Deserializer D(Stream);
llvm::cerr << "Materializing identifier table.\n";
return D.Materialize<IdentifierTable>();
}
...@@ -23,8 +23,10 @@ ...@@ -23,8 +23,10 @@
namespace llvm { namespace llvm {
template <typename T> struct IntrospectionTrait;
template <typename T> struct DenseMapInfo; template <typename T> struct DenseMapInfo;
template <typename T> struct SerializeTrait;
class Serializer;
class Deserializer;
} }
namespace clang { namespace clang {
...@@ -129,7 +131,7 @@ public: ...@@ -129,7 +131,7 @@ public:
/// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether
/// this identifier is a C++ alternate representation of an operator. /// this identifier is a C++ alternate representation of an operator.
void setIsCPlusplusOperatorKeyword(bool Val = true) void setIsCPlusPlusOperatorKeyword(bool Val = true)
{ IsCPPOperatorKeyword = Val; } { IsCPPOperatorKeyword = Val; }
bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
...@@ -138,13 +140,6 @@ public: ...@@ -138,13 +140,6 @@ public:
template<typename T> template<typename T>
T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); } T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }
void setFETokenInfo(void *T) { FETokenInfo = T; } void setFETokenInfo(void *T) { FETokenInfo = T; }
// For serialization and profiling.
#if defined(_MSC_VER) && _MSC_VER <= 1400 // workaround for VC++ upto V8.0
template<typename T> friend class /*llvm::*/IntrospectionTrait;
#else
template<typename T> friend class llvm::IntrospectionTrait;
#endif
}; };
/// IdentifierTable - This table implements an efficient mapping from strings to /// IdentifierTable - This table implements an efficient mapping from strings to
...@@ -182,18 +177,20 @@ public: ...@@ -182,18 +177,20 @@ public:
iterator begin() const { return HashTable.begin(); } iterator begin() const { return HashTable.begin(); }
iterator end() const { return HashTable.end(); } iterator end() const { return HashTable.end(); }
unsigned size() const { return HashTable.size(); }
/// PrintStats - Print some statistics to stderr that indicate how well the /// PrintStats - Print some statistics to stderr that indicate how well the
/// hashing is doing. /// hashing is doing.
void PrintStats() const; void PrintStats() const;
// For serialization and profiling.
#if defined(_MSC_VER) && _MSC_VER <= 1400 // workaround for VC++ upto V8.0
template<typename T> friend class /*llvm::*/IntrospectionTrait;
#else
template<typename T> friend class llvm::IntrospectionTrait;
#endif
private:
void AddKeywords(const LangOptions &LangOpts); void AddKeywords(const LangOptions &LangOpts);
private:
/// This ctor is not intended to be used by anyone except for object
/// serialization.
IdentifierTable();
friend class llvm::SerializeTrait<IdentifierTable>;
}; };
/// Selector - This smart pointer class efficiently represents Objective-C /// Selector - This smart pointer class efficiently represents Objective-C
...@@ -311,6 +308,27 @@ struct DenseMapInfo<clang::Selector> { ...@@ -311,6 +308,27 @@ struct DenseMapInfo<clang::Selector> {
static bool isPod() { return true; } static bool isPod() { return true; }
}; };
/// Define SerializeTrait to enable serialization for IdentifierInfos.
template <>
struct SerializeTrait<clang::IdentifierInfo> {
static void Serialize(llvm::Serializer& S, const clang::IdentifierInfo& I);
static void Deserialize(llvm::Deserializer& S, clang::IdentifierInfo& I);
};
/// Define SerializeTrait to enable serialization for IdentifierTables.
template <>
struct SerializeTrait<clang::IdentifierTable> {
static void Serialize(llvm::Serializer& S, const clang::IdentifierTable& X);
static void Deserialize(llvm::Deserializer& S, clang::IdentifierTable& X);
private:
static inline clang::IdentifierTable* Instantiate() {
return new clang::IdentifierTable();
}
friend class Deserializer;
};
} // end namespace llvm } // end namespace llvm
#endif #endif
...@@ -48,4 +48,33 @@ const char *getTokenName(enum TokenKind Kind); ...@@ -48,4 +48,33 @@ const char *getTokenName(enum TokenKind Kind);
} // end namespace tok } // end namespace tok
} // end namespace clang } // end namespace clang
//===----------------------------------------------------------------------===//
// Serialization traits.
//===----------------------------------------------------------------------===//
namespace llvm {
template <typename T> struct SerializeTrait;
class Serializer;
class Deserializer;
template<>
struct SerializeTrait<clang::tok::TokenKind> {
static void Serialize(llvm::Serializer& S, clang::tok::TokenKind X);
static void Deserialize(llvm::Deserializer& D, clang::tok::TokenKind& X);
};
template<>
struct SerializeTrait<clang::tok::PPKeywordKind> {
static void Serialize(llvm::Serializer& S, clang::tok::PPKeywordKind X);
static void Deserialize(llvm::Deserializer& D, clang::tok::PPKeywordKind& X);
};
template<>
struct SerializeTrait<clang::tok::ObjCKeywordKind> {
static void Serialize(llvm::Serializer& S, clang::tok::ObjCKeywordKind X);
static void Deserialize(llvm::Deserializer& D, clang::tok::ObjCKeywordKind& X);
};
} // end namespace llvm
#endif #endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment