Skip to content

Commit a884dee

Browse files
authored
Merge pull request #1 from Vipul-Cariappa/mcbarton/Add-llvm-21-support
Mcbarton/add llvm 21 support
2 parents eaf352c + 71f02da commit a884dee

File tree

13 files changed

+744
-191
lines changed

13 files changed

+744
-191
lines changed

docs/DevelopersDocumentation.rst

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,12 +423,54 @@ library files and run pytest:
423423
python -m pip install pytest
424424
python -m pytest -sv
425425
426-
***********************************
426+
###################################
427427
CppInterOp Internal Documentation
428-
***********************************
428+
###################################
429429

430430
CppInterOp maintains an internal Doxygen documentation of its components.
431431
Internal documentation aims to capture intrinsic details and overall usage of
432432
code components. The goal of internal documentation is to make the codebase
433433
easier to understand for the new developers. Internal documentation can be
434434
visited : `here <build/html/index.html>`_
435+
436+
**************************************
437+
Multiple Interpreter & Thread-Safety
438+
**************************************
439+
440+
CppInterOp allows the user to create multiple interpreters at a time and
441+
use those interpreters. The interpreters that are created are stored in a
442+
stack and a map. The stack is used to enable the model where the user
443+
wants to create a temporary interpreter and destroy it after performing a
444+
few operations. In such a use case, the top of the stack is the only
445+
interpreter in use at any given point in time.
446+
447+
The map is used to store the mapping from :code:`clang::ASTContext` to
448+
:code:`Cpp::InterpreterInfo`. This is required to figure out which
449+
interpreter an object belongs to. Say the library user performs the
450+
following operations:
451+
452+
1. Create an Interpreter
453+
2. Compile some code with variable :code:`a`
454+
3. Create another Interpreter
455+
4. Performs :code:`Cpp::GetVariableOffset(a)`
456+
457+
In step 4, the top of the stack is an interpreter without the definition of
458+
:code:`a`. And we cannot use it to figure out the address of :code:`a`.
459+
The :code:`clang::Decl` passed to :code:`Cpp::GetVariableOffset` is used to
460+
retrieve the :code:`clang::ASTContext`, using
461+
:code:`clang::Decl::getASTContext`. We then use the map to figure out the
462+
exact Interpreter Instance this :code:`clang::Decl` belongs to and perform
463+
the operation.
464+
465+
A shortcoming of this is that if the CppInterOp accepts a
466+
:code:`clang::QualType` instead of :code:`clang::Decl`, then it is not
467+
possible to get the :code:`clang::ASTContext` from the :code:`clang::QualType`.
468+
In such cases, we iterate over the Allocator of all the Interpreters in our
469+
stack and figure out which :code:`clang::ASTContext` allocated this
470+
:code:`clang::QualType`. This is a very expensive operation. But there is no
471+
alternative to this.
472+
473+
For **thread-safety**, we introduce a lock for each of the interpreters we
474+
create. And lock only that one specific interpreter when required. We also
475+
have 2 global locks, one for LLVM, and another is used to lock operations
476+
performed on the interpreter stack and the map itself.

include/CppInterOp/CppInterOp.h

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ CPPINTEROP_API std::string GetQualifiedCompleteName(TCppScope_t klass);
389389
CPPINTEROP_API std::vector<TCppScope_t> GetUsingNamespaces(TCppScope_t scope);
390390

391391
/// Gets the global scope of the whole C++ instance.
392-
CPPINTEROP_API TCppScope_t GetGlobalScope();
392+
CPPINTEROP_API TCppScope_t GetGlobalScope(TInterp_t interp = nullptr);
393393

394394
/// Strips the typedef and returns the underlying class, and if the
395395
/// underlying decl is not a class it returns the input unchanged.
@@ -398,18 +398,28 @@ CPPINTEROP_API TCppScope_t GetUnderlyingScope(TCppScope_t scope);
398398
/// Gets the namespace or class (by stripping typedefs) for the name
399399
/// passed as a parameter, and if the parent is not passed,
400400
/// then global scope will be assumed.
401+
/// Looks up the name in parent, if parent is nullptr,
402+
/// interp is used to select the interpreter if multiple in-use.
403+
/// interp is ignored if parent is non-null.
401404
CPPINTEROP_API TCppScope_t GetScope(const std::string& name,
402-
TCppScope_t parent = nullptr);
405+
TCppScope_t parent = nullptr,
406+
TInterp_t interp = nullptr);
403407

404408
/// When the namespace is known, then the parent doesn't need
405409
/// to be specified. This will probably be phased-out in
406410
/// future versions of the interop library.
407-
CPPINTEROP_API TCppScope_t GetScopeFromCompleteName(const std::string& name);
411+
/// interp is used to select the interpreter if multiple in-use.
412+
CPPINTEROP_API TCppScope_t GetScopeFromCompleteName(const std::string& name,
413+
TInterp_t interp = nullptr);
408414

