diff --git a/lib/.clang-tidy b/lib/.clang-tidy new file mode 100644 index 000000000..4b09e2878 --- /dev/null +++ b/lib/.clang-tidy @@ -0,0 +1,2 @@ +Checks: > + -cppcoreguidelines-avoid-non-const-global-variables diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index b6cf555e8..3129a395e 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -65,11 +65,14 @@ #include #include #include +#include #include #include #include #include +#include #include +#include // Stream redirect. #ifdef _WIN32 @@ -92,9 +95,15 @@ using namespace clang; using namespace llvm; using namespace std; +#define LOCK(InterpInfo) \ + std::lock_guard interop_lock( \ + (InterpInfo).InterpreterLock) + struct InterpreterInfo { compat::Interpreter* Interpreter = nullptr; bool isOwned = true; + std::recursive_mutex InterpreterLock; + InterpreterInfo(compat::Interpreter* I, bool Owned) : Interpreter(I), isOwned(Owned) {} @@ -130,15 +139,54 @@ struct InterpreterInfo { }; // std::deque avoids relocations and calling the dtor of InterpreterInfo. -static llvm::ManagedStatic> sInterpreters; +static llvm::ManagedStatic>> + sInterpreters; +static llvm::ManagedStatic< + std::unordered_map>> + sInterpreterASTMap; +static std::mutex InterpreterStackLock; + +static InterpreterInfo& getInterpInfo() { + std::unique_lock Lock(InterpreterStackLock); + assert(!sInterpreters->empty() && + "Interpreter instance must be set before calling this!"); + return *sInterpreters->back(); +} +static InterpreterInfo& getInterpInfo(const clang::Decl* D) { + if (!D) + return getInterpInfo(); + if (sInterpreters->size() == 1) + return *sInterpreters->back(); + return *(*sInterpreterASTMap)[&D->getASTContext()].lock(); +} static compat::Interpreter& getInterp() { + std::unique_lock Lock(InterpreterStackLock); assert(!sInterpreters->empty() && "Interpreter instance must be set before calling this!"); - return *sInterpreters->back().Interpreter; + return *sInterpreters->back()->Interpreter; +} +static compat::Interpreter& getInterp(const clang::Decl* D) { + if (!D) + return getInterp(); + if (sInterpreters->size() == 1) + return *sInterpreters->back()->Interpreter; + return *(*sInterpreterASTMap)[&D->getASTContext()].lock()->Interpreter; } + static clang::Sema& getSema() { return getInterp().getCI()->getSema(); } +static clang::Sema& getSema(const clang::Decl* D) { + if (!D) + return getSema(); + return getInterpInfo(D).Interpreter->getSema(); +} + static clang::ASTContext& getASTContext() { return getSema().getASTContext(); } +static clang::ASTContext& getASTContext(const clang::Decl* D) { + if (!D) + return getASTContext(); + return getSema(D).getASTContext(); +} static void ForceCodeGen(Decl* D, compat::Interpreter& I) { // The decl was deferred by CodeGen. Force its emission. @@ -266,21 +314,31 @@ std::string Demangle(const std::string& mangled_name) { return demangle; } -void EnableDebugOutput(bool value /* =true*/) { llvm::DebugFlag = value; } +void EnableDebugOutput(bool value /* =true*/) { + // TODO: This should be locked under a global LLVM lock + LOCK(getInterpInfo()); + llvm::DebugFlag = value; +} -bool IsDebugOutputEnabled() { return llvm::DebugFlag; } +bool IsDebugOutputEnabled() { + // TODO: This should be locked under a global LLVM lock + LOCK(getInterpInfo()); + return llvm::DebugFlag; +} static void InstantiateFunctionDefinition(Decl* D) { - compat::SynthesizingCodeRAII RAII(&getInterp()); if (auto* FD = llvm::dyn_cast_or_null(D)) { - getSema().InstantiateFunctionDefinition(SourceLocation(), FD, - /*Recursive=*/true, - /*DefinitionRequired=*/true); + LOCK(getInterpInfo(FD)); + compat::SynthesizingCodeRAII RAII(&getInterp(FD)); + getSema(FD).InstantiateFunctionDefinition(SourceLocation(), FD, + /*Recursive=*/true, + /*DefinitionRequired=*/true); } } bool IsAggregate(TCppScope_t scope) { Decl* D = static_cast(scope); + LOCK(getInterpInfo(D)); // Aggregates are only arrays or tag decls. if (ValueDecl* ValD = dyn_cast(D)) @@ -316,9 +374,11 @@ bool IsFunctionPointerType(TCppType_t type) { bool IsClassPolymorphic(TCppScope_t klass) { Decl* D = static_cast(klass); - if (auto* CXXRD = llvm::dyn_cast(D)) + if (auto* CXXRD = llvm::dyn_cast(D)) { + LOCK(getInterpInfo(CXXRD)); if (auto* CXXRDD = CXXRD->getDefinition()) return CXXRDD->isPolymorphic(); + } return false; } @@ -334,12 +394,13 @@ bool IsComplete(TCppScope_t scope) { Decl* D = static_cast(scope); + LOCK(getInterpInfo(D)); if (isa(D)) { QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(scope)); - clang::Sema& S = getSema(); + clang::Sema& S = getSema(D); SourceLocation fakeLoc = GetValidSLoc(S); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(&getInterp(D)); #endif // CPPINTEROP_USE_CLING return S.isCompleteType(fakeLoc, QT); } @@ -359,6 +420,7 @@ size_t SizeOf(TCppScope_t scope) { return 0; if (auto* RD = dyn_cast(static_cast(scope))) { + LOCK(getInterpInfo(RD)); ASTContext& Context = RD->getASTContext(); const ASTRecordLayout& Layout = Context.getASTRecordLayout(RD); return Layout.getSize().getQuantity(); @@ -392,8 +454,10 @@ bool IsTypedefed(TCppScope_t handle) { bool IsAbstract(TCppType_t klass) { auto* D = (clang::Decl*)klass; - if (auto* CXXRD = llvm::dyn_cast_or_null(D)) + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(CXXRD)); return CXXRD->isAbstract(); + } return false; } @@ -427,6 +491,7 @@ static bool isSmartPointer(const RecordType* RT) { }; const RecordDecl* Record = RT->getDecl(); + LOCK(getInterpInfo(Record)); if (IsUseCountPresent(Record)) return true; @@ -494,6 +559,7 @@ std::vector GetEnumConstants(TCppScope_t handle) { auto* D = (clang::Decl*)handle; if (auto* ED = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(ED)); std::vector enum_constants; for (auto* ECD : ED->enumerators()) { enum_constants.push_back((TCppScope_t)ECD); @@ -531,7 +597,8 @@ size_t GetSizeOfType(TCppType_t type) { return SizeOf(TT->getDecl()); // FIXME: Can we get the size of a non-tag type? - auto TI = getSema().getASTContext().getTypeInfo(QT); + auto TI = getSema().getASTContext().getTypeInfo( + QT); // FIXME: is this the corrent sema? size_t TypeSize = TI.Width; return TypeSize / 8; } @@ -556,8 +623,8 @@ std::string GetName(TCppType_t klass) { } std::string GetCompleteName(TCppType_t klass) { - auto& C = getSema().getASTContext(); auto* D = (Decl*)klass; + auto& C = getSema(D).getASTContext(); PrintingPolicy Policy = C.getPrintingPolicy(); Policy.SuppressUnwrittenScope = true; @@ -607,8 +674,8 @@ std::string GetQualifiedName(TCppType_t klass) { // FIXME: Figure out how to merge with GetCompleteName. std::string GetQualifiedCompleteName(TCppType_t klass) { - auto& C = getSema().getASTContext(); auto* D = (Decl*)klass; + auto& C = getSema(D).getASTContext(); if (auto* ND = llvm::dyn_cast_or_null(D)) { if (auto* TD = llvm::dyn_cast(ND)) { @@ -637,6 +704,7 @@ std::vector GetUsingNamespaces(TCppScope_t scope) { auto* D = (clang::Decl*)scope; if (auto* DC = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(D)); std::vector namespaces; for (auto UD : DC->using_directives()) { namespaces.push_back((TCppScope_t)UD->getNominatedNamespace()); @@ -724,13 +792,14 @@ TCppScope_t GetScopeFromCompleteName(const std::string& name) { TCppScope_t GetNamed(const std::string& name, TCppScope_t parent /*= nullptr*/) { clang::DeclContext* Within = 0; + auto* D = static_cast(parent); + LOCK(getInterpInfo(D)); if (parent) { - auto* D = (clang::Decl*)parent; D = GetUnderlyingScope(D); Within = llvm::dyn_cast(D); } - auto* ND = Cpp_utils::Lookup::Named(&getSema(), name, Within); + auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); if (ND && ND != (clang::NamedDecl*)-1) { return (TCppScope_t)(ND->getCanonicalDecl()); } @@ -760,10 +829,13 @@ TCppScope_t GetParentScope(TCppScope_t scope) { TCppIndex_t GetNumBases(TCppScope_t klass) { auto* D = (Decl*)klass; - if (auto* CTSD = llvm::dyn_cast_or_null(D)) + if (auto* CTSD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(CTSD)); if (!CTSD->hasDefinition()) - compat::InstantiateClassTemplateSpecialization(getInterp(), CTSD); + compat::InstantiateClassTemplateSpecialization(getInterp(CTSD), CTSD); + } if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(CXXRD)); if (CXXRD->hasDefinition()) return CXXRD->getNumBases(); } @@ -774,8 +846,12 @@ TCppIndex_t GetNumBases(TCppScope_t klass) { TCppScope_t GetBaseClass(TCppScope_t klass, TCppIndex_t ibase) { auto* D = (Decl*)klass; auto* CXXRD = llvm::dyn_cast_or_null(D); - if (!CXXRD || CXXRD->getNumBases() <= ibase) - return 0; + if (!CXXRD) + return nullptr; + + LOCK(getInterpInfo(CXXRD)); + if (CXXRD->getNumBases() <= ibase) + return nullptr; auto type = (CXXRD->bases_begin() + ibase)->getType(); if (auto RT = type->getAs()) @@ -864,12 +940,15 @@ int64_t GetBaseClassOffset(TCppScope_t derived, TCppScope_t base) { return -1; CXXRecordDecl* DCXXRD = cast(DD); CXXRecordDecl* BCXXRD = cast(BD); + + LOCK(getInterpInfo(DD)); + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); DCXXRD->isDerivedFrom(BCXXRD, Paths); // FIXME: We might want to cache these requests as they seem expensive. - return ComputeBaseOffset(getSema().getASTContext(), DCXXRD, Paths.front()); + return ComputeBaseOffset(getSema(DD).getASTContext(), DCXXRD, Paths.front()); } template @@ -879,6 +958,7 @@ static void GetClassDecls(TCppScope_t klass, return; auto* D = (clang::Decl*)klass; + LOCK(getInterpInfo(D)); if (auto* TD = dyn_cast(D)) D = GetScopeFromType(TD->getUnderlyingType()); @@ -888,11 +968,11 @@ static void GetClassDecls(TCppScope_t klass, auto* CXXRD = dyn_cast(D); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(&getInterp(CXXRD)); #endif // CPPINTEROP_USE_CLING if (CXXRD->hasDefinition()) CXXRD = CXXRD->getDefinition(); - getSema().ForceDeclarationOfImplicitMembers(CXXRD); + getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); for (Decl* DI : CXXRD->decls()) { if (auto* MD = dyn_cast(DI)) methods.push_back(MD); @@ -918,7 +998,7 @@ static void GetClassDecls(TCppScope_t klass, // Result is appended to the decls, i.e. CXXRD, iterator // non-shadowed decl will be push_back later // methods.push_back(Result); - getSema().findInheritingConstructor(SourceLocation(), CXXCD, CUSD); + getSema(CXXRD).findInheritingConstructor(SourceLocation(), CXXCD, CUSD); } } } @@ -935,8 +1015,10 @@ void GetFunctionTemplatedDecls(TCppScope_t klass, bool HasDefaultConstructor(TCppScope_t scope) { auto* D = (clang::Decl*)scope; - if (auto* CXXRD = llvm::dyn_cast_or_null(D)) + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(CXXRD)); return CXXRD->hasDefaultConstructor(); + } return false; } @@ -947,18 +1029,21 @@ TCppFunction_t GetDefaultConstructor(compat::Interpreter& interp, return nullptr; auto* CXXRD = (clang::CXXRecordDecl*)scope; + LOCK(getInterpInfo(CXXRD)); return interp.getCI()->getSema().LookupDefaultConstructor(CXXRD); } TCppFunction_t GetDefaultConstructor(TCppScope_t scope) { - return GetDefaultConstructor(getInterp(), scope); + auto* CXXRD = static_cast(scope); + return GetDefaultConstructor(getInterp(CXXRD), scope); } TCppFunction_t GetDestructor(TCppScope_t scope) { auto* D = (clang::Decl*)scope; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - getSema().ForceDeclarationOfImplicitMembers(CXXRD); + LOCK(getInterpInfo(CXXRD)); + getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); return CXXRD->getDestructor(); } @@ -977,12 +1062,14 @@ std::vector GetFunctionsUsingName(TCppScope_t scope, if (!scope || name.empty()) return {}; + LOCK(getInterpInfo(D)); + D = GetUnderlyingScope(D); std::vector funcs; llvm::StringRef Name(name); - auto& S = getSema(); - DeclarationName DName = &getASTContext().Idents.get(name); + auto& S = getSema(D); + DeclarationName DName = &S.getASTContext().Idents.get(name); clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, For_Visible_Redeclaration); @@ -1003,6 +1090,7 @@ std::vector GetFunctionsUsingName(TCppScope_t scope, TCppType_t GetFunctionReturnType(TCppFunction_t func) { auto* D = (clang::Decl*)func; if (auto* FD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(FD)); QualType Type = FD->getReturnType(); if (Type->isUndeducedAutoType()) { bool needInstantiation = false; @@ -1021,8 +1109,10 @@ TCppType_t GetFunctionReturnType(TCppFunction_t func) { return Type.getAsOpaquePtr(); } - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (auto* FD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(FD)); return (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr(); + } return 0; } @@ -1050,9 +1140,9 @@ TCppIndex_t GetFunctionRequiredArgs(TCppConstFunction_t func) { } TCppType_t GetFunctionArgType(TCppFunction_t func, TCppIndex_t iarg) { - auto* D = (clang::Decl*)func; - + auto* D = static_cast(func); if (auto* FD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(FD)); if (iarg < FD->getNumParams()) { auto* PVD = FD->getParamDecl(iarg); return PVD->getOriginalType().getAsOpaquePtr(); @@ -1078,7 +1168,7 @@ std::string GetFunctionSignature(TCppFunction_t func) { std::string Signature; raw_string_ostream SS(Signature); - PrintingPolicy Policy = getASTContext().getPrintingPolicy(); + PrintingPolicy Policy = getASTContext(D).getPrintingPolicy(); // Skip printing the body Policy.TerseOutput = true; Policy.FullyQualifiedName = true; @@ -1125,12 +1215,14 @@ bool IsTemplatedFunction(TCppFunction_t func) { // the template function exists and >1 means overloads bool ExistsFunctionTemplate(const std::string& name, TCppScope_t parent) { DeclContext* Within = 0; + auto* D = (Decl*)parent; if (parent) { - auto* D = (Decl*)parent; Within = llvm::dyn_cast(D); } - auto* ND = Cpp_utils::Lookup::Named(&getSema(), name, Within); + LOCK(getInterpInfo(D)); + + auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); if ((intptr_t)ND == (intptr_t)0) return false; @@ -1149,8 +1241,10 @@ void LookupConstructors(const std::string& name, TCppScope_t parent, auto* D = (Decl*)parent; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - getSema().ForceDeclarationOfImplicitMembers(CXXRD); - DeclContextLookupResult Result = getSema().LookupConstructors(CXXRD); + LOCK(getInterpInfo(CXXRD)); + + getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); + DeclContextLookupResult Result = getSema(CXXRD).LookupConstructors(CXXRD); // Obtaining all constructors when we intend to lookup a method under a // scope can lead to crashes. We avoid that by accumulating constructors // only if the Decl matches the lookup name. @@ -1166,12 +1260,14 @@ bool GetClassTemplatedMethods(const std::string& name, TCppScope_t parent, if (!D && name.empty()) return false; + LOCK(getInterpInfo(D)); + // Accumulate constructors LookupConstructors(name, parent, funcs); - auto& S = getSema(); + auto& S = getSema(D); D = GetUnderlyingScope(D); llvm::StringRef Name(name); - DeclarationName DName = &getASTContext().Idents.get(name); + DeclarationName DName = &S.getASTContext().Idents.get(name); clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, For_Visible_Redeclaration); auto* DC = clang::Decl::castToDeclContext(D); @@ -1207,11 +1303,16 @@ TCppFunction_t BestOverloadFunctionMatch(const std::vector& candidates, const std::vector& explicit_types, const std::vector& arg_types) { - auto& S = getSema(); + if (candidates.empty()) + return nullptr; + InterpreterInfo& II = getInterpInfo(static_cast(candidates[0])); + LOCK(II); + + auto& S = II.Interpreter->getSema(); auto& C = S.getASTContext(); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(II.Interpreter); #endif // The overload resolution interfaces in Sema require a list of expressions. @@ -1330,6 +1431,7 @@ bool IsDestructor(TCppConstFunction_t method) { bool IsStaticMethod(TCppConstFunction_t method) { const auto* D = static_cast(method); if (auto* CXXMD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(D)); return CXXMD->isStatic(); } @@ -1349,7 +1451,7 @@ TCppFuncAddr_t GetFunctionAddress(const char* mangled_name) { static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { const auto get_mangled_name = [](const FunctionDecl* FD) { - auto MangleCtxt = getASTContext().createMangleContext(); + auto MangleCtxt = getASTContext(FD).createMangleContext(); if (!MangleCtxt->shouldMangleDeclName(FD)) { return FD->getNameInfo().getName().getAsString(); @@ -1376,6 +1478,7 @@ static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { auto* D = static_cast(method); if (auto* FD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(FD)); if ((IsTemplateInstantiationOrSpecialization(FD) || FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) && !FD->getDefinition()) @@ -1391,6 +1494,7 @@ TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { bool IsVirtualMethod(TCppFunction_t method) { auto* D = (Decl*)method; if (auto* CXXMD = llvm::dyn_cast_or_null(D)) { + LOCK(getInterpInfo(CXXMD)); return CXXMD->isVirtual(); } @@ -1401,7 +1505,9 @@ void GetDatamembers(TCppScope_t scope, std::vector& datamembers) { auto* D = (Decl*)scope; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - getSema().ForceDeclarationOfImplicitMembers(CXXRD); + LOCK(getInterpInfo(CXXRD)); + + getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); if (CXXRD->hasDefinition()) CXXRD = CXXRD->getDefinition(); @@ -1448,6 +1554,11 @@ void GetEnumConstantDatamembers(TCppScope_t scope, bool include_enum_class) { std::vector EDs; GetClassDecls(scope, EDs); + if (EDs.empty()) + return; + + LOCK(getInterpInfo(static_cast(EDs[0]))); + for (TCppScope_t i : EDs) { auto* ED = static_cast(i); @@ -1462,12 +1573,13 @@ void GetEnumConstantDatamembers(TCppScope_t scope, TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent) { clang::DeclContext* Within = 0; + auto* D = static_cast(parent); if (parent) { - auto* D = (clang::Decl*)parent; Within = llvm::dyn_cast(D); } - auto* ND = Cpp_utils::Lookup::Named(&getSema(), name, Within); + LOCK(getInterpInfo(D)); + auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); if (ND && ND != (clang::NamedDecl*)-1) { if (llvm::isa_and_nonnull(ND)) { return (TCppScope_t)ND; @@ -1509,9 +1621,6 @@ TCppType_t GetVariableType(TCppScope_t var) { intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, CXXRecordDecl* BaseCXXRD) { - if (!D) - return 0; - auto& C = I.getSema().getASTContext(); if (auto* FD = llvm::dyn_cast(D)) { @@ -1586,9 +1695,9 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, if (!address) { if (!VD->hasInit()) { #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(&getInterp(VD)); #endif // CPPINTEROP_USE_CLING - getSema().InstantiateVariableDefinition(SourceLocation(), VD); + getSema(VD).InstantiateVariableDefinition(SourceLocation(), VD); VD = VD->getDefinition(); } if (VD->hasInit() && @@ -1619,8 +1728,11 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, intptr_t GetVariableOffset(TCppScope_t var, TCppScope_t parent) { auto* D = static_cast(var); + if (!D) + return 0; + LOCK(getInterpInfo(D)); auto* RD = llvm::dyn_cast_or_null(static_cast(parent)); - return GetVariableOffset(getInterp(), D, RD); + return GetVariableOffset(getInterp(D), D, RD); } // Check if the Access Specifier of the variable matches the provided value. @@ -1643,11 +1755,7 @@ bool IsPrivateVariable(TCppScope_t var) { bool IsStaticVariable(TCppScope_t var) { auto* D = (Decl*)var; - if (llvm::isa_and_nonnull(D)) { - return true; - } - - return false; + return llvm::isa_and_nonnull(D); } bool IsConstVariable(TCppScope_t var) { @@ -1671,7 +1779,7 @@ bool IsPODType(TCppType_t type) { if (QT.isNull()) return false; - return QT.isPODType(getASTContext()); + return QT.isPODType(getASTContext()); // FIXME: which ASTContext? } bool IsPointerType(TCppType_t type) { @@ -1703,13 +1811,17 @@ bool IsRValueReferenceType(TCppType_t type) { TCppType_t GetPointerType(TCppType_t type) { QualType QT = QualType::getFromOpaquePtr(type); - return getASTContext().getPointerType(QT).getAsOpaquePtr(); + return getASTContext() + .getPointerType(QT) + .getAsOpaquePtr(); // FIXME: which ASTContext? } TCppType_t GetReferencedType(TCppType_t type, bool rvalue) { QualType QT = QualType::getFromOpaquePtr(type); if (rvalue) - return getASTContext().getRValueReferenceType(QT).getAsOpaquePtr(); + return getASTContext() + .getRValueReferenceType(QT) + .getAsOpaquePtr(); // FIXME: which ASTContext? return getASTContext().getLValueReferenceType(QT).getAsOpaquePtr(); } @@ -1881,6 +1993,7 @@ TCppType_t GetType(const std::string& name) { if (!builtin.isNull()) return builtin.getAsOpaquePtr(); + LOCK(getInterpInfo()); auto* D = (Decl*)GetNamed(name, /* Within= */ 0); if (auto* TD = llvm::dyn_cast_or_null(D)) { return QualType(TD->getTypeForDecl(), 0).getAsOpaquePtr(); @@ -1892,7 +2005,10 @@ TCppType_t GetType(const std::string& name) { TCppType_t GetComplexType(TCppType_t type) { QualType QT = QualType::getFromOpaquePtr(type); - return getASTContext().getComplexType(QT).getAsOpaquePtr(); + LOCK(getInterpInfo()); // FIXME: Which interpreter to lock? + return getASTContext() + .getComplexType(QT) + .getAsOpaquePtr(); // FIXME: which ASTContext? } TCppType_t GetTypeFromScope(TCppScope_t klass) { @@ -1900,7 +2016,7 @@ TCppType_t GetTypeFromScope(TCppScope_t klass) { return 0; auto* D = (Decl*)klass; - ASTContext& C = getASTContext(); + ASTContext& C = getASTContext(D); if (ValueDecl* VD = dyn_cast(D)) return VD->getType().getAsOpaquePtr(); @@ -2291,8 +2407,8 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type, // available, while there is a move constructor. // include utility header if not already included for std::move - DeclarationName DMove = &getASTContext().Idents.get("move"); - auto result = getSema().getStdNamespace()->lookup(DMove); + DeclarationName DMove = &getASTContext(FD).Idents.get("move"); + auto result = getSema(FD).getStdNamespace()->lookup(DMove); if (result.empty()) Cpp::Declare("#include "); @@ -2505,6 +2621,8 @@ void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD, int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, std::string& wrapper_name, std::string& wrapper) { assert(FD && "generate_wrapper called without a function decl!"); + LOCK(getInterpInfo(FD)); + ASTContext& Context = FD->getASTContext(); // // Get the class or namespace name. @@ -2925,6 +3043,8 @@ JitCall::GenericCall make_wrapper(compat::Interpreter& I, const FunctionDecl* FD) { static std::map gWrapperStore; + LOCK(getInterpInfo(FD)); + auto R = gWrapperStore.find(FD); if (R != gWrapperStore.end()) return (JitCall::GenericCall)R->second; @@ -3017,6 +3137,8 @@ static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp, static map gDtorWrapperStore; + LOCK(getInterpInfo(D)); + auto I = gDtorWrapperStore.find(D); if (I != gDtorWrapperStore.end()) return (JitCall::DestructorCall)I->second; @@ -3165,7 +3287,8 @@ CPPINTEROP_API JitCall MakeFunctionCallable(TInterp_t I, } CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { - return MakeFunctionCallable(&getInterp(), func); + const auto* D = static_cast(func); + return MakeFunctionCallable(&getInterp(D), func); } namespace { @@ -3196,6 +3319,7 @@ static std::string MakeResourcesPath() { TInterp_t CreateInterpreter(const std::vector& Args /*={}*/, const std::vector& GpuArgs /*={}*/) { + std::unique_lock Lock(InterpreterStackLock); std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr); std::string ResourceDir = MakeResourcesPath(); std::vector ClingArgv = {"-resource-dir", ResourceDir.c_str(), @@ -3271,34 +3395,50 @@ TInterp_t CreateInterpreter(const std::vector& Args /*={}*/, } // namespace __internal_CppInterOp )"); - sInterpreters->emplace_back(I, /*Owned=*/true); + sInterpreters->emplace_back( + std::make_shared(I, /*Owned=*/true)); + sInterpreterASTMap->insert( + {&sInterpreters->back()->Interpreter->getSema().getASTContext(), + sInterpreters->back()}); return I; } bool DeleteInterpreter(TInterp_t I /*=nullptr*/) { + std::unique_lock Lock(InterpreterStackLock); + if (!I) { + auto foundAST = std::find_if( + sInterpreterASTMap->begin(), sInterpreterASTMap->end(), + [](const auto& Item) { return Item.second.lock() == sInterpreters->back(); }); + sInterpreterASTMap->erase(foundAST); sInterpreters->pop_back(); return true; } auto found = std::find_if(sInterpreters->begin(), sInterpreters->end(), - [&I](const auto& Info) { return Info.Interpreter == I; }); + [&I](const auto& Info) { return Info->Interpreter == I; }); if (found == sInterpreters->end()) return false; // failure + auto foundAST = std::find_if( + sInterpreterASTMap->begin(), sInterpreterASTMap->end(), + [&found](const auto& Item) { return Item.second.lock() == *found; }); + sInterpreterASTMap->erase(foundAST); sInterpreters->erase(found); return true; } bool ActivateInterpreter(TInterp_t I) { + std::unique_lock Lock(InterpreterStackLock); + if (!I) return false; auto found = std::find_if(sInterpreters->begin(), sInterpreters->end(), - [&I](const auto& Info) { return Info.Interpreter == I; }); + [&I](const auto& Info) { return Info->Interpreter == I; }); if (found == sInterpreters->end()) return false; @@ -3309,18 +3449,22 @@ bool ActivateInterpreter(TInterp_t I) { } TInterp_t GetInterpreter() { + std::unique_lock Lock(InterpreterStackLock); if (sInterpreters->empty()) return nullptr; - return sInterpreters->back().Interpreter; + return sInterpreters->back()->Interpreter; } void UseExternalInterpreter(TInterp_t I) { + std::unique_lock Lock(InterpreterStackLock); assert(sInterpreters->empty() && "sInterpreter already in use!"); - sInterpreters->emplace_back(static_cast(I), - /*isOwned=*/false); + sInterpreters->emplace_back( + std::make_shared(static_cast(I), + /*isOwned=*/false)); } void AddSearchPath(const char* dir, bool isUser, bool prepend) { + LOCK(getInterpInfo()); getInterp().getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend); } @@ -3384,7 +3528,10 @@ void DetectSystemCompilerIncludePaths(std::vector& Paths, exec(cmd.c_str(), Paths); } -void AddIncludePath(const char* dir) { getInterp().AddIncludePath(dir); } +void AddIncludePath(const char* dir) { + LOCK(getInterpInfo()); + getInterp().AddIncludePath(dir); +} void GetIncludePaths(std::vector& IncludePaths, bool withSystem, bool withFlags) { @@ -3421,10 +3568,14 @@ int Declare(compat::Interpreter& I, const char* code, bool silent) { } int Declare(const char* code, bool silent) { + LOCK(getInterpInfo()); return Declare(getInterp(), code, silent); } -int Process(const char* code) { return getInterp().process(code); } +int Process(const char* code) { + LOCK(getInterpInfo()); + return getInterp().process(code); +} intptr_t Evaluate(const char* code, bool* HadError /*=nullptr*/) { #ifdef CPPINTEROP_USE_CLING @@ -3436,6 +3587,7 @@ intptr_t Evaluate(const char* code, bool* HadError /*=nullptr*/) { if (HadError) *HadError = false; + LOCK(getInterpInfo()); auto res = getInterp().evaluate(code, V); if (res != 0) { // 0 is success if (HadError) @@ -3452,6 +3604,7 @@ std::string LookupLibrary(const char* lib_name) { } bool LoadLibrary(const char* lib_stem, bool lookup) { + LOCK(getInterpInfo()); compat::Interpreter::CompilationResult res = getInterp().loadLibrary(lib_stem, lookup); @@ -3459,11 +3612,13 @@ bool LoadLibrary(const char* lib_stem, bool lookup) { } void UnloadLibrary(const char* lib_stem) { + LOCK(getInterpInfo()); getInterp().getDynamicLibraryManager()->unloadLibrary(lib_stem); } std::string SearchLibrariesForSymbol(const char* mangled_name, bool search_system /*true*/) { + LOCK(getInterpInfo()); auto* DLM = getInterp().getDynamicLibraryManager(); return DLM->searchLibrariesForSymbol(mangled_name, search_system); } @@ -3549,16 +3704,20 @@ bool InsertOrReplaceJitSymbol(compat::Interpreter& I, bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, uint64_t address) { + LOCK(getInterpInfo()); return InsertOrReplaceJitSymbol(getInterp(), linker_mangled_name, address); } std::string ObjToString(const char* type, void* obj) { + LOCK(getInterpInfo()); // FIXME: not enough information to lock the corrent + // interpreter return getInterp().toString(type, obj); } -static Decl* InstantiateTemplate(TemplateDecl* TemplateD, - TemplateArgumentListInfo& TLI, Sema& S, - bool instantiate_body) { +Decl* InstantiateTemplate(TemplateDecl* TemplateD, + TemplateArgumentListInfo& TLI, Sema& S, + bool instantiate_body) { + LOCK(getInterpInfo()); // This is not right but we don't have a lot of options to choose from as a // template instantiation requires a valid source location. SourceLocation fakeLoc = GetValidSLoc(S); @@ -3653,13 +3812,16 @@ TCppScope_t InstantiateTemplate(TCppScope_t tmpl, const TemplateArgInfo* template_args, size_t template_args_size, bool instantiate_body) { - return InstantiateTemplate(getInterp(), tmpl, template_args, + auto* D = static_cast(tmpl); + LOCK(getInterpInfo(D)); + return InstantiateTemplate(getInterp(D), tmpl, template_args, template_args_size, instantiate_body); } void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance, std::vector& args) { auto* CTSD = static_cast(templ_instance); + LOCK(getInterpInfo(CTSD)); for (const auto& TA : CTSD->getTemplateInstantiationArgs().asArray()) { switch (TA.getKind()) { default: @@ -3691,6 +3853,7 @@ InstantiateTemplateFunctionFromString(const char* function_template) { std::string id = "__Cppyy_GetMethTmpl_" + std::to_string(var_count++); std::string instance = "auto " + id + " = " + function_template + ";\n"; + LOCK(getInterpInfo()); if (!Cpp::Declare(instance.c_str(), /*silent=*/false)) { VarDecl* VD = (VarDecl*)Cpp::GetNamed(id, 0); DeclRefExpr* DRE = (DeclRefExpr*)VD->getInit()->IgnoreImpCasts(); @@ -3704,6 +3867,7 @@ void GetAllCppNames(TCppScope_t scope, std::set& names) { clang::DeclContext* DC; clang::DeclContext::decl_iterator decl; + LOCK(getInterpInfo(D)); if (auto* TD = dyn_cast_or_null(D)) { DC = clang::TagDecl::castToDeclContext(TD); decl = DC->decls_begin(); @@ -3733,6 +3897,7 @@ void GetEnums(TCppScope_t scope, std::vector& Result) { auto* DC = llvm::dyn_cast(D); + LOCK(getInterpInfo(D)); llvm::SmallVector DCs; DC->collectAllContexts(DCs); @@ -3775,13 +3940,15 @@ std::vector GetDimensions(TCppType_t type) { } bool IsTypeDerivedFrom(TCppType_t derived, TCppType_t base) { - auto& S = getSema(); - auto fakeLoc = GetValidSLoc(S); auto derivedType = clang::QualType::getFromOpaquePtr(derived); auto baseType = clang::QualType::getFromOpaquePtr(base); + auto* CXXRD = baseType->getAsRecordDecl(); + LOCK(getInterpInfo(CXXRD)); + auto& S = getSema(CXXRD); + auto fakeLoc = GetValidSLoc(S); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp()); + cling::Interpreter::PushTransactionRAII RAII(&getInterp(CXXRD)); #endif return S.IsDerivedFrom(fakeLoc, derivedType, baseType); } @@ -3791,6 +3958,7 @@ std::string GetFunctionArgDefault(TCppFunction_t func, auto* D = (clang::Decl*)func; clang::ParmVarDecl* PI = nullptr; + LOCK(getInterpInfo(D)); if (auto* FD = llvm::dyn_cast_or_null(D)) PI = FD->getParamDecl(param_index); @@ -3886,6 +4054,7 @@ OperatorArity GetOperatorArity(TCppFunction_t op) { void GetOperator(TCppScope_t scope, Operator op, std::vector& operators, OperatorArity kind) { Decl* D = static_cast(scope); + LOCK(getInterpInfo(D)); if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { auto fn = [&operators, kind, op](const RecordDecl* RD) { ASTContext& C = RD->getASTContext(); @@ -3901,7 +4070,7 @@ void GetOperator(TCppScope_t scope, Operator op, fn(CXXRD); CXXRD->forallBases(fn); } else if (auto* DC = llvm::dyn_cast_or_null(D)) { - ASTContext& C = getSema().getASTContext(); + ASTContext& C = getSema(D).getASTContext(); DeclContextLookupResult Result = DC->lookup(C.DeclarationNames.getCXXOperatorName( (clang::OverloadedOperatorKind)op)); @@ -3950,7 +4119,8 @@ TCppObject_t Construct(compat::Interpreter& interp, TCppScope_t scope, TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/, TCppIndex_t count /*=1UL*/) { - return Construct(getInterp(), scope, arena, count); + auto* D = static_cast(scope); + return Construct(getInterp(D), scope, arena, count); } bool Destruct(compat::Interpreter& interp, TCppObject_t This, const Decl* Class, @@ -3966,7 +4136,7 @@ bool Destruct(compat::Interpreter& interp, TCppObject_t This, const Decl* Class, bool Destruct(TCppObject_t This, TCppConstScope_t scope, bool withFree /*=true*/, TCppIndex_t count /*=0UL*/) { const auto* Class = static_cast(scope); - return Destruct(getInterp(), This, Class, withFree, count); + return Destruct(getInterp(Class), This, Class, withFree, count); } class StreamCaptureInfo { @@ -4070,6 +4240,8 @@ std::string EndStdStreamCapture() { void CodeComplete(std::vector& Results, const char* code, unsigned complete_line /* = 1U */, unsigned complete_column /* = 1U */) { + LOCK(getInterpInfo()); // FIXME: Not enough info to lock the corrent + // interpreter compat::codeComplete(Results, getInterp(), code, complete_line, complete_column); } diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index e9b82ea1d..7af49e6e9 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -361,3 +361,22 @@ if (llvm::sys::RunningOnValgrind()) delete ExtInterp; #endif } + +TEST(InterpreterTest, MultipleInterpreter) { + EXPECT_TRUE(Cpp::CreateInterpreter()); + Cpp::Declare(R"( + void f() {} + )"); + auto f = Cpp::GetNamed("f"); + + EXPECT_TRUE(Cpp::CreateInterpreter()); + Cpp::Declare(R"( + void ff() {} + )"); + auto ff = Cpp::GetNamed("ff"); + + auto f_callable = Cpp::MakeFunctionCallable(f); + EXPECT_EQ(f_callable.getKind(), Cpp::JitCall::Kind::kGenericCall); + auto ff_callable = Cpp::MakeFunctionCallable(ff); + EXPECT_EQ(ff_callable.getKind(), Cpp::JitCall::Kind::kGenericCall); +}