mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user