409415
/// This function performs a lookup within the specified parent,
410416
/// a specific named entity (functions, enums, etcetera).
417+
/// Looks up the name in parent, if parent is nullptr,
418+
/// interp is used to select the interpreter if multiple in-use.
419+
/// interp is ignored if parent is non-null.
411420
CPPINTEROP_API TCppScope_t GetNamed(const std::string& name,
412-
TCppScope_t parent = nullptr);
421+
TCppScope_t parent = nullptr,
422+
TInterp_t interp = nullptr);
413423

414424
/// Gets the parent of the scope that is passed as a parameter.
415425
CPPINTEROP_API TCppScope_t GetParentScope(TCppScope_t scope);
@@ -493,8 +503,12 @@ CPPINTEROP_API bool IsTemplatedFunction(TCppFunction_t func);
493503

494504
/// This function performs a lookup to check if there is a
495505
/// templated function of that type.
506+
/// Looks up the name in parent, if parent is nullptr,
507+
/// interp is used to select the interpreter if multiple in-use.
508+
/// interp is ignored if parent is non-null.
496509
CPPINTEROP_API bool ExistsFunctionTemplate(const std::string& name,
497-
TCppScope_t parent = nullptr);
510+
TCppScope_t parent = nullptr,
511+
TInterp_t interp = nullptr);
498512

499513
/// Sets a list of all the constructor for a scope/class that is
500514
/// supplied as a parameter.
@@ -542,7 +556,8 @@ CPPINTEROP_API bool IsDestructor(TCppConstFunction_t method);
542556
CPPINTEROP_API bool IsStaticMethod(TCppConstFunction_t method);
543557

544558
///\returns the address of the function given its potentially mangled name.
545-
CPPINTEROP_API TCppFuncAddr_t GetFunctionAddress(const char* mangled_name);
559+
CPPINTEROP_API TCppFuncAddr_t GetFunctionAddress(const char* mangled_name,
560+
TInterp_t interp = nullptr);
546561

547562
///\returns the address of the function given its function declaration.
548563
CPPINTEROP_API TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method);
@@ -643,7 +658,9 @@ CPPINTEROP_API TCppType_t GetCanonicalType(TCppType_t type);
643658

644659
/// Used to either get the built-in type of the provided string, or
645660
/// use the name to lookup the actual type.
646-
CPPINTEROP_API TCppType_t GetType(const std::string& type);
661+
/// interp is used to select the interpreter if multiple in-use.
662+
CPPINTEROP_API TCppType_t GetType(const std::string& type,
663+
TInterp_t interp = nullptr);
647664

648665
///\returns the complex of the provided type.
649666
CPPINTEROP_API TCppType_t GetComplexType(TCppType_t element_type);
@@ -702,6 +719,11 @@ CreateInterpreter(const std::vector<const char*>& Args = {},
702719
///\returns false on failure or if \c I is not tracked in the stack.
703720
CPPINTEROP_API bool DeleteInterpreter(TInterp_t I = nullptr);
704721

722+
/// Take ownership of an interpreter instance.
723+
///\param[in] I - the interpreter to be taken, if nullptr, returns the last.
724+
///\returns nullptr on failure or if \c I is not tracked in the stack.
725+
CPPINTEROP_API TInterp_t TakeInterpreter(TInterp_t I = nullptr);
726+
705727
/// Activates an instance of an interpreter to handle subsequent API requests
706728
///\param[in] I - the interpreter to be activated.
707729
///\returns false on failure.
@@ -722,10 +744,10 @@ CPPINTEROP_API void UseExternalInterpreter(TInterp_t I);
722744

723745
/// Adds a Search Path for the Interpreter to get the libraries.
724746
CPPINTEROP_API void AddSearchPath(const char* dir, bool isUser = true,
725-
bool prepend = false);
747+
bool prepend = false, TInterp_t I = nullptr);
726748

727749
/// Returns the resource-dir path (for headers).
728-
CPPINTEROP_API const char* GetResourceDir();
750+
CPPINTEROP_API const char* GetResourceDir(TInterp_t I = nullptr);
729751

730752
/// Uses the underlying clang compiler to detect the resource directory.
731753
/// In essence calling clang -print-resource-dir and checks if it ends with
@@ -746,46 +768,52 @@ DetectSystemCompilerIncludePaths(std::vector<std::string>& Paths,
746768

747769
/// Secondary search path for headers, if not found using the
748770
/// GetResourceDir() function.
749-
CPPINTEROP_API void AddIncludePath(const char* dir);
771+
CPPINTEROP_API void AddIncludePath(const char* dir, TInterp_t I = nullptr);
750772

751773
// Gets the currently used include paths
752774
///\param[out] IncludePaths - the list of include paths
753775
///
754776
CPPINTEROP_API void GetIncludePaths(std::vector<std::string>& IncludePaths,
755777
bool withSystem = false,
756-
bool withFlags = false);
778+
bool withFlags = false,
779+
TInterp_t I = nullptr);
757780

758781
/// Only Declares a code snippet in \c code and does not execute it.
759782
///\returns 0 on success
760-
CPPINTEROP_API int Declare(const char* code, bool silent = false);
783+
CPPINTEROP_API int Declare(const char* code, bool silent = false,
784+
TInterp_t I = nullptr);
761785

762786
/// Declares and executes a code snippet in \c code.
763787
///\returns 0 on success
764-
CPPINTEROP_API int Process(const char* code);
788+
CPPINTEROP_API int Process(const char* code, TInterp_t I = nullptr);
765789

766790
/// Declares, executes and returns the execution result as a intptr_t.
767791
///\returns the expression results as a intptr_t.
768-
CPPINTEROP_API intptr_t Evaluate(const char* code, bool* HadError = nullptr);
792+
CPPINTEROP_API intptr_t Evaluate(const char* code, bool* HadError = nullptr,
793+
TInterp_t I = nullptr);
769794

770795
/// Looks up the library if access is enabled.
771796
///\returns the path to the library.
772-
CPPINTEROP_API std::string LookupLibrary(const char* lib_name);
797+
CPPINTEROP_API std::string LookupLibrary(const char* lib_name,
798+
TInterp_t I = nullptr);
773799

774800
/// Finds \c lib_stem considering the list of search paths and loads it by
775801
/// calling dlopen.
776802
/// \returns true on success.
777-
CPPINTEROP_API bool LoadLibrary(const char* lib_stem, bool lookup = true);
803+
CPPINTEROP_API bool LoadLibrary(const char* lib_stem, bool lookup = true,
804+
TInterp_t I = nullptr);
778805

779806
/// Finds \c lib_stem considering the list of search paths and unloads it by
780807
/// calling dlclose.
781808
/// function.
782-
CPPINTEROP_API void UnloadLibrary(const char* lib_stem);
809+
CPPINTEROP_API void UnloadLibrary(const char* lib_stem, TInterp_t I = nullptr);
783810

784811
/// Scans all libraries on the library search path for a given potentially
785812
/// mangled symbol name.
786813
///\returns the path to the first library that contains the symbol definition.
787-
CPPINTEROP_API std::string
788-
SearchLibrariesForSymbol(const char* mangled_name, bool search_system /*true*/);
814+
CPPINTEROP_API std::string SearchLibrariesForSymbol(const char* mangled_name,
815+
bool search_system /*true*/,
816+
TInterp_t I = nullptr);
789817

790818
/// Inserts or replaces a symbol in the JIT with the one provided. This is
791819
/// useful for providing our own implementations of facilities such as printf.
@@ -796,7 +824,8 @@ SearchLibrariesForSymbol(const char* mangled_name, bool search_system /*true*/);
796824
///
797825
///\returns true on failure.
798826
CPPINTEROP_API bool InsertOrReplaceJitSymbol(const char* linker_mangled_name,
799-
uint64_t address);
827+
uint64_t address,
828+
TInterp_t I = nullptr);
800829

801830
/// Tries to load provided objects in a string format (prettyprint).
802831
CPPINTEROP_API std::string ObjToString(const char* type, void* obj);
@@ -833,9 +862,10 @@ GetClassTemplateInstantiationArgs(TCppScope_t templ_instance,
833862

834863
/// Instantiates a function template from a given string representation. This
835864
/// function also does overload resolution.
865+
///\param[in] interp - is used to select the interpreter if multiple in-use.
836866
///\returns the instantiated function template declaration.
837-
CPPINTEROP_API TCppFunction_t
838-
InstantiateTemplateFunctionFromString(const char* function_template);
867+
CPPINTEROP_API TCppFunction_t InstantiateTemplateFunctionFromString(
868+
const char* function_template, TInterp_t interp = nullptr);
839869

840870
/// Finds best overload match based on explicit template parameters (if any)
841871
/// and argument types.
@@ -932,7 +962,7 @@ CPPINTEROP_API void CodeComplete(std::vector<std::string>& Results,
932962
/// Reverts the last N operations performed by the interpreter.
933963
///\param[in] N The number of operations to undo. Defaults to 1.
934964
///\returns 0 on success, non-zero on failure.
935-
CPPINTEROP_API int Undo(unsigned N = 1);
965+
CPPINTEROP_API int Undo(unsigned N = 1, TInterp_t interp = nullptr);
936966

937967
} // end namespace Cpp
938968

lib/CppInterOp/Compatibility.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ inline void InstantiateClassTemplateSpecialization(
429429
#if CLANG_VERSION_MAJOR < 20
430430
interp.getSema().InstantiateClassTemplateSpecialization(
431431
clang::SourceLocation::getFromRawEncoding(1), CTSD,
432+
432433
clang::TemplateSpecializationKind::TSK_ExplicitInstantiationDefinition,
433434
/*Complain=*/true);
434435
#else

0 commit comments

Comments
 (0)