From: Ted Kremenek Date: Wed, 23 Apr 2008 16:25:39 +0000 (+0000) Subject: TranslationUnit now owns IdentifierTable, TargetInfo, and Selectors objects X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c1e9dea3d974dcfcf2baa15810aa3511db688bda;p=clang TranslationUnit now owns IdentifierTable, TargetInfo, and Selectors objects 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50149 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp index eaee94e51d..2f04ab78d4 100644 --- a/Driver/ASTConsumers.cpp +++ b/Driver/ASTConsumers.cpp @@ -826,20 +826,24 @@ namespace { class ASTSerializer : public ASTConsumer { protected: Diagnostic &Diags; - TranslationUnit TU; + const LangOptions& lang; + TranslationUnit* TU; + public: ASTSerializer(Diagnostic& diags, const LangOptions& LO) - : Diags(diags), TU(LO) {} + : Diags(diags), lang(LO), TU(0) {} + + virtual ~ASTSerializer() { delete TU; } virtual void Initialize(ASTContext &Context) { - TU.setContext(&Context); + if (!TU) TU = new TranslationUnit(Context, lang); } virtual void HandleTopLevelDecl(Decl *D) { if (Diags.hasErrorOccurred()) return; - TU.AddTopLevelDecl(D); + if (TU) TU->AddTopLevelDecl(D); } }; @@ -851,7 +855,7 @@ public: : ASTSerializer(diags,LO), FName(F) {} ~SingleFileSerializer() { - EmitASTBitcodeFile(TU,FName); + EmitASTBitcodeFile(TU, FName); } }; @@ -863,7 +867,11 @@ public: : ASTSerializer(diags,LO), EmitDir(dir) {} ~BuildSerializer() { - SourceManager& SourceMgr = TU.getASTContext()->getSourceManager(); + + if (!TU) + return; + + SourceManager& SourceMgr = TU->getContext().getSourceManager(); unsigned ID = SourceMgr.getMainFileID(); assert (ID && "MainFileID not set!"); const FileEntry* FE = SourceMgr.getFileEntryForID(ID); @@ -887,7 +895,7 @@ public: sprintf(&buf[0], "%s-%llX.ast", FE->getName(), (uint64_t) FE->getInode()); FName.appendComponent(&buf[0]); - EmitASTBitcodeFile(TU,FName); + EmitASTBitcodeFile(TU, FName); // Now emit the sources. diff --git a/Driver/SerializationTest.cpp b/Driver/SerializationTest.cpp index 086d5587e9..6e9309dc28 100644 --- a/Driver/SerializationTest.cpp +++ b/Driver/SerializationTest.cpp @@ -33,21 +33,22 @@ using namespace clang; namespace { class SerializationTest : public ASTConsumer { - TranslationUnit TU; + llvm::OwningPtr TU; Diagnostic &Diags; FileManager &FMgr; + const LangOptions& lopts; public: SerializationTest(Diagnostic &d, FileManager& fmgr, const LangOptions& LOpts) - : TU(LOpts), Diags(d), FMgr(fmgr) {} + : Diags(d), FMgr(fmgr), lopts(LOpts) {} ~SerializationTest(); virtual void Initialize(ASTContext& context) { - TU.setContext(&context); + if (!TU) TU.reset(new TranslationUnit(context, lopts)); } virtual void HandleTopLevelDecl(Decl *D) { - TU.AddTopLevelDecl(D); + TU->AddTopLevelDecl(D); } private: @@ -73,12 +74,12 @@ bool SerializationTest::Serialize(llvm::sys::Path& Filename, assert (DeclPP && "Could not open file for printing out decls."); llvm::OwningPtr FilePrinter(CreateASTPrinter(&DeclPP)); - for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I) + for (TranslationUnit::iterator I=TU->begin(), E=TU->end(); I!=E; ++I) FilePrinter->HandleTopLevelDecl(*I); } // Serialize the translation unit. - return EmitASTBitcodeFile(TU,Filename); + return EmitASTBitcodeFile(*TU,Filename); } bool SerializationTest::Deserialize(llvm::sys::Path& Filename, diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 144ab4e65a..f077952ea2 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -1274,7 +1274,7 @@ static void ProcessSerializedFile(const std::string& InFile, Diagnostic& Diag, exit (1); } - llvm::OwningPtr TU(ReadASTBitcodeFile(Filename,FileMgr)); + llvm::OwningPtr TU(ReadASTBitcodeFile(Filename, FileMgr)); if (!TU) { fprintf(stderr, "error: file '%s' could not be deserialized\n", @@ -1294,7 +1294,7 @@ static void ProcessSerializedFile(const std::string& InFile, Diagnostic& Diag, exit (1); } - Consumer->Initialize(*TU->getContext()); + Consumer->Initialize(TU->getContext()); // FIXME: We need to inform Consumer about completed TagDecls as well. for (TranslationUnit::iterator I=TU->begin(), E=TU->end(); I!=E; ++I) diff --git a/include/clang/AST/TranslationUnit.h b/include/clang/AST/TranslationUnit.h index 0c7d0348da..6aa3a40b87 100644 --- a/include/clang/AST/TranslationUnit.h +++ b/include/clang/AST/TranslationUnit.h @@ -34,19 +34,17 @@ class TranslationUnit { LangOptions LangOpts; ASTContext* Context; std::vector TopLevelDecls; + bool OwnsMetaData; // The default ctor is only invoked during deserialization. - explicit TranslationUnit() : Context(NULL) {} + explicit TranslationUnit() : Context(NULL), OwnsMetaData(true) {} public: - explicit TranslationUnit(const LangOptions& lopt) - : LangOpts(lopt), Context(NULL) {} + explicit TranslationUnit(ASTContext& Ctx, const LangOptions& lopt) + : LangOpts(lopt), Context(&Ctx), OwnsMetaData(false) {} ~TranslationUnit(); - void setContext(ASTContext* context) { Context = context; } - ASTContext* getContext() const { return Context; } - const LangOptions& getLangOpts() const { return LangOpts; } const std::string& getSourceFile() const; @@ -58,9 +56,12 @@ public: // Accessors const LangOptions& getLangOptions() const { return LangOpts; } - ASTContext* getASTContext() { return Context; } + + ASTContext& getContext() { return *Context; } + const ASTContext& getContext() const { return *Context; } /// AddTopLevelDecl - Add a top-level declaration to the translation unit. + /// Ownership of the Decl is transfered to the TranslationUnit object. void AddTopLevelDecl(Decl* d) { TopLevelDecls.push_back(d); } @@ -77,6 +78,9 @@ public: /// EmitASTBitcodeFile - Emit a translation unit to a bitcode file. bool EmitASTBitcodeFile(const TranslationUnit& TU, const llvm::sys::Path& Filename); + +bool EmitASTBitcodeFile(const TranslationUnit* TU, + const llvm::sys::Path& Filename); /// ReadASTBitcodeFile - Reconsitute a translation unit from a bitcode file. TranslationUnit* ReadASTBitcodeFile(const llvm::sys::Path& Filename, diff --git a/lib/AST/TranslationUnit.cpp b/lib/AST/TranslationUnit.cpp index 0198f6f1cf..5c043efeb3 100644 --- a/lib/AST/TranslationUnit.cpp +++ b/lib/AST/TranslationUnit.cpp @@ -33,11 +33,28 @@ enum { BasicMetadataBlock = 1, TranslationUnit::~TranslationUnit() { for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->Destroy(*Context); + + if (OwnsMetaData && Context) { + // The ASTContext object has the sole references to the IdentifierTable + // Selectors, and the Target information. Go and delete them, since + // the TranslationUnit effectively owns them. + + delete &(Context->Idents); + delete &(Context->Selectors); + delete &(Context->Target); + delete Context; + } } +bool clang::EmitASTBitcodeFile(const TranslationUnit* TU, + const llvm::sys::Path& Filename) { + + return TU ? EmitASTBitcodeFile(*TU, Filename) : false; +} + bool clang::EmitASTBitcodeFile(const TranslationUnit& TU, const llvm::sys::Path& Filename) { - + // Reserve 256K for bitstream buffer. std::vector Buffer; Buffer.reserve(256*1024); @@ -194,7 +211,7 @@ TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr, { // Read the TargetInfo. llvm::SerializedPtrID PtrID = Dezr.ReadPtrID(); char* triple = Dezr.ReadCStr(NULL,0,true); - Dezr.RegisterPtr(PtrID,TargetInfo::CreateTargetInfo(std::string(triple))); + Dezr.RegisterPtr(PtrID, TargetInfo::CreateTargetInfo(std::string(triple))); delete [] triple; }