3bcfc8b25e
* Merge the DynamicIDHandler into InterpreterCallbacks. The DynamicIDHandler was used to define the failed lookup names as dependent, so that later on they could be "healed" by the EvaluateTSynthesizer - by generating a call to gCling->EvaluateT... * Add a flag in the InterpreterCallbacks giving a hint when the failed lookup is performed - during compilation time or during evaluation type, maybe its name is misnomer. Maybe I should rename it to IsInRuntimeEvalMode or smth like that... * Simplify the evaluation routine. The idea is to be merged with one of the existing - either echo or evaluate * Implement proper mock object as test dynamic symbol resolver callback. Now it fully relies on InterpreterCallbacks. * Implement dynamic expression node marking. Every node that needs runtime resolution is marked as dependent. However, clang marks other nodes as dependent, too (eg. templates). Until now it was very difficult to distinguish between both. Now every "artificially" (marked by us) node's declaration is annotated so that it could be found back easily by using a simple RecursiveASTVisitor. Generally we have two issues when using dynamic scopes - filtering the failed lookups that need to be evaluated at runtime, and filtering the "artificially" marked as dependent dynamic nodes/decls. Whereas the second issue is solved by using the annotations, the first one is more tricky to solve because clang doesn't give us enough information to conclude what should be done. For now I have narrowed down the cases so that dynamic nodes can appear only in function decls. git-svn-id: http://root.cern.ch/svn/root/trunk@48575 27541ba8-7e3a-0410-8455-c3a389f83636
274 lines
11 KiB
C++
274 lines
11 KiB
C++
//--------------------------------------------------------------------*- C++ -*-
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// version: $Id$
|
|
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifndef CLING_DYNAMIC_LOOKUP_H
|
|
#define CLING_DYNAMIC_LOOKUP_H
|
|
|
|
#include "TransactionTransformer.h"
|
|
|
|
#include "clang/AST/StmtVisitor.h"
|
|
#include "clang/Sema/Ownership.h"
|
|
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
|
|
namespace clang {
|
|
class Sema;
|
|
}
|
|
|
|
namespace cling {
|
|
typedef llvm::SmallVector<clang::Stmt*, 2> ASTNodes;
|
|
|
|
/// \brief Helper structure that allows children of a node to delegate how
|
|
/// to be replaced from their parent. For example a child can return more than
|
|
/// one replacement node.
|
|
class ASTNodeInfo {
|
|
private:
|
|
ASTNodes Nodes;
|
|
bool forReplacement;
|
|
public:
|
|
ASTNodeInfo() : forReplacement(false){}
|
|
ASTNodeInfo(clang::Stmt* S, bool needed) : forReplacement(needed) {
|
|
Nodes.push_back(S);
|
|
}
|
|
|
|
bool isForReplacement() { return forReplacement; }
|
|
void setForReplacement(bool val = true) { forReplacement = val; }
|
|
bool hasSingleNode() { return Nodes.size() == 1; }
|
|
clang::Stmt* getAsSingleNode() {
|
|
assert(hasSingleNode() && "There is more than one node!");
|
|
return Nodes[0];
|
|
}
|
|
ASTNodes& getNodes() { return Nodes; }
|
|
void addNode(clang::Stmt* Node) { Nodes.push_back(Node); }
|
|
template <typename T> T* getAs() {
|
|
return llvm::dyn_cast<T>(getAsSingleNode());
|
|
}
|
|
template <typename T> T* castTo() {
|
|
T* Result = llvm::dyn_cast<T>(getAsSingleNode());
|
|
assert(Result && "Cannot cast to type!");
|
|
return Result;
|
|
}
|
|
};
|
|
} //end namespace cling
|
|
|
|
namespace cling {
|
|
|
|
typedef llvm::DenseMap<clang::Stmt*, clang::Stmt*> MapTy;
|
|
|
|
/// \brief In order to implement the runtime type binding and expression
|
|
/// evaluation we need to be able to compile code which contains unknown
|
|
/// symbols (undefined variables, types, functions, etc.). This cannot be done
|
|
/// by a compiler like clang, because it is not valid C++ code.
|
|
///
|
|
/// DynamicExprTransformer transforms these unknown symbols into valid C++
|
|
/// code at AST (abstract syntax tree) level. Thus it provides an opportunity
|
|
/// their evaluation to happen at runtime. Several steps are performed:
|
|
///
|
|
/// 1. Skip compiler's error diagnostics - if a compiler encounters unknown
|
|
/// symbol, by definition, it must output an error and it mustn't produce
|
|
/// machine code. Cling implements an extension to Clang semantic analyzer
|
|
/// that allows the compiler to recover even an unknown symbol is encountered.
|
|
/// For instance if the compiler sees a symbol it looks for its definition in
|
|
/// a internal structure (symbol table) and it is not found it asks whether
|
|
/// somebody else could provide the missing symbol. That is the place where
|
|
/// the DynamicIDHandler, which is controlled by DynamicExprTransformer comes
|
|
/// into play. It marks all unknown symbols as dependent as if they are
|
|
/// templates and are going to be resolved at first instantiation, with the
|
|
/// only difference that an instantiation never happens. The advantage is that
|
|
/// the unknown symbols are not diagnosed but the disadvantage is that
|
|
/// somebody needs to transform them into valid expressions with valid types.
|
|
///
|
|
/// 2. Replace all dependent symbols - all artificially dependent symbols need
|
|
/// to be replaced with appropriate valid symbols in order the compiler to
|
|
/// produce executable machine code. The DynamicExprTransformer walks up all
|
|
/// statements and declarations that might be possibly marked earlier as
|
|
/// dependent and replaces them with valid expression, which preserves the
|
|
/// meant behavior. Main implementation goal is to replace the as little
|
|
/// as possible part of the statement. The replacement is done immediately
|
|
/// after the expected type can be deduced.
|
|
///
|
|
/// 2.1. EvaluateT - this is a templated function, which is put at the
|
|
/// place of the dependent expression. It will be called at runtime and it
|
|
/// will use the runtime instance of the interpreter (cling interprets itself)
|
|
/// to evaluate the replaced expression. The template parameter of the
|
|
/// function carries the expected expression type. If unknown symbol is
|
|
/// encountered as a right-hand-side of an assignment one can claim that
|
|
/// the type of the unknown expression should be compatible with the type of
|
|
/// the left-hand-side.
|
|
///
|
|
/// 2.2 LifetimeHandler - in some more complex situation in order to preserve
|
|
/// the behavior the expression must be replaced with more complex structures.
|
|
///
|
|
/// 3. Evaluate interface - this is the core function in the interpreter,
|
|
/// which does the delayed evaluation. It uses a callback function, which
|
|
/// should be reimplemented in the subsystem that provides the runtime types
|
|
/// and addresses of the expressions.
|
|
class EvaluateTSynthesizer : public TransactionTransformer,
|
|
public clang::StmtVisitor<EvaluateTSynthesizer,
|
|
ASTNodeInfo> {
|
|
|
|
private:
|
|
|
|
/// \brief Stores the declaration of the EvaluateT function.
|
|
clang::FunctionDecl* m_EvalDecl;
|
|
|
|
/// \brief Stores helper structure dealing with static initializers.
|
|
clang::CXXRecordDecl* m_LifetimeHandlerDecl;
|
|
|
|
/// \brief Stores member function defined in the LifetimeHanlder.
|
|
clang::CXXMethodDecl* m_LHgetMemoryDecl;
|
|
|
|
/// \brief Stores helper class used in EvaluateT call.
|
|
clang::CXXRecordDecl* m_DynamicExprInfoDecl;
|
|
|
|
/// \brief Stores the clang::DeclContext declaration, used in as an parameter
|
|
/// in EvaluateT call.
|
|
clang::CXXRecordDecl* m_DeclContextDecl;
|
|
|
|
/// \brief Keeps track of the replacements being made. If an AST node is
|
|
/// changed with another it should be added to the map (newNode->oldNode).
|
|
MapTy m_SubstSymbolMap;
|
|
|
|
/// \brief Stores the actual declaration context, in which declarations are
|
|
/// being visited.
|
|
clang::DeclContext* m_CurDeclContext;
|
|
|
|
/// \brief Use instead of clang::SourceRange().
|
|
clang::SourceRange m_NoRange;
|
|
|
|
/// \brief Use instead of clang::SourceLocation() as start location.
|
|
clang::SourceLocation m_NoSLoc;
|
|
|
|
/// \brief Use instead of clang::SourceLocation() as end location.
|
|
clang::SourceLocation m_NoELoc;
|
|
|
|
/// \brief Needed for the AST transformations, owned by Sema.
|
|
clang::ASTContext* m_Context;
|
|
|
|
/// \brief Counter used when we need unique names.
|
|
unsigned long long m_UniqueNameCounter;
|
|
|
|
public:
|
|
|
|
typedef clang::StmtVisitor<EvaluateTSynthesizer, ASTNodeInfo>
|
|
BaseStmtVisitor;
|
|
|
|
using BaseStmtVisitor::Visit;
|
|
|
|
EvaluateTSynthesizer(clang::Sema* S);
|
|
|
|
~EvaluateTSynthesizer();
|
|
|
|
virtual void Transform();
|
|
|
|
MapTy& getSubstSymbolMap() { return m_SubstSymbolMap; }
|
|
|
|
ASTNodeInfo VisitStmt(clang::Stmt* Node);
|
|
ASTNodeInfo VisitCompoundStmt(clang::CompoundStmt* Node);
|
|
ASTNodeInfo VisitIfStmt(clang::IfStmt* Node);
|
|
/// \brief Transforms a declaration with initializer of dependent type.
|
|
/// If an object on the free store is being initialized we use the
|
|
/// EvaluateT
|
|
/// If an object on the stack is being initialized it is transformed into
|
|
/// reference and an object on the free store is created in order to
|
|
/// avoid the copy constructors, which might be private
|
|
///
|
|
/// For example:
|
|
/// @code
|
|
/// int i = 5;
|
|
/// MyClass my(dep->Symbol(i))
|
|
/// @endcode
|
|
/// where dep->Symbol() is of artificially dependent type it is being
|
|
/// transformed into:
|
|
/// @code
|
|
/// cling::runtime::internal::LifetimeHandler
|
|
/// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass");
|
|
/// MyClass &my(*(MyClass*)__unique.getMemory());
|
|
/// @endcode
|
|
///
|
|
/// Note: here our main priority is to preserve equivalent behavior. We have
|
|
/// to clean the heap memory afterwords.
|
|
///
|
|
ASTNodeInfo VisitDeclStmt(clang::DeclStmt* Node);
|
|
ASTNodeInfo VisitExpr(clang::Expr* Node);
|
|
ASTNodeInfo VisitBinaryOperator(clang::BinaryOperator* Node);
|
|
ASTNodeInfo VisitCallExpr(clang::CallExpr* E);
|
|
ASTNodeInfo VisitDeclRefExpr(clang::DeclRefExpr* DRE);
|
|
ASTNodeInfo VisitDependentScopeDeclRefExpr(
|
|
clang::DependentScopeDeclRefExpr* Node);
|
|
|
|
protected:
|
|
|
|
///\brief On first use it finds commonly used declarations.
|
|
///
|
|
/// For example: EvaluateT, clang::DeclContext and so on.
|
|
///
|
|
void Initialize();
|
|
|
|
/// @{
|
|
/// @name Helpers, which simplify node replacement
|
|
|
|
///\brief Replaces given dependent AST node with an instantiation of
|
|
/// EvaluateT with the deduced type.
|
|
///
|
|
/// @param[in] InstTy The deduced type used to create instantiation.
|
|
/// @param[in] SubTree The AST node or subtree, which is being replaced.
|
|
/// @param[in] ValuePrinterReq Whether to turn on the value printing or not
|
|
///
|
|
clang::Expr* SubstituteUnknownSymbol(const clang::QualType InstTy,
|
|
clang::Expr* SubTree,
|
|
bool ValuePrinterReq = false);
|
|
|
|
///\brief Builds the actual call expression, which is put in the place of
|
|
/// the dependent AST node.
|
|
///
|
|
/// @param[in] InstTy The deduced type used to create instantiation.
|
|
/// @param[in] SubTree The AST node or subtree, which is being replaced.
|
|
/// @param[in] CallArgs Proper arguments, which the call will use.
|
|
///
|
|
clang::CallExpr* BuildEvalCallExpr(clang::QualType InstTy,
|
|
clang::Expr* SubTree,
|
|
llvm::SmallVector<clang::Expr*, 2>& CallArgs);
|
|
|
|
///\brief Builds the DynamicExprInfo class with proper info.
|
|
///
|
|
clang::Expr* BuildDynamicExprInfo(clang::Expr* SubTree,
|
|
bool ValuePrinterReq = false);
|
|
|
|
///\brief Creates cstyle casts a pointer expression to a given qualified
|
|
/// type.
|
|
///
|
|
clang::Expr* ConstructCStyleCasePtrExpr(clang::QualType Ty, uint64_t Ptr);
|
|
|
|
///\brief Creates const char* expression from given value.
|
|
clang::Expr* ConstructConstCharPtrExpr(const char* Val);
|
|
|
|
///\brief Checks if the given node is marked as dependent by us.
|
|
///
|
|
bool IsArtificiallyDependent(clang::Expr* Node);
|
|
|
|
///\brief Checks if the given declaration should be examined. It checks
|
|
/// whether a declaration context marked as dependent contains the
|
|
/// declaration or the declaration type is not one of those we are looking
|
|
/// for.
|
|
///
|
|
bool ShouldVisit(clang::Decl* D);
|
|
|
|
/// \brief Gets all children of a given node.
|
|
///
|
|
bool GetChildren(ASTNodes& Children, clang::Stmt* Node);
|
|
|
|
/// \brief Creates unique name (eg. of a variable). Used internally for
|
|
/// AST node synthesis.
|
|
///
|
|
void createUniqueName(std::string& out);
|
|
/// @}
|
|
};
|
|
} // end namespace cling
|
|
#endif // CLING_DYNAMIC_LOOKUP_H
|