From: Ted Kremenek Date: Wed, 5 Dec 2007 21:36:08 +0000 (+0000) Subject: Added "TranslationUnit" class that will be used to provide an interface X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2f74359d4de9bf0eec7b6cb93ca04621997787d7;p=clang Added "TranslationUnit" class that will be used to provide an interface for serializing/deserializing ASTs that is decoupled from the logic in SerializationTest (which will soon be rewritten to use this interface). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44631 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/TranslationUnit.cpp b/Driver/TranslationUnit.cpp new file mode 100644 index 0000000000..627657aa92 --- /dev/null +++ b/Driver/TranslationUnit.cpp @@ -0,0 +1,229 @@ +//===--- TranslationUnit.cpp - Abstraccction for Translation Units --------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +// FIXME: This should eventually be moved out of the driver, or replaced +// with its eventual successor. +// +//===----------------------------------------------------------------------===// + +#include "TranslationUnit.h" +#include "clang.h" + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/AST.h" + +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/scoped_ptr.h" + +#include + +namespace { + enum { BasicMetadataBlock = 1, + ASTContextBlock = 2, + DeclsBlock = 3 }; +} + +using namespace clang; + +bool TranslationUnit::EmitBitcodeFile(llvm::sys::Path& Filename) const { + + // Reserve 256K for bitstream buffer. + std::vector Buffer; + Buffer.reserve(256*1024); + + // Create bitstream. + llvm::BitstreamWriter Stream(Buffer); + + // Emit the preamble. + 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); + + { + // Create serializer. Placing it in its own scope assures any necessary + // finalization of bits to the buffer in the serializer's dstor. + llvm::Serializer Sezr(Stream); + + // Emit the translation unit. + Emit(Sezr); + } + + // Write the bits to disk. + if (FILE* fp = fopen(Filename.c_str(),"wb")) { + fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp); + fclose(fp); + return true; + } + + return false; +} + +void TranslationUnit::Emit(llvm::Serializer& Sezr) const { + + // ===---------------------------------------------------===/ + // Serialize the top-level decls. + // ===---------------------------------------------------===/ + + Sezr.EnterBlock(DeclsBlock); + + // Only serialize the head of a decl chain. The ASTConsumer interfaces + // provides us with each top-level decl, including those nested in + // a decl chain, so we may be passed decls that are already serialized. + for (const_iterator I=begin(), E=end(); I!=E; ++I) + if (!Sezr.isRegistered(*I)) + Sezr.EmitOwnedPtr(*I); + + Sezr.ExitBlock(); + + // ===---------------------------------------------------===/ + // Serialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Emit ASTContext. + Sezr.EnterBlock(ASTContextBlock); + Sezr.EmitOwnedPtr(Context); + Sezr.ExitBlock(); + + Sezr.EnterBlock(BasicMetadataBlock); + + // Block for SourceManager, LangOptions, and Target. Allows easy skipping + // around to the block for the Selectors during deserialization. + Sezr.EnterBlock(); + + // Emit the SourceManager. + Sezr.Emit(Context->SourceMgr); + + // Emit the LangOptions. + Sezr.Emit(LangOpts); + + // Emit the Target. + Sezr.EmitPtr(&Context->Target); + Sezr.EmitCStr(Context->Target.getTargetTriple()); + + Sezr.ExitBlock(); // exit "BasicMetadataBlock" + + // Emit the Selectors. + Sezr.Emit(Context->Selectors); + + // Emit the Identifier Table. + Sezr.Emit(Context->Idents); + + Sezr.ExitBlock(); // exit "ASTContextBlock" +} + +TranslationUnit* TranslationUnit::ReadBitcodeFile(llvm::sys::Path& Filename, + FileManager& FMgr) { + + // Create the memory buffer that contains the contents of the file. + llvm::scoped_ptr + MBuffer(llvm::MemoryBuffer::getFile(Filename.c_str(), + strlen(Filename.c_str()))); + + if (!MBuffer) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Check if the file is of the proper length. + if (MBuffer->getBufferSize() & 0x3) { + // FIXME: Provide diagnostic: "Length should be a multiple of 4 bytes." + return NULL; + } + + // Create the bitstream reader. + unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart(); + llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize()); + + 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) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Create the deserializer. + llvm::Deserializer Dezr(Stream); + + return Create(Dezr,FMgr); +} + +TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr, + FileManager& FMgr) { + + // Create the translation unit object. + TranslationUnit* TU = new TranslationUnit(); + + // ===---------------------------------------------------===/ + // Deserialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock + // (which will appear earlier) and record its location. + + bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock); + assert (FoundBlock); + + llvm::Deserializer::Location ASTContextBlockLoc = + Dezr.getCurrentBlockLocation(); + + FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock); + assert (FoundBlock); + + // Read the SourceManager. + SourceManager::CreateAndRegister(Dezr,FMgr); + + // Read the LangOptions. + TU->LangOpts.Read(Dezr); + + { + // Read the TargetInfo. + llvm::SerializedPtrID PtrID = Dezr.ReadPtrID(); + char* triple = Dezr.ReadCStr(NULL,0,true); + std::vector triples; + triples.push_back(triple); + delete [] triple; + Dezr.RegisterPtr(PtrID,CreateTargetInfo(triples,NULL)); + } + + // For Selectors, we must read the identifier table first because the + // SelectorTable depends on the identifiers being already deserialized. + llvm::Deserializer::Location SelectorBlkLoc = Dezr.getCurrentBlockLocation(); + Dezr.SkipBlock(); + + // Read the identifier table. + IdentifierTable::CreateAndRegister(Dezr); + + // Now jump back and read the selectors. + Dezr.JumpTo(SelectorBlkLoc); + SelectorTable::CreateAndRegister(Dezr); + + // Now jump back to ASTContextBlock and read the ASTContext. + Dezr.JumpTo(ASTContextBlockLoc); + TU->Context = Dezr.ReadOwnedPtr(); + + // "Rewind" the stream. Find the block with the serialized top-level decls. + Dezr.Rewind(); + FoundBlock = Dezr.SkipToBlock(DeclsBlock); + assert (FoundBlock); + llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation(); + + while (!Dezr.FinishedBlock(DeclBlockLoc)) + TU->AddTopLevelDecl(Dezr.ReadOwnedPtr()); + + return TU; +} + diff --git a/Driver/TranslationUnit.h b/Driver/TranslationUnit.h new file mode 100644 index 0000000000..a86f47ddcc --- /dev/null +++ b/Driver/TranslationUnit.h @@ -0,0 +1,75 @@ +//===--- TranslationUnit.h - Abstraction for Translation Units -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Ted Kremenek and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +// FIXME: This should eventually be moved out of the driver, or replaced +// with its eventual successor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TRANSLATION_UNIT_H +#define LLVM_CLANG_TRANSLATION_UNIT_H + +#include "clang/Basic/LangOptions.h" +#include "llvm/Bitcode/SerializationFwd.h" +#include "llvm/System/Path.h" +#include + +namespace clang { + +class FileManager; +class SourceManager; +class TargetInfo; +class IdentifierTable; +class SelectorTable; +class ASTContext; +class Decl; + +class TranslationUnit { + LangOptions LangOpts; + ASTContext* Context; + std::list TopLevelDecls; + + explicit TranslationUnit() : Context(NULL) {} + +public: + explicit TranslationUnit(const LangOptions& lopt, ASTContext& context) + : LangOpts(lopt), Context(&context) {} + + /// EmitBitcodeFile - Emit the translation unit to a bitcode file. + bool EmitBitcodeFile(llvm::sys::Path& Filename) const; + + /// Emit - Emit the translation unit to an arbitray bitcode stream. + void Emit(llvm::Serializer& S) const; + + /// Create - Reconsititute a translation unit from a bitcode stream. + static TranslationUnit* Create(llvm::Deserializer& D, FileManager& FMgr); + + /// ReadBitcodeFile - Reconsitute a translation unit from a bitcode file. + static TranslationUnit* ReadBitcodeFile(llvm::sys::Path& Filename, + FileManager& FMgr); + + // Accessors + const LangOptions& getLangOptions() const { return LangOpts; } + ASTContext* getASTContext() { return Context; } + + /// AddTopLevelDecl - Add a top-level declaration to the translation unit. + void AddTopLevelDecl(Decl* d) { + TopLevelDecls.push_back(d); + } + + typedef std::list::iterator iterator; + iterator begin() { return TopLevelDecls.begin(); } + iterator end() { return TopLevelDecls.end(); } + + typedef std::list::const_iterator const_iterator; + const_iterator begin() const { return TopLevelDecls.begin(); } + const_iterator end() const { return TopLevelDecls.end(); } +}; + +} // end namespace clang + +#endif