Stop leaking memory from Module and FileUnit.

Also, disallow creating Modules and FileUnits on the stack. They must always
live as long as the ASTContext.

<rdar://problem/15596964>

Swift SVN r13671
This commit is contained in:
Jordan Rose
2014-02-08 02:12:57 +00:00
parent 1e3fd1a5b1
commit cbcf17f9bd
11 changed files with 37 additions and 14 deletions

View File

@@ -392,6 +392,13 @@ public:
/// Add a cleanup function to be called when the ASTContext is deallocated. /// Add a cleanup function to be called when the ASTContext is deallocated.
void addCleanup(std::function<void(void)> cleanup); void addCleanup(std::function<void(void)> cleanup);
/// Add a cleanup to run the given object's destructor when the ASTContext is
/// deallocated.
template<typename T>
void addDestructorCleanup(T &object) {
addCleanup([&object]{ object.~T(); });
}
/// Create a context for the initializer of a non-local variable, /// Create a context for the initializer of a non-local variable,
/// like a global or a field. To reduce memory usage, if the /// like a global or a field. To reduce memory usage, if the
/// context goes unused, it should be returned to the ASTContext /// context goes unused, it should be returned to the ASTContext

View File

@@ -172,13 +172,12 @@ private:
// FIXME: Do we really need to bloat all modules with this? // FIXME: Do we really need to bloat all modules with this?
DebuggerClient *DebugClient = nullptr; DebuggerClient *DebugClient = nullptr;
// FIXME: This storage is never freed, because Modules are allocated on the
// ASTContext.
TinyPtrVector<FileUnit *> Files; TinyPtrVector<FileUnit *> Files;
Module(Identifier name, ASTContext &ctx);
public: public:
Module(Identifier Name, ASTContext &C) static Module *create(Identifier name, ASTContext &ctx) {
: DeclContext(DeclContextKind::Module, nullptr), Ctx(C), Name(Name) { return new (ctx) Module(name, ctx);
} }
ArrayRef<FileUnit *> getFiles() { ArrayRef<FileUnit *> getFiles() {
@@ -413,9 +412,9 @@ protected:
: DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) { : DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) {
} }
public:
virtual ~FileUnit() = default; virtual ~FileUnit() = default;
public:
FileUnitKind getKind() const { FileUnitKind getKind() const {
return Kind; return Kind;
} }
@@ -571,6 +570,8 @@ private:
/// May be -1, to indicate no association with a buffer. /// May be -1, to indicate no association with a buffer.
int BufferID; int BufferID;
friend ASTContext;
~SourceFile();
public: public:
/// The list of top-level declarations in the source file. /// The list of top-level declarations in the source file.
std::vector<Decl*> Decls; std::vector<Decl*> Decls;
@@ -606,7 +607,6 @@ public:
SourceFile(Module &M, SourceFileKind K, Optional<unsigned> bufferID, SourceFile(Module &M, SourceFileKind K, Optional<unsigned> bufferID,
bool hasBuiltinModuleAccess = false); bool hasBuiltinModuleAccess = false);
~SourceFile();
ArrayRef<std::pair<Module::ImportedModule, bool>> getImports() const { ArrayRef<std::pair<Module::ImportedModule, bool>> getImports() const {
assert(ASTStage >= Parsed || Kind == SourceFileKind::SIL); assert(ASTStage >= Parsed || Kind == SourceFileKind::SIL);
@@ -714,6 +714,9 @@ private:
std::unique_ptr<LookupCache> Cache; std::unique_ptr<LookupCache> Cache;
LookupCache &getCache() const; LookupCache &getCache() const;
friend ASTContext;
~BuiltinUnit() = default;
public: public:
explicit BuiltinUnit(Module &M); explicit BuiltinUnit(Module &M);
@@ -733,6 +736,7 @@ public:
/// Represents an externally-loaded file of some kind. /// Represents an externally-loaded file of some kind.
class LoadedFile : public FileUnit { class LoadedFile : public FileUnit {
protected: protected:
~LoadedFile() = default;
LoadedFile(FileUnitKind Kind, Module &M) noexcept LoadedFile(FileUnitKind Kind, Module &M) noexcept
: FileUnit(Kind, M) { : FileUnit(Kind, M) {
assert(classof(this) && "invalid kind"); assert(classof(this) && "invalid kind");

View File

@@ -37,6 +37,8 @@ class ClangModuleUnit final : public LoadedFile {
Module *getAdapterModule() const; Module *getAdapterModule() const;
~ClangModuleUnit() = default;
public: public:
ClangModuleUnit(Module &M, ClangImporter &owner, ClangModuleUnit(Module &M, ClangImporter &owner,
clang::Module *clangModule); clang::Module *clangModule);

View File

@@ -132,6 +132,8 @@ class SerializedASTFile final : public LoadedFile {
ModuleFile &File; ModuleFile &File;
~SerializedASTFile() = default;
SerializedASTFile(Module &M, ModuleFile &file) SerializedASTFile(Module &M, ModuleFile &file)
: LoadedFile(FileUnitKind::SerializedAST, M), File(file) {} : LoadedFile(FileUnitKind::SerializedAST, M), File(file) {}

View File

@@ -244,7 +244,7 @@ ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() {
} }
static Module *createBuiltinModule(ASTContext &ctx) { static Module *createBuiltinModule(ASTContext &ctx) {
auto M = new (ctx) Module(ctx.getIdentifier("Builtin"), ctx); auto M = Module::create(ctx.getIdentifier("Builtin"), ctx);
M->addFile(*new (ctx) BuiltinUnit(*M)); M->addFile(*new (ctx) BuiltinUnit(*M));
return M; return M;
} }

View File

@@ -84,6 +84,7 @@ void BuiltinUnit::LookupCache::lookupValue(Identifier Name, NLKind LookupKind,
// Out-of-line because std::unique_ptr wants LookupCache to be complete. // Out-of-line because std::unique_ptr wants LookupCache to be complete.
BuiltinUnit::BuiltinUnit(Module &M) BuiltinUnit::BuiltinUnit(Module &M)
: FileUnit(FileUnitKind::Builtin, M) { : FileUnit(FileUnitKind::Builtin, M) {
M.Ctx.addDestructorCleanup(*this);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@@ -269,6 +270,12 @@ void SourceLookupCache::lookupClassMember(AccessPathTy accessPath,
// Module Implementation // Module Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
Module::Module(Identifier name, ASTContext &ctx)
: DeclContext(DeclContextKind::Module, nullptr), Ctx(ctx), Name(name) {
ctx.addDestructorCleanup(*this);
}
void Module::addFile(FileUnit &newFile) { void Module::addFile(FileUnit &newFile) {
// Require Main and REPL files to be the first file added. // Require Main and REPL files to be the first file added.
assert(Files.empty() || assert(Files.empty() ||
@@ -1099,6 +1106,7 @@ SourceFile::SourceFile(Module &M, SourceFileKind K,
Optional<unsigned> bufferID, bool hasBuiltinModuleAccess) Optional<unsigned> bufferID, bool hasBuiltinModuleAccess)
: FileUnit(FileUnitKind::Source, M), : FileUnit(FileUnitKind::Source, M),
BufferID(bufferID ? *bufferID : -1), Kind(K) { BufferID(bufferID ? *bufferID : -1), Kind(K) {
M.Ctx.addDestructorCleanup(*this);
performAutoImport(*this, hasBuiltinModuleAccess); performAutoImport(*this, hasBuiltinModuleAccess);
} }

View File

@@ -304,7 +304,7 @@ Module *ClangImporter::loadModule(
// FIXME: The name of this module could end up as a key in the ASTContext, // FIXME: The name of this module could end up as a key in the ASTContext,
// but that's not correct for submodules. // but that's not correct for submodules.
Identifier name = Impl.SwiftContext.getIdentifier((*clangModule).Name); Identifier name = Impl.SwiftContext.getIdentifier((*clangModule).Name);
auto result = new (Impl.SwiftContext) Module(name, Impl.SwiftContext); auto result = Module::create(name, Impl.SwiftContext);
auto file = new (Impl.SwiftContext) ClangModuleUnit(*result, *this, auto file = new (Impl.SwiftContext) ClangModuleUnit(*result, *this,
clangModule); clangModule);
@@ -332,7 +332,7 @@ ClangImporter::Implementation::getWrapperForModule(ClangImporter &importer,
// FIXME: Handle hierarchical names better. // FIXME: Handle hierarchical names better.
Identifier name = SwiftContext.getIdentifier(underlying->Name); Identifier name = SwiftContext.getIdentifier(underlying->Name);
auto wrapper = new (SwiftContext) Module(name, SwiftContext); auto wrapper = Module::create(name, SwiftContext);
auto file = new (SwiftContext) ClangModuleUnit(*wrapper, importer, auto file = new (SwiftContext) ClangModuleUnit(*wrapper, importer,
underlying); underlying);

View File

@@ -161,7 +161,7 @@ bool swift::CompilerInstance::setup(const CompilerInvocation &Invok) {
void CompilerInstance::performParse() { void CompilerInstance::performParse() {
const SourceFileKind Kind = Invocation.getInputKind(); const SourceFileKind Kind = Invocation.getInputKind();
Identifier ID = Context->getIdentifier(Invocation.getModuleName()); Identifier ID = Context->getIdentifier(Invocation.getModuleName());
MainModule = new (*Context) Module(ID, *Context); MainModule = Module::create(ID, *Context);
Context->LoadedModules[ID.str()] = MainModule; Context->LoadedModules[ID.str()] = MainModule;
if (Kind == SourceFileKind::SIL) { if (Kind == SourceFileKind::SIL) {

View File

@@ -33,8 +33,8 @@ bool ide::isSourceInputComplete(std::unique_ptr<llvm::MemoryBuffer> MemBuf) {
ASTContext Ctx(LangOpts, SearchPathOpts, SM, Diags); ASTContext Ctx(LangOpts, SearchPathOpts, SM, Diags);
auto ModName = Ctx.getIdentifier("input"); auto ModName = Ctx.getIdentifier("input");
Module Mod(ModName, Ctx); Module &Mod = *Module::create(ModName, Ctx);
SourceFile SF(Mod, SourceFileKind::Main, BufferID); SourceFile &SF = *new (Ctx) SourceFile(Mod, SourceFileKind::Main, BufferID);
PersistentParserState PersistentState; PersistentParserState PersistentState;
Parser P(BufferID, SF, /*SIL=*/nullptr, &PersistentState); Parser P(BufferID, SF, /*SIL=*/nullptr, &PersistentState);

View File

@@ -93,7 +93,7 @@ Module *SourceLoader::loadModule(SourceLoc importLoc,
else else
bufferID = Ctx.SourceMgr.addNewSourceBuffer(inputFile.take()); bufferID = Ctx.SourceMgr.addNewSourceBuffer(inputFile.take());
auto *importMod = new (Ctx) Module(moduleID.first, Ctx); auto *importMod = Module::create(moduleID.first, Ctx);
Ctx.LoadedModules[moduleID.first.str()] = importMod; Ctx.LoadedModules[moduleID.first.str()] = importMod;
auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library, auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library,

View File

@@ -218,7 +218,7 @@ Module *SerializedModuleLoader::loadModule(SourceLoc importLoc,
assert(inputFile); assert(inputFile);
auto M = new (Ctx) Module(moduleID.first, Ctx); auto M = Module::create(moduleID.first, Ctx);
Ctx.LoadedModules[moduleID.first.str()] = M; Ctx.LoadedModules[moduleID.first.str()] = M;
(void)loadAST(*M, moduleID.second, std::move(inputFile)); (void)loadAST(*M, moduleID.second, std::move(inputFile));