diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 469ce1fd75bf8..1dcba1ef96798 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -96,7 +96,6 @@ class Interpreter { // An optional parser for CUDA offloading std::unique_ptr DeviceParser; - llvm::Error CreateExecutor(); unsigned InitPTUSize = 0; // This member holds the last result of the value printing. It's a class @@ -114,6 +113,14 @@ class Interpreter { // That's useful for testing and out-of-tree clients. Interpreter(std::unique_ptr CI, llvm::Error &Err); + // Create the internal IncrementalExecutor, or re-create it after calling + // ResetExecutor(). + llvm::Error CreateExecutor(); + + // Delete the internal IncrementalExecutor. This causes a hard shutdown of the + // JIT engine. In particular, it doesn't run cleanup or destructors. + void ResetExecutor(); + // Lazily construct the RuntimeInterfaceBuilder. The provided instance will be // used for the entire lifetime of the interpreter. The default implementation // targets the in-process __clang_Interpreter runtime. Override this to use a diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index e293fefb52496..7fa52f2f15fc4 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -375,6 +375,10 @@ Interpreter::Parse(llvm::StringRef Code) { llvm::Error Interpreter::CreateExecutor() { const clang::TargetInfo &TI = getCompilerInstance()->getASTContext().getTargetInfo(); + if (IncrExecutor) + return llvm::make_error("Operation failed. " + "Execution engine exists", + std::error_code()); llvm::Error Err = llvm::Error::success(); auto Executor = std::make_unique(*TSCtx, Err, TI); if (!Err) @@ -383,6 +387,8 @@ llvm::Error Interpreter::CreateExecutor() { return Err; } +void Interpreter::ResetExecutor() { IncrExecutor.reset(); } + llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { assert(T.TheModule); if (!IncrExecutor) { diff --git a/clang/unittests/Interpreter/CMakeLists.txt b/clang/unittests/Interpreter/CMakeLists.txt index 046d96ad0ec64..498070b43d922 100644 --- a/clang/unittests/Interpreter/CMakeLists.txt +++ b/clang/unittests/Interpreter/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS OrcJIT Support TargetParser + TestingSupport ) add_clang_unittest(ClangReplInterpreterTests diff --git a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp index 4e9f2dba210a3..f1c3d65ab0a95 100644 --- a/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp +++ b/clang/unittests/Interpreter/InterpreterExtensionsTest.cpp @@ -27,6 +27,30 @@ using namespace clang; namespace { +class TestCreateResetExecutor : public Interpreter { +public: + TestCreateResetExecutor(std::unique_ptr CI, + llvm::Error &Err) + : Interpreter(std::move(CI), Err) {} + + llvm::Error testCreateExecutor() { return Interpreter::CreateExecutor(); } + + void resetExecutor() { Interpreter::ResetExecutor(); } +}; + +TEST(InterpreterExtensionsTest, ExecutorCreateReset) { + clang::IncrementalCompilerBuilder CB; + llvm::Error ErrOut = llvm::Error::success(); + TestCreateResetExecutor Interp(cantFail(CB.CreateCpp()), ErrOut); + cantFail(std::move(ErrOut)); + cantFail(Interp.testCreateExecutor()); + Interp.resetExecutor(); + cantFail(Interp.testCreateExecutor()); + EXPECT_THAT_ERROR(Interp.testCreateExecutor(), + llvm::FailedWithMessage("Operation failed. " + "Execution engine exists")); +} + class RecordRuntimeIBMetrics : public Interpreter { struct NoopRuntimeInterfaceBuilder : public RuntimeInterfaceBuilder { NoopRuntimeInterfaceBuilder(Sema &S) : S(S) {}