Skip to content

Commit 9e2eb5b

Browse files
add Cpp::TakeInterpreter
pops interpreter with destroying it destruction to be handled by the caller
1 parent 573ba9e commit 9e2eb5b

File tree

4 files changed

+84
-37
lines changed

4 files changed

+84
-37
lines changed

include/CppInterOp/CppInterOp.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,11 @@ CreateInterpreter(const std::vector<const char*>& Args = {},
702702
///\returns false on failure or if \c I is not tracked in the stack.
703703
CPPINTEROP_API bool DeleteInterpreter(TInterp_t I = nullptr);
704704

705+
/// Take ownership of an interpreter instance.
706+
///\param[in] I - the interpreter to be taken, if nullptr, returns the last.
707+
///\returns nullptr on failure or if \c I is not tracked in the stack.
708+
CPPINTEROP_API TInterp_t TakeInterpreter(TInterp_t I = nullptr);
709+
705710
/// Activates an instance of an interpreter to handle subsequent API requests
706711
///\param[in] I - the interpreter to be activated.
707712
///\returns false on failure.

lib/CppInterOp/CppInterOp.cpp

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "llvm/Support/CommandLine.h"
5555
#include "llvm/Support/Debug.h"
5656
#include "llvm/Support/Error.h"
57+
#include "llvm/Support/ErrorHandling.h"
5758
#include "llvm/Support/ManagedStatic.h"
5859
#include "llvm/Support/Path.h"
5960
#include "llvm/Support/raw_ostream.h"
@@ -138,16 +139,16 @@ struct InterpreterInfo {
138139
InterpreterInfo& operator=(const InterpreterInfo&) = delete;
139140
};
140141

141-
// NOLINTBEGIN
142+
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
142143
// std::deque avoids relocations and calling the dtor of InterpreterInfo.
143-
static llvm::ManagedStatic<std::deque<std::shared_ptr<InterpreterInfo>>>
144+
static llvm::ManagedStatic<std::deque<std::unique_ptr<InterpreterInfo>>>
144145
sInterpreters;
145146
static llvm::ManagedStatic<
146-
std::unordered_map<clang::ASTContext*, std::weak_ptr<InterpreterInfo>>>
147+
std::unordered_map<clang::ASTContext*, InterpreterInfo*>>
147148
sInterpreterASTMap;
148149
static std::recursive_mutex InterpreterStackLock;
149150
static std::recursive_mutex LLVMLock;
150-
// NOLINTEND
151+
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
151152

152153
static InterpreterInfo& getInterpInfo() {
153154
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
@@ -161,17 +162,20 @@ static InterpreterInfo& getInterpInfo(const clang::Decl* D) {
161162
return getInterpInfo();
162163
if (sInterpreters->size() == 1)
163164
return *sInterpreters->back();
164-
return *(*sInterpreterASTMap)[&D->getASTContext()].lock();
165+
return *(*sInterpreterASTMap)[&D->getASTContext()];
165166
}
166167
static InterpreterInfo& getInterpInfo(const void* D) {
167168
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
169+
QualType QT = QualType::getFromOpaquePtr(D);
170+
if (auto* D = QT->getAsTagDecl())
171+
return getInterpInfo(D);
168172
if (!D)
169173
return getInterpInfo();
170174
if (sInterpreters->size() == 1)
171175
return *sInterpreters->back();
172176
for (auto& item : *sInterpreterASTMap) {
173177
if (item.first->getAllocator().identifyObject(D))
174-
return *item.second.lock();
178+
return *item.second;
175179
}
176180
llvm_unreachable(
177181
"This pointer does not belong to any interpreter instance.\n");
@@ -189,7 +193,7 @@ static compat::Interpreter& getInterp(const clang::Decl* D) {
189193
return getInterp();
190194
if (sInterpreters->size() == 1)
191195
return *sInterpreters->back()->Interpreter;
192-
return *(*sInterpreterASTMap)[&D->getASTContext()].lock()->Interpreter;
196+
return *(*sInterpreterASTMap)[&D->getASTContext()]->Interpreter;
193197
}
194198
static compat::Interpreter& getInterp(const void* D) {
195199
return *getInterpInfo(D).Interpreter;
@@ -3338,6 +3342,8 @@ static std::string MakeResourcesPath() {
33383342
TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
33393343
const std::vector<const char*>& GpuArgs /*={}*/) {
33403344
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
3345+
assert(sInterpreters->size() == sInterpreterASTMap->size());
3346+
33413347
std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr);
33423348
std::string ResourceDir = MakeResourcesPath();
33433349
std::vector<const char*> ClingArgv = {"-resource-dir", ResourceDir.c_str(),
@@ -3414,42 +3420,73 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
34143420
)");
34153421

34163422
sInterpreters->emplace_back(
3417-
std::make_shared<InterpreterInfo>(I, /*Owned=*/true));
3423+
std::make_unique<InterpreterInfo>(I, /*Owned=*/true));
34183424
sInterpreterASTMap->insert(
34193425
{&sInterpreters->back()->Interpreter->getSema().getASTContext(),
3420-
sInterpreters->back()});
3426+
sInterpreters->back().get()});
34213427

3428+
assert(sInterpreters->size() == sInterpreterASTMap->size());
34223429
return I;
34233430
}
34243431

3432+
static inline auto find_interpreter_in_stack(TInterp_t I) {
3433+
return std::find_if(
3434+
sInterpreters->begin(), sInterpreters->end(),
3435+
[&I](const auto& Info) { return Info->Interpreter == I; });
3436+
}
3437+
3438+
static inline auto find_interpreter_in_map(InterpreterInfo* I) {
3439+
return std::find_if(sInterpreterASTMap->begin(), sInterpreterASTMap->end(),
3440+
[&](const auto& Item) { return Item.second == I; });
3441+
}
3442+
34253443
bool DeleteInterpreter(TInterp_t I /*=nullptr*/) {
34263444
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
3445+
assert(sInterpreters->size() == sInterpreterASTMap->size());
34273446

34283447
if (!I) {
3429-
auto foundAST =
3430-
std::find_if(sInterpreterASTMap->begin(), sInterpreterASTMap->end(),
3431-
[](const auto& Item) {
3432-
return Item.second.lock() == sInterpreters->back();
3433-
});
3448+
auto foundAST = find_interpreter_in_map(sInterpreters->back().get());
3449+
assert(foundAST != sInterpreterASTMap->end());
34343450
sInterpreterASTMap->erase(foundAST);
34353451
sInterpreters->pop_back();
34363452
return true;
34373453
}
34383454

3439-
auto found =
3440-
std::find_if(sInterpreters->begin(), sInterpreters->end(),
3441-
[&I](const auto& Info) { return Info->Interpreter == I; });
3455+
auto found = find_interpreter_in_stack(I);
34423456
if (found == sInterpreters->end())
34433457
return false; // failure
34443458

3445-
auto foundAST = std::find_if(
3446-
sInterpreterASTMap->begin(), sInterpreterASTMap->end(),
3447-
[&found](const auto& Item) { return Item.second.lock() == *found; });
3459+
auto foundAST = find_interpreter_in_map((*found).get());
3460+
assert(foundAST != sInterpreterASTMap->end());
34483461
sInterpreterASTMap->erase(foundAST);
34493462
sInterpreters->erase(found);
34503463
return true;
34513464
}
34523465

3466+
TInterp_t TakeInterpreter(TInterp_t I /*=nullptr*/) {
3467+
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
3468+
assert(sInterpreters->size() == sInterpreterASTMap->size());
3469+
3470+
if (!I) {
3471+
auto foundAST = find_interpreter_in_map(sInterpreters->back().get());
3472+
sInterpreterASTMap->erase(foundAST);
3473+
InterpreterInfo* res = sInterpreters->back().release();
3474+
sInterpreters->pop_back();
3475+
return res->Interpreter;
3476+
}
3477+
3478+
auto found = find_interpreter_in_stack(I);
3479+
if (found == sInterpreters->end())
3480+
return nullptr; // failure
3481+
3482+
auto foundAST = find_interpreter_in_map((*found).get());
3483+
sInterpreterASTMap->erase(foundAST);
3484+
InterpreterInfo* res = (*found).release();
3485+
sInterpreters->erase(found);
3486+
assert(sInterpreters->size() == sInterpreterASTMap->size());
3487+
return res->Interpreter;
3488+
}
3489+
34533490
bool ActivateInterpreter(TInterp_t I) {
34543491
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
34553492

@@ -3477,10 +3514,13 @@ TInterp_t GetInterpreter() {
34773514

34783515
void UseExternalInterpreter(TInterp_t I) {
34793516
std::lock_guard<std::recursive_mutex> Lock(InterpreterStackLock);
3480-
assert(sInterpreters->empty() && "sInterpreter already in use!");
34813517
sInterpreters->emplace_back(
3482-
std::make_shared<InterpreterInfo>(static_cast<compat::Interpreter*>(I),
3518+
std::make_unique<InterpreterInfo>(static_cast<compat::Interpreter*>(I),
34833519
/*isOwned=*/false));
3520+
sInterpreterASTMap->insert(
3521+
{&sInterpreters->back()->Interpreter->getSema().getASTContext(),
3522+
sInterpreters->back().get()});
3523+
assert(sInterpreters->size() == sInterpreterASTMap->size());
34843524
}
34853525

34863526
void AddSearchPath(const char* dir, bool isUser, bool prepend) {
@@ -3734,9 +3774,9 @@ std::string ObjToString(const char* type, void* obj) {
37343774
return getInterp().toString(type, obj);
37353775
}
37363776

3737-
Decl* InstantiateTemplate(TemplateDecl* TemplateD,
3738-
TemplateArgumentListInfo& TLI, Sema& S,
3739-
bool instantiate_body) {
3777+
static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
3778+
TemplateArgumentListInfo& TLI, Sema& S,
3779+
bool instantiate_body) {
37403780
LOCK(getInterpInfo());
37413781
// This is not right but we don't have a lot of options to choose from as a
37423782
// template instantiation requires a valid source location.

lib/CppInterOp/CppInterOpInterpreter.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,11 @@ namespace Cpp {
140140
/// CppInterOp Interpreter
141141
///
142142
class Interpreter {
143-
private:
144143
std::unique_ptr<clang::Interpreter> inner;
145144

145+
public:
146146
Interpreter(std::unique_ptr<clang::Interpreter> CI) : inner(std::move(CI)) {}
147147

148-
public:
149148
static std::unique_ptr<Interpreter>
150149
create(int argc, const char* const* argv, const char* llvmdir = nullptr,
151150
const std::vector<std::shared_ptr<clang::ModuleFileExtension>>&

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "gtest/gtest.h"
2525

2626
#include <algorithm>
27+
#include <utility>
2728

2829
using ::testing::StartsWith;
2930

@@ -150,6 +151,8 @@ TEST(InterpreterTest, Process) {
150151
EXPECT_EQ(Res, CXError_Success);
151152
clang_Value_dispose(CXV);
152153
clang_Interpreter_dispose(CXI);
154+
auto* OldI = Cpp::TakeInterpreter();
155+
EXPECT_EQ(OldI, I);
153156
}
154157

155158
TEST(InterpreterTest, EmscriptenExceptionHandling) {
@@ -329,7 +332,9 @@ if (llvm::sys::RunningOnValgrind())
329332
// Create the interpreter instance.
330333
std::unique_ptr<clang::Interpreter> I =
331334
ExitOnErr(clang::Interpreter::create(std::move(CI)));
332-
auto ExtInterp = I.get();
335+
336+
auto CPPI = Cpp::Interpreter(std::move(I));
337+
auto* ExtInterp = &CPPI;
333338
#endif // CPPINTEROP_USE_REPL
334339

335340
#ifdef CPPINTEROP_USE_CLING
@@ -346,12 +351,9 @@ if (llvm::sys::RunningOnValgrind())
346351

347352
EXPECT_NE(ExtInterp, nullptr);
348353

349-
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
350-
#ifndef _WIN32 // Windows seems to fail to die...
351-
EXPECT_DEATH(Cpp::UseExternalInterpreter(ExtInterp), "sInterpreter already in use!");
352-
#endif // _WIN32
353-
#endif
354-
EXPECT_TRUE(Cpp::GetInterpreter()) << "External Interpreter not set";
354+
Cpp::UseExternalInterpreter(ExtInterp);
355+
EXPECT_EQ(ExtInterp, Cpp::GetInterpreter());
356+
EXPECT_EQ(ExtInterp, Cpp::TakeInterpreter(ExtInterp));
355357

356358
#ifndef CPPINTEROP_USE_CLING
357359
I.release();
@@ -366,14 +368,15 @@ TEST(InterpreterTest, MultipleInterpreter) {
366368
#if CLANG_VERSION_MAJOR < 20 && defined(EMSCRIPTEN)
367369
GTEST_SKIP() << "Test fails for Emscipten LLVM 20 builds";
368370
#endif
369-
370-
EXPECT_TRUE(Cpp::CreateInterpreter());
371+
auto* I = Cpp::CreateInterpreter();
372+
EXPECT_TRUE(I);
371373
Cpp::Declare(R"(
372374
void f() {}
373375
)");
374376
Cpp::TCppScope_t f = Cpp::GetNamed("f");
375377

376-
EXPECT_TRUE(Cpp::CreateInterpreter());
378+
auto* I2 = Cpp::CreateInterpreter();
379+
EXPECT_TRUE(I2);
377380
Cpp::Declare(R"(
378381
void ff() {}
379382
)");

0 commit comments

Comments
 (0)