mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 19:49:36 +00:00
467297ab48
when it is constructed via deserialization. This is done by recording a flag indicating that this is the case, and it deletes these objects by getting the references stored in the ASTContext object. This fixes some memory leaks that occurs when we deserialize translation units from bitcode files. The rationale between having TranslationUnit sometimes own these objects and sometimes not is that a TranslationUnit object can be constructed from state generated by the parser (Preprocessor; semantic analyzer, etc.), and thus in these cases won't own the IdentifierTable or Selectors, etc. During deserialization, there is no Preprocessor, so somebody needs to own these objects in order for them to be properly reclaimed. llvm-svn: 50149
198 lines
5.8 KiB
C++
198 lines
5.8 KiB
C++
//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements prototype code for serialization of objects in clang.
|
|
// It is not intended yet for public use, but simply is a placeholder to
|
|
// experiment with new serialization features. Serialization will eventually
|
|
// be integrated as a proper component of the clang libraries.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/ASTConsumer.h"
|
|
#include "clang/AST/CFG.h"
|
|
#include "clang.h"
|
|
#include "ASTConsumers.h"
|
|
#include "clang/AST/TranslationUnit.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/Support/Streams.h"
|
|
#include <fstream>
|
|
#include <cstring>
|
|
using namespace clang;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Driver code.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
|
|
class SerializationTest : public ASTConsumer {
|
|
llvm::OwningPtr<TranslationUnit> TU;
|
|
Diagnostic &Diags;
|
|
FileManager &FMgr;
|
|
const LangOptions& lopts;
|
|
public:
|
|
SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts)
|
|
: Diags(d), FMgr(fmgr), lopts(LOpts) {}
|
|
|
|
~SerializationTest();
|
|
|
|
virtual void Initialize(ASTContext& context) {
|
|
if (!TU) TU.reset(new TranslationUnit(context, lopts));
|
|
}
|
|
|
|
virtual void HandleTopLevelDecl(Decl *D) {
|
|
TU->AddTopLevelDecl(D);
|
|
}
|
|
|
|
private:
|
|
bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
|
bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
ASTConsumer*
|
|
clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr,
|
|
const LangOptions &LOpts) {
|
|
|
|
return new SerializationTest(Diags,FMgr,LOpts);
|
|
}
|
|
|
|
|
|
bool SerializationTest::Serialize(llvm::sys::Path& Filename,
|
|
llvm::sys::Path& FNameDeclPrint) {
|
|
{
|
|
// Pretty-print the decls to a temp file.
|
|
std::ofstream DeclPP(FNameDeclPrint.c_str());
|
|
assert (DeclPP && "Could not open file for printing out decls.");
|
|
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
|
|
|
for (TranslationUnit::iterator I=TU->begin(), E=TU->end(); I!=E; ++I)
|
|
FilePrinter->HandleTopLevelDecl(*I);
|
|
}
|
|
|
|
// Serialize the translation unit.
|
|
return EmitASTBitcodeFile(*TU,Filename);
|
|
}
|
|
|
|
bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
|
|
llvm::sys::Path& FNameDeclPrint) {
|
|
|
|
// Deserialize the translation unit.
|
|
TranslationUnit* NewTU = ReadASTBitcodeFile(Filename,FMgr);
|
|
|
|
if (!NewTU)
|
|
return false;
|
|
|
|
{
|
|
// Pretty-print the deserialized decls to a temp file.
|
|
std::ofstream DeclPP(FNameDeclPrint.c_str());
|
|
assert (DeclPP && "Could not open file for printing out decls.");
|
|
llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
|
|
|
|
for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
|
|
FilePrinter->HandleTopLevelDecl(*I);
|
|
}
|
|
|
|
delete NewTU;
|
|
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
class TmpDirJanitor {
|
|
llvm::sys::Path& Dir;
|
|
public:
|
|
explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
|
|
|
|
~TmpDirJanitor() {
|
|
llvm::cerr << "Removing: " << Dir.c_str() << '\n';
|
|
Dir.eraseFromDisk(true);
|
|
}
|
|
};
|
|
}
|
|
|
|
SerializationTest::~SerializationTest() {
|
|
|
|
std::string ErrMsg;
|
|
llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
|
|
|
|
if (Dir.isEmpty()) {
|
|
llvm::cerr << "Error: " << ErrMsg << "\n";
|
|
return;
|
|
}
|
|
|
|
TmpDirJanitor RemoveTmpOnExit(Dir);
|
|
|
|
llvm::sys::Path FNameDeclBefore = Dir;
|
|
FNameDeclBefore.appendComponent("test.decl_before.txt");
|
|
|
|
if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
|
|
llvm::cerr << "Error: " << ErrMsg << "\n";
|
|
return;
|
|
}
|
|
|
|
llvm::sys::Path FNameDeclAfter = Dir;
|
|
FNameDeclAfter.appendComponent("test.decl_after.txt");
|
|
|
|
if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
|
|
llvm::cerr << "Error: " << ErrMsg << "\n";
|
|
return;
|
|
}
|
|
|
|
llvm::sys::Path ASTFilename = Dir;
|
|
ASTFilename.appendComponent("test.ast");
|
|
|
|
if (ASTFilename.makeUnique(true,&ErrMsg)) {
|
|
llvm::cerr << "Error: " << ErrMsg << "\n";
|
|
return;
|
|
}
|
|
|
|
// Serialize and then deserialize the ASTs.
|
|
bool status = Serialize(ASTFilename, FNameDeclBefore);
|
|
assert (status && "Serialization failed.");
|
|
status = Deserialize(ASTFilename, FNameDeclAfter);
|
|
assert (status && "Deserialization failed.");
|
|
|
|
// Read both pretty-printed files and compare them.
|
|
|
|
using llvm::MemoryBuffer;
|
|
|
|
llvm::OwningPtr<MemoryBuffer>
|
|
MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str()));
|
|
|
|
if(!MBufferSer) {
|
|
llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
|
|
return;
|
|
}
|
|
|
|
llvm::OwningPtr<MemoryBuffer>
|
|
MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str()));
|
|
|
|
if(!MBufferDSer) {
|
|
llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
|
|
return;
|
|
}
|
|
|
|
const char *p1 = MBufferSer->getBufferStart();
|
|
const char *e1 = MBufferSer->getBufferEnd();
|
|
const char *p2 = MBufferDSer->getBufferStart();
|
|
const char *e2 = MBufferDSer->getBufferEnd();
|
|
|
|
if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
|
|
for ( ; p1 != e1 ; ++p1, ++p2 )
|
|
if (*p1 != *p2) break;
|
|
|
|
if (p1 != e1 || p2 != e2 )
|
|
llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
|
|
else
|
|
llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
|
|
}
|