cling/lib/Interpreter/DynamicLookup.h

293 lines
12 KiB
C
Raw Normal View History

//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 14:08:37 +04:00
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#ifndef CLING_DYNAMIC_LOOKUP_H
#define CLING_DYNAMIC_LOOKUP_H
#include "ASTTransformer.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Sema/Ownership.h"
#include "llvm/Support/Casting.h"
namespace clang {
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 16:49:28 +03:00
class Decl;
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;
bool m_HasErrorOccurred;
public:
ASTNodeInfo() : forReplacement(false), m_HasErrorOccurred(false) {}
ASTNodeInfo(clang::Stmt* S, bool needed)
: forReplacement(needed), m_HasErrorOccurred(false) {
Nodes.push_back(S);
}
bool isForReplacement() { return forReplacement; }
void setForReplacement(bool val = true) { forReplacement = val; }
void setErrorOccurred(bool val = true) { m_HasErrorOccurred = val; }
bool hasErrorOccurred() { return m_HasErrorOccurred; }
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.
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 16:49:28 +03:00
class EvaluateTSynthesizer : public ASTTransformer,
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 Stores the cling::Interpreter (cling::runtime::gCling),
/// used in as an parameter LifetimeHandler's ctor.
clang::VarDecl* m_gCling;
/// \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;
/// \brief Counter used when entering/exitting compound stmt. Needed for
/// value printing of dynamic expressions.
unsigned m_NestedCompoundStmts;
public:
typedef clang::StmtVisitor<EvaluateTSynthesizer, ASTNodeInfo>
BaseStmtVisitor;
using BaseStmtVisitor::Visit;
EvaluateTSynthesizer(clang::Sema* S);
~EvaluateTSynthesizer();
Emit Decls as DeclCollector sees them. Now that we can easily revert Transactions' IR (by unloading their module) we do not need to queue the Decls before emitting them. This enables EndOfTU actions to be emitted seeminglessly, without extra transactions, or explicit post-EndOfTU-emission: each Transaction will have its TU finalized exactly once. This in turn allows us to turn on Debug emission - which relies on being invoked exactly once per Module. Transformers must be invoked before emitting Decls. They are now invoked for each Decl; WrapperTransformers are invoked when seeing a wrapper decl. They do not see the "full transaction AST" anymore - luckily none of our transformers requires this and actually become simpler because of this change. This also fixes a bug where the relative sequencing of parsed and deserialized Decls was lost (parsed was emitted before deserialized). Remove unused IRTransactions; they should really be llvm::Pass-es. We don't have them anyway. Disable a few transformations if the Decl isFromASTFile. When reverting a Transaction, also revert its nested ones. In the ValueExtractionSynthesizer, pass the ValuePrinter option as int, instead of the transaction pointer - that might have changed (at least its options) by the time we invoke the wrapper. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # Explicit paths specified without -i or -o; assuming --only paths... # rebase in progress; onto b3d9f92 # You are currently splitting a commit while rebasing branch 'declcollector-emits-v2' on 'b3d9f92'. # # Changes to be committed: # modified: interpreter/cling/include/cling/Interpreter/RuntimeUniverse.h # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/AutoSynthesizer.h # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/CheckEmptyTransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/DeclCollector.cpp # modified: interpreter/cling/lib/Interpreter/DeclCollector.h # modified: interpreter/cling/lib/Interpreter/DeclExtractor.cpp # modified: interpreter/cling/lib/Interpreter/DeclExtractor.h # modified: interpreter/cling/lib/Interpreter/DynamicLookup.cpp # modified: interpreter/cling/lib/Interpreter/DynamicLookup.h # modified: interpreter/cling/lib/Interpreter/IncrementalParser.cpp # modified: interpreter/cling/lib/Interpreter/IncrementalParser.h # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.cpp # modified: interpreter/cling/lib/Interpreter/TransactionTransformer.h # modified: interpreter/cling/lib/Interpreter/TransactionUnloader.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValueExtractionSynthesizer.h # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.cpp # modified: interpreter/cling/lib/Interpreter/ValuePrinterSynthesizer.h # # Untracked files: # .idea/ # 0001-Fix-llvm-merge-issue.patch # 0002-Fix-warnings.patch # 0003-Keep-weak-symbols-around-subsequent-transactions-mig.patch # T.cxx # T.cxx~ # TMVA.root # a.out # boost.root # config/Makefile.depend~ # core/textinput/src/textinput/TerminalDisplayWin.cpp.orig # ct.root # data.root # interpreter/cling/76fc2055249da7b03148a7d4197a279e9943f012.patch # interpreter/cling/lib/Interpreter/CIFactory.cpp~ # interpreter/cling/lib/Interpreter/DeclCollector.h~ # interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp~ # modulemap-one-header-per-file.txt # osrm-routed # tiles.tar.bz2 # tmva_class_example.root # tutorials/v3.root # weights/ #
2015-03-16 16:49:28 +03:00
Result Transform(clang::Decl* D) override;
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);
///\brief \c delete t; \c if t is dependent, the whole stmt must be escaped.
///
ASTNodeInfo VisitCXXDeleteExpr(clang::CXXDeleteExpr* Node);
///\brief Surrounds member accesses into dependent types; remove on
/// subsitution of its child expression.
///
ASTNodeInfo VisitCXXDependentScopeMemberExpr(
clang::CXXDependentScopeMemberExpr* Node);
ASTNodeInfo VisitExpr(clang::Expr* Node);
ASTNodeInfo VisitBinaryOperator(clang::BinaryOperator* Node);
ASTNodeInfo VisitArraySubscriptExpr(clang::ArraySubscriptExpr* ASE);
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 const char* expression from given value.
clang::Expr* ConstructConstCharPtrExpr(llvm::StringRef Val);
///\brief Checks if the given node is marked as dependent by us.
///
bool IsArtificiallyDependent(clang::Expr* Node);
///\brief Checks if the function might contain dynamically scoped Decls.
///
bool ShouldVisit(clang::FunctionDecl* D);
/// \brief Gets all children of a given node.
///
bool GetChildren(ASTNodes& Children, clang::Stmt* Node);
2014-08-04 06:05:42 +04:00
/// \brief Creates unique name (eg. of a variable). Used internally for
/// AST node synthesis.
///
std::string createUniqueName();
/// @}
};
} // end namespace cling
#endif // CLING_DYNAMIC_LOOKUP_H