Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion interpreter/cling/lib/Interpreter/CIFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,9 @@ namespace {
for (auto& E : moduleExtensions)
FrontendOpts.ModuleFileExtensions.push_back(E);

FrontendOpts.DisableFree = true;
// The clang driver adds -disable-free to every cc1 line.
// Interpreter::ShutDown() should free the frontend.
FrontendOpts.DisableFree = false;
Comment on lines -1625 to +1627

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT this is mostly an optimization where, instead of freeing, the "compiler" intentionally leaks because the OS will clean up the process anyway.


// Set up compiler language and target
if (!SetupCompiler(CI.get(), COpts, InitLang, InitTarget))
Expand Down
30 changes: 21 additions & 9 deletions interpreter/cling/lib/Interpreter/IncrementalJIT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ namespace {
bool needsToReserveAllocationSpace() override { return true; }
};

/// A JITLinkMemoryManager for Cling that never frees its allocations.
/// A JITLinkMemoryManager for Cling.
class ClingJITLinkMemoryManager : public InProcessMemoryManager {
public:
using InProcessMemoryManager::InProcessMemoryManager;
Expand All @@ -273,16 +273,28 @@ namespace {
// Disabled until CallFunc is informed about unloading, and can
// re-generate the wrapper (if the decl is still available). See
// https://github.com/root-project/root/issues/10898

// We still have to release the allocations which resets their addresses
// to FinalizedAlloc::InvalidAddr, or the assertion in ~FinalizedAlloc
// will be unhappy...
for (auto &Alloc : Allocs) {
Alloc.release();
}
// Pretend we successfully deallocated everything...
//
// Releasing the handles orphans each allocation's vector of JITLink
// dealloc actions. Retain them (required for CallFunc) and let the
// base class free everything when this manager is destroyed at
// interpreter teardown.
std::lock_guard<std::mutex> G(m_RetainedMutex);
for (auto& Alloc : Allocs)
m_Retained.push_back(std::move(Alloc));
OnDeallocated(Error::success());
}

~ClingJITLinkMemoryManager() override {
if (!m_Retained.empty())
InProcessMemoryManager::deallocate(std::move(m_Retained),
[](Error Err) {
consumeError(std::move(Err));
});
Comment on lines +288 to +292

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may still be too early, depending on which order the shutdown sequence is running and and whether something still has a pointer to one of the compiled functions...

}

private:
std::mutex m_RetainedMutex;
std::vector<FinalizedAlloc> m_Retained;
};

/// A DynamicLibrarySearchGenerator that uses ResourceTracker to remember
Expand Down
2 changes: 2 additions & 0 deletions interpreter/cling/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ namespace cling {
return Result.getLocWithOffset(m_VirtualFileLocOffset++);
}

void IncrementalParser::destroyParser() { m_Parser.reset(); }

IncrementalParser::~IncrementalParser() {
Transaction* T = const_cast<Transaction*>(getFirstTransaction());
while (T) {
Expand Down
4 changes: 4 additions & 0 deletions interpreter/cling/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ namespace cling {
bool isChildInterpreter);
clang::CompilerInstance* getCI() const { return m_CI.get(); }
clang::Parser* getParser() const { return m_Parser.get(); }

///\brief Destroy the Parser. It writes to Sema in its destructor, so
/// it must go before Interpreter::ShutDown() frees Sema.
void destroyParser();
clang::CodeGenerator* getCodeGenerator() const { return m_CodeGen; }
bool hasCodeGenerator() const { return m_CodeGen; }

Expand Down
11 changes: 7 additions & 4 deletions interpreter/cling/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,11 @@ namespace cling {
CI->resetAndLeakASTContext();
llvm::BuryPointer(CI->takeASTConsumer().get());
} else {
// The Parser writes to Sema in its destructor, so it must go
// first; Sema, the ASTContext and the consumer are freed here,
// while the diagnostic client and the interpreter callbacks are
// still alive -- ~Sema and ~ASTContext reach both.
m_IncrParser->destroyParser();
CI->setSema(nullptr);
CI->setASTContext(nullptr);
CI->setASTConsumer(nullptr);
Expand All @@ -625,11 +630,9 @@ namespace cling {
CI->resetAndLeakPreprocessor();
CI->resetAndLeakSourceManager();
CI->resetAndLeakFileManager();
} else {
CI->setPreprocessor(nullptr);
CI->setSourceManager(nullptr);
CI->setFileManager(nullptr);
}
// ~CompilerInstance destroys the Preprocessor, SourceManager and
// FileManager in the right order.
}

LO.setCompilingModule(clang::LangOptions::CMK_None);
Expand Down
Loading