From: Ted Kremenek Date: Tue, 23 Oct 2007 22:18:37 +0000 (+0000) Subject: Implemented serialization for IdentifierInfo and IdentifierTable. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c637e6b7afeebc6b4f751e4373715b6a8ea77272;p=clang Implemented serialization for IdentifierInfo and IdentifierTable. Updated serialization test code in the driver to test serialization of these types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43266 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Basic/IdentifierTable.cpp b/Basic/IdentifierTable.cpp index 7c2681615f..760dcf4349 100644 --- a/Basic/IdentifierTable.cpp +++ b/Basic/IdentifierTable.cpp @@ -16,6 +16,8 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/Serialization.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -48,6 +50,9 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts) AddKeywords(LangOpts); } +// This cstor is intended to be used only for serialization. +IdentifierTable::IdentifierTable() : HashTable(8192) {} + //===----------------------------------------------------------------------===// // Language Keyword Implementation //===----------------------------------------------------------------------===// @@ -93,7 +98,7 @@ static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, IdentifierTable &Table) { IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); Info.setTokenID(TokenCode); - Info.setIsCPlusplusOperatorKeyword(); + Info.setIsCPlusPlusOperatorKeyword(); } /// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or @@ -372,4 +377,63 @@ SelectorTable::~SelectorTable() { delete static_cast *>(Impl); } +//===----------------------------------------------------------------------===// +// Serialization for IdentifierInfo and IdentifierTable. +//===----------------------------------------------------------------------===// + +void llvm::SerializeTrait::Serialize(llvm::Serializer& S, + const IdentifierInfo& I) { + + S.Emit(I.getTokenID()); + S.EmitInt(I.getBuiltinID(),9); + S.Emit(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::Deserialize(llvm::Deserializer& D, + IdentifierInfo& I) { + tok::TokenKind X; + I.setTokenID(D.Read(X)); + + I.setBuiltinID(D.ReadInt(9)); + + tok::ObjCKeywordKind Y; + I.setObjCKeywordID(D.Read(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::Serialize(llvm::Serializer& S, + const IdentifierTable& T){ + S.Emit(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::Deserialize(llvm::Deserializer& D, + IdentifierTable& T) { + unsigned len = D.ReadInt(); + std::vector 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); + } +} + diff --git a/Basic/TokenKinds.cpp b/Basic/TokenKinds.cpp index 772925b1e5..f1c1e9f678 100644 --- a/Basic/TokenKinds.cpp +++ b/Basic/TokenKinds.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/TokenKinds.h" +#include "llvm/Bitcode/Serialization.h" #include using namespace clang; @@ -26,3 +27,37 @@ const char *tok::getTokenName(enum TokenKind Kind) { assert(Kind < tok::NUM_TOKENS); return TokNames[Kind]; } + +// Serialization traits for TokenKind, PPKeywordKind, and ObjCKeywordKind + +void llvm::SerializeTrait::Serialize(llvm::Serializer& S, + tok::TokenKind X) { + S.EmitEnum(X,0,tok::NUM_TOKENS-1); +} + +void llvm::SerializeTrait::Deserialize(llvm::Deserializer& D, + tok::TokenKind& X) { + X = D.ReadEnum(0,tok::NUM_TOKENS-1); +} + +void llvm::SerializeTrait::Serialize(llvm::Serializer& S, + tok::PPKeywordKind X) { + S.EmitEnum(X,0,tok::NUM_PP_KEYWORDS-1); +} + +void llvm::SerializeTrait::Deserialize(llvm::Deserializer& D, + tok::PPKeywordKind& X) { + X = D.ReadEnum(0,tok::NUM_PP_KEYWORDS-1); +} + +void +llvm::SerializeTrait::Serialize(llvm::Serializer& S, + tok::ObjCKeywordKind X) { + S.EmitEnum(X,0,tok::NUM_OBJC_KEYWORDS-1); +} + +void +llvm::SerializeTrait::Deserialize(llvm::Deserializer& D, + tok::ObjCKeywordKind& X) { + X = D.ReadEnum(0,tok::NUM_OBJC_KEYWORDS-1); +} \ No newline at end of file diff --git a/Driver/Makefile b/Driver/Makefile index 86c6143412..6d2cfe0a75 100644 --- a/Driver/Makefile +++ b/Driver/Makefile @@ -5,6 +5,7 @@ CXXFLAGS = -fno-rtti TOOLNAME = clang USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSEMA.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 diff --git a/Driver/SerializationTest.cpp b/Driver/SerializationTest.cpp index 1901591420..811dddbb74 100644 --- a/Driver/SerializationTest.cpp +++ b/Driver/SerializationTest.cpp @@ -19,226 +19,148 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "llvm/System/Path.h" -#include "llvm/Bitcode/BitstreamWriter.h" -#include -#include +#include "llvm/Support/Streams.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Bitcode/Serialization.h" +#include + +//===----------------------------------------------------------------------===// +// Driver code. +//===----------------------------------------------------------------------===// using namespace clang; -using llvm::BitstreamWriter; -using std::cerr; -using std::cout; -using std::endl; -using std::flush; -namespace llvm { -template struct IntrospectionTrait { - struct Flags { - enum { isPod = false, UniqueInstances = false, UniqueRefs = false }; - }; - - template - struct Ops { - static inline void Introspect(T& X, Introspector& I) { - assert (false && "Introspect not implemented."); - } +namespace { + template + struct Janitor { + T* Obj; + Janitor(T* obj) : Obj(obj) {} + ~Janitor() { delete Obj; } }; -}; -} +} // end anonymous namespace namespace { -class SerializationTest : public ASTConsumer { - IdentifierTable* IdTable; - unsigned MainFileID; -public: - void Initialize(ASTContext& Context, unsigned mainFileID) { - IdTable = &Context.Idents; - MainFileID = mainFileID; - RunSerializationTest(); - } - - void RunSerializationTest(); - bool WriteAll(llvm::sys::Path& Filename); - - virtual void HandleTopLevelDecl(Decl *D) {} -}; - -class Writer { - std::vector Buffer; - BitstreamWriter Stream; - std::ostream& Out; -public: - - enum { IdentifierTableBID = 0x8 }; - - Writer(std::ostream& out) : Stream(Buffer), Out(out) { - Buffer.reserve(256*1024); + class SerializationTest : public ASTConsumer { + IdentifierTable* IdTable; + unsigned MainFileID; + public: + void Initialize(ASTContext& Context, unsigned mainFileID) { + IdTable = &Context.Idents; + MainFileID = mainFileID; + } - // Emit the file header. - 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); - } - - ~Writer() { - Out.write((char*)&Buffer.front(), Buffer.size()); - Out.flush(); - } - - template inline void operator()(T& x) { - llvm::IntrospectionTrait::template Ops::Introspect(x,*this); - } + ~SerializationTest() { + RunSerializationTest(); + } - template inline void operator()(T& x, unsigned bits) { - llvm::IntrospectionTrait::template Ops::Introspect(x,bits,*this); - } - - template inline void operator()(const T& x) { - operator()(const_cast(x)); - } - - template inline void operator()(const T& x, unsigned bits) { - operator()(const_cast(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 inline void EnterSubblock(unsigned CodeLen) { - Stream.EnterSubblock(8,CodeLen); - } - - inline void ExitBlock() { Stream.ExitBlock(); } - -}; - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// External Interface. -//===----------------------------------------------------------------------===// + void RunSerializationTest(); + bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T); + IdentifierTable* ReadTable(llvm::sys::Path& Filename); + + virtual void HandleTopLevelDecl(Decl *D) {} + }; +} // end anonymous namespace ASTConsumer* clang::CreateSerializationTest() { return new SerializationTest(); } - -//===----------------------------------------------------------------------===// -// Serialization "Driver" code. -//===----------------------------------------------------------------------===// void SerializationTest::RunSerializationTest() { std::string ErrMsg; llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); - + if (Filename.isEmpty()) { - cerr << "Error: " << ErrMsg << "\n"; + llvm::cerr << "Error: " << ErrMsg << "\n"; return; } - Filename.appendComponent("test.cfe_bc"); + Filename.appendComponent("test.ast"); if (Filename.makeUnique(true,&ErrMsg)) { - cerr << "Error: " << ErrMsg << "\n"; + llvm::cerr << "Error: " << ErrMsg << "\n"; return; } - if (!WriteAll(Filename)) - return; - - cout << "Wrote file: " << Filename.c_str() << "\n"; + llvm::cerr << "Writing out Identifier table\n"; + WriteTable(Filename,IdTable); + llvm::cerr << "Reading in Identifier Table\n"; + IdentifierTable* T = ReadTable(Filename); + Janitor 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 wilco(ReadTable(Filename)); } -bool SerializationTest::WriteAll(llvm::sys::Path& Filename) { - std::ofstream Out(Filename.c_str()); +bool SerializationTest::WriteTable(llvm::sys::Path& Filename, + IdentifierTable* T) { + if (!T) + return false; - if (!Out) { - cerr << "Error: Cannot open " << Filename.c_str() << "\n"; + std::vector Buffer; + 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; } - - Writer W(Out); - W(*IdTable); - - W.getStream().FlushToWord(); + + llvm::cerr << "Wrote file: " << Filename.c_str() << "\n"; return true; } -//===----------------------------------------------------------------------===// -// Serialization Methods. -//===----------------------------------------------------------------------===// - -namespace llvm { -struct IntrospectionPrimitivesFlags { - enum { isPod = true, UniqueInstances = false, UniqueRefs = false }; -}; +IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) { + llvm::MemoryBuffer* Buffer = + llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str())); - -template<> struct -IntrospectionTrait::Flags : public IntrospectionPrimitivesFlags {}; + if(!Buffer) { + llvm::cerr << "Error reading file\n"; + return NULL; + } -template<> struct -IntrospectionTrait::Flags : public IntrospectionPrimitivesFlags {}; - -template<> struct -IntrospectionTrait::Flags : public IntrospectionPrimitivesFlags {}; - - - -template<> -struct IntrospectionTrait { - - 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 - 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::Ops { - static void Introspect(clang::IdentifierTable& X, Writer& W) { - W.EnterSubblock(1); -/* - for (clang::IdentifierTable::iterator I = X.begin(), E = X.end(); - I != E; ++I) - W(I->getValue()); - */ - W.ExitBlock(); + Janitor AutoReleaseBuffer(Buffer); + + if (Buffer->getBufferSize() & 0x3) { + llvm::cerr << "AST file should be a multiple of 4 bytes in length\n"; + return NULL; } -}; - - + 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(); +} diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index e94d50519f..3e21344802 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -23,8 +23,10 @@ namespace llvm { - template struct IntrospectionTrait; template struct DenseMapInfo; + template struct SerializeTrait; + class Serializer; + class Deserializer; } namespace clang { @@ -129,7 +131,7 @@ public: /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether /// this identifier is a C++ alternate representation of an operator. - void setIsCPlusplusOperatorKeyword(bool Val = true) + void setIsCPlusPlusOperatorKeyword(bool Val = true) { IsCPPOperatorKeyword = Val; } bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } @@ -138,13 +140,6 @@ public: template T *getFETokenInfo() const { return static_cast(FETokenInfo); } void setFETokenInfo(void *T) { FETokenInfo = T; } - - // For serialization and profiling. -#if defined(_MSC_VER) && _MSC_VER <= 1400 // workaround for VC++ upto V8.0 - template friend class /*llvm::*/IntrospectionTrait; -#else - template friend class llvm::IntrospectionTrait; -#endif }; /// IdentifierTable - This table implements an efficient mapping from strings to @@ -182,18 +177,20 @@ public: iterator begin() const { return HashTable.begin(); } iterator end() const { return HashTable.end(); } + unsigned size() const { return HashTable.size(); } + /// PrintStats - Print some statistics to stderr that indicate how well the /// hashing is doing. void PrintStats() const; - // For serialization and profiling. -#if defined(_MSC_VER) && _MSC_VER <= 1400 // workaround for VC++ upto V8.0 - template friend class /*llvm::*/IntrospectionTrait; -#else - template friend class llvm::IntrospectionTrait; -#endif -private: 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; }; /// Selector - This smart pointer class efficiently represents Objective-C @@ -311,6 +308,27 @@ struct DenseMapInfo { static bool isPod() { return true; } }; +/// Define SerializeTrait to enable serialization for IdentifierInfos. +template <> +struct SerializeTrait { + 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 { + 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 #endif diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h index e51f0c7f8a..2e213bddf1 100644 --- a/include/clang/Basic/TokenKinds.h +++ b/include/clang/Basic/TokenKinds.h @@ -48,4 +48,33 @@ const char *getTokenName(enum TokenKind Kind); } // end namespace tok } // end namespace clang +//===----------------------------------------------------------------------===// +// Serialization traits. +//===----------------------------------------------------------------------===// + +namespace llvm { + template struct SerializeTrait; + class Serializer; + class Deserializer; + +template<> +struct SerializeTrait { + static void Serialize(llvm::Serializer& S, clang::tok::TokenKind X); + static void Deserialize(llvm::Deserializer& D, clang::tok::TokenKind& X); +}; + +template<> +struct SerializeTrait { + static void Serialize(llvm::Serializer& S, clang::tok::PPKeywordKind X); + static void Deserialize(llvm::Deserializer& D, clang::tok::PPKeywordKind& X); +}; + +template<> +struct SerializeTrait { + static void Serialize(llvm::Serializer& S, clang::tok::ObjCKeywordKind X); + static void Deserialize(llvm::Deserializer& D, clang::tok::ObjCKeywordKind& X); +}; + +} // end namespace llvm + #endif