Reduce the amount of headers needed by the dynamic scopes at runtime:

* Make GenericValue, clang::QualType opaque in Value
* Move LifetimeHandler implementation into source; requires separate header
* 

Also:
* Value: replace CPP macros by overloads


git-svn-id: http://root.cern.ch/svn/root/trunk@48675 27541ba8-7e3a-0410-8455-c3a389f83636
This commit is contained in:
Axel Naumann 2013-02-22 15:59:54 +00:00
parent e0397a6d4c
commit 664e8b22ac
10 changed files with 309 additions and 183 deletions

View File

@ -0,0 +1,85 @@
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
#ifndef CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H
#define CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H
#include <string>
namespace clang {
class DeclContext;
}
namespace cling {
class DynamicExprInfo;
class Interpreter;
/// \brief Contains declarations for cling's runtime.
namespace runtime {
/// \brief Provides private definitions for the dynamic scopes and runtime
/// bindings. These builtins should not be used for other purposes.
namespace internal {
extern Interpreter* gCling;
/// \brief LifetimeHandler is used in case of initialization using address
/// on the automatic store (stack) instead of EvaluateT.
///
/// The reason is to avoid the copy constructors that might be private.
/// This is part of complex transformation, which aims to preserve the
/// code behavior. For example:
/// @code
/// int i = 5;
/// MyClass my(dep->Symbol(i))
/// @endcode
/// where dep->Symbol() is a symbol not known at compile-time
/// transformed into:
/// @code
/// cling::runtime::internal::LifetimeHandler
/// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass");
/// MyClass &my(*(MyClass*)__unique.getMemory());
/// @endcode
class LifetimeHandler {
private:
/// \brief The Interpreter handling this storage element.
Interpreter* m_Interpreter;
/// \brief The memory on the free store, where the object will be
/// created.
void* m_Memory;
/// \brief The type of the object that will be created.
std::string m_Type;
public:
/// \brief Constructs an expression, which creates the object on the
/// free store and tells the interpreter to evaluate it.
///
/// @param[in] ExprInfo Helper structure that keeps information about
/// the expression that is being replaced and the addresses of the
/// variables that the replaced expression contains.
/// @param[in] DC The declaration context, in which the expression will
/// be evaluated at runtime
/// @param[in] type The type of the object, which will help to delete
/// it, when the LifetimeHandler goes out of scope.
///
LifetimeHandler(DynamicExprInfo* ExprInfo,
clang::DeclContext* DC,
const char* type,
Interpreter* Interp = gCling);
///\brief Returns the created object.
void* getMemory() const { return m_Memory; }
/// \brief Clears up the free store, when LifetimeHandler goes out of
/// scope.
///
~LifetimeHandler();
};
}
} // end namespace runtime
} // end namespace cling
#endif // CLING_DYNAMIC_LOOKUP_LIFETIME_HANDLER_H

View File

@ -17,17 +17,12 @@
#include "cling/Interpreter/RuntimeUniverse.h"
#endif
#include "cling/Interpreter/DynamicExprInfo.h"
#include "cling/Interpreter/ValuePrinter.h"
#include "cling/Interpreter/DynamicLookupLifetimeHandler.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "llvm/Support/raw_ostream.h"
#include <stdio.h>
namespace cling {
/// \brief Used to stores the declarations, which are going to be
/// available only at runtime. These are cling runtime builtins.
/// \brief Contains declarations for cling's runtime.
namespace runtime {
/// \brief Provides builtins, which are neccessary for the dynamic scopes
@ -68,71 +63,6 @@ namespace runtime {
cling::runtime::gCling->Evaluate(ExprInfo->getExpr(), DC,
ExprInfo->isValuePrinterRequested());
}
/// \brief LifetimeHandler is used in case of initialization using address
/// on the automatic store (stack) instead of EvaluateT.
///
/// The reason is to avoid the copy constructors that might be private.
/// This is part of complex transformation, which aims to preserve the
/// code behavior. For example:
/// @code
/// int i = 5;
/// MyClass my(dep->Symbol(i))
/// @endcode
/// where dep->Symbol() is a symbol not known at compile-time
/// transformed into:
/// @code
/// cling::runtime::internal::LifetimeHandler
/// __unique("dep->Sybmol(*(int*)@)",(void*[]){&i}, DC, "MyClass");
/// MyClass &my(*(MyClass*)__unique.getMemory());
/// @endcode
class LifetimeHandler {
private:
/// \brief The memory on the free store, where the object will be
/// created.
void* m_Memory;
/// \brief The type of the object that will be created.
std::string m_Type;
public:
/// \brief Constructs an expression, which creates the object on the
/// free store and tells the interpreter to evaluate it.
///
/// @param[in] ExprInfo Helper structure that keeps information about
/// the expression that is being replaced and the addresses of the
/// variables that the replaced expression contains.
/// @param[in] DC The declaration context, in which the expression will
/// be evaluated at runtime
/// @param[in] type The type of the object, which will help to delete
/// it, when the LifetimeHandler goes out of scope.
///
LifetimeHandler(DynamicExprInfo* ExprInfo,
clang::DeclContext* DC,
const char* type) {
m_Type = type;
std::string ctor("new ");
ctor += type;
ctor += ExprInfo->getExpr();
StoredValueRef res = cling::runtime::gCling->Evaluate(ctor.c_str(), DC,
ExprInfo->isValuePrinterRequested()
);
m_Memory = (void*)res.get().getGV().PointerVal;
}
///\brief Returns the created object.
void* getMemory() const { return m_Memory; }
/// \brief Clears up the free store, when LifetimeHandler goes out of
/// scope.
///
~LifetimeHandler() {
std::string str;
llvm::raw_string_ostream stream(str);
stream<<"delete ("<< m_Type << "*) "<< m_Memory << ";";
stream.flush();
cling::runtime::gCling->execute(str);
}
};
}
} // end nmespace internal
} // end namespace runtime
} // end namespace cling

View File

@ -3,16 +3,13 @@
// version: $Id$
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
#ifndef __CLING__
#error "This file must not be included by compiled programs."
#else
#ifdef CLING_RUNTIME_UNIVERSE_H
#error "CLING_RUNTIME_UNIVERSE_H Must only include once."
#else
#ifndef CLING_RUNTIME_UNIVERSE_H
#define CLING_RUNTIME_UNIVERSE_H
#if !defined(__CLING__) && !defined(__COMPILING_CLING__)
#error "This file must not be included by compiled programs."
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS // needed by System/DataTypes.h
#endif
@ -90,6 +87,4 @@ extern "C" {
}
#endif // __cplusplus
#endif // CLING_RUNTIME_UNIVERSE_H (error)
#endif // __CLING__
#endif // CLING_RUNTIME_UNIVERSE_H

View File

@ -26,7 +26,7 @@ namespace cling {
/// \brief Number of bytes that need to be allocated to hold a value
/// of our type
int64_t getAllocSizeInBytes(const clang::ASTContext& ctx) const;
long long getAllocSizeInBytes(const clang::ASTContext& ctx) const;
/// \brief Memory allocated for value, owned by this value
///

View File

@ -7,14 +7,16 @@
#ifndef CLING_VALUE_H
#define CLING_VALUE_H
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/Type.h"
#include <stddef.h>
#include <assert.h>
namespace llvm {
class Type;
struct GenericValue;
}
namespace clang {
class ASTContext;
class QualType;
}
namespace cling {
@ -32,35 +34,43 @@ namespace cling {
/// void types
/// 3. Parameters for calls given an llvm::Function and a clang::FunctionDecl.
class Value {
private:
/// \brief Forward decl for typed access specializations
template <typename T> struct TypedAccess;
protected:
/// \brief value
llvm::GenericValue m_GV;
char /*llvm::GenericValue*/ m_GV[32]; // 24 bytes on 64bit
/// \brief the value's type according to clang
clang::QualType m_ClangType;
/// \brief the value's type according to clang, stored as void* to reduce
/// dependencies.
void* /*clang::QualType*/ m_ClangType;
/// \brief the value's type according to clang
const llvm::Type* m_LLVMType;
enum EStorageType {
kSignedIntegerOrEnumerationType,
kUnsignedIntegerOrEnumerationType,
kDoubleType,
kFloatType,
kLongDoubleType,
kPointerType,
kUnsupportedType
};
/// \brief Retrieve the underlying, canonical, desugared, unqualified type.
EStorageType getStorageType() const;
public:
/// \brief Default constructor, creates a value that IsInvalid().
Value() {}
/// \brief Construct a valid Value.
Value(const llvm::GenericValue& v, clang::QualType t)
: m_GV(v), m_ClangType(t), m_LLVMType(0) { }
Value(const llvm::GenericValue& v, clang::QualType t);
Value(const llvm::GenericValue& v, clang::QualType clangTy,
const llvm::Type* llvmTy)
: m_GV(v), m_ClangType(clangTy), m_LLVMType(llvmTy) { }
const llvm::Type* llvmTy);
llvm::GenericValue getGV() const { return m_GV; }
void setGV(llvm::GenericValue GV) { m_GV = GV; }
clang::QualType getClangType() const { return m_ClangType; }
llvm::GenericValue getGV() const;
void setGV(llvm::GenericValue GV);
clang::QualType getClangType() const;
const llvm::Type* getLLVMType() const { return m_LLVMType; }
void setLLVMType(const llvm::Type* Ty) { m_LLVMType = Ty; }
@ -68,13 +78,10 @@ namespace cling {
//
/// Determine whether the Value has been set by checking
/// whether the type is valid.
bool isValid() const { return !m_ClangType.isNull(); }
bool isValid() const;
/// \brief Determine whether the Value is set but void.
bool isVoid(const clang::ASTContext& ASTContext) const {
return isValid()
&& m_ClangType.getDesugaredType(ASTContext)->isVoidType();
}
bool isVoid(const clang::ASTContext& ASTContext) const;
/// \brief Determine whether the Value is set and not void.
//
@ -87,6 +94,24 @@ namespace cling {
template <typename T>
T getAs() const;
template <typename T>
T* getAs(T**) const { return (T*)getAs((void**)0); }
void* getAs(void**) const;
double getAs(double*) const;
long double getAs(long double*) const;
float getAs(float*) const;
bool getAs(bool*) const;
signed char getAs(signed char*) const;
unsigned char getAs(unsigned char*) const;
signed short getAs(signed short*) const;
unsigned short getAs(unsigned short*) const;
signed int getAs(signed int*) const;
unsigned int getAs(unsigned int*) const;
signed long getAs(signed long*) const;
unsigned long getAs(unsigned long*) const;
signed long long getAs(signed long long*) const;
unsigned long long getAs(unsigned long long*) const;
/// \brief Get the value.
//
/// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
@ -96,83 +121,31 @@ namespace cling {
T simplisticCastAs() const;
};
template<typename T>
struct Value::TypedAccess{
T extract(const llvm::GenericValue& value) {
return *reinterpret_cast<T*>(value.PointerVal);
}
};
template<typename T>
struct Value::TypedAccess<T*>{
T* extract(const llvm::GenericValue& value) {
return reinterpret_cast<T*>(value.PointerVal);
}
};
#define CLING_VALUE_TYPEDACCESS(TYPE, GETTER) \
template<> \
struct Value::TypedAccess<TYPE> { \
TYPE extract(const llvm::GenericValue& value) { \
return value.GETTER; \
} \
}
#define CLING_VALUE_TYPEDACCESS_SIGNED(TYPE) \
CLING_VALUE_TYPEDACCESS(signed TYPE, IntVal.getSExtValue())
#define CLING_VALUE_TYPEDACCESS_UNSIGNED(TYPE) \
CLING_VALUE_TYPEDACCESS(unsigned TYPE, IntVal.getZExtValue())
#define CLING_VALUE_TYPEDACCESS_BOTHSIGNS(TYPE) \
CLING_VALUE_TYPEDACCESS_SIGNED(TYPE); \
CLING_VALUE_TYPEDACCESS_UNSIGNED(TYPE);
CLING_VALUE_TYPEDACCESS(double, DoubleVal);
//CLING_VALUE_TYPEDACCESS(long double, ???);
CLING_VALUE_TYPEDACCESS(float, FloatVal);
CLING_VALUE_TYPEDACCESS(bool, IntVal.getBoolValue());
CLING_VALUE_TYPEDACCESS_BOTHSIGNS(char)
CLING_VALUE_TYPEDACCESS_BOTHSIGNS(short)
CLING_VALUE_TYPEDACCESS_BOTHSIGNS(int)
CLING_VALUE_TYPEDACCESS_BOTHSIGNS(long)
CLING_VALUE_TYPEDACCESS_BOTHSIGNS(long long)
#undef CLING_VALUE_TYPEDACCESS_BOTHSIGNS
#undef CLING_VALUE_TYPEDACCESS_UNSIGNED
#undef CLING_VALUE_TYPEDACCESS_SIGNED
#undef CLING_VALUE_TYPEDACCESS
template <typename T>
T Value::getAs() const {
// T *must* correspond to type. Else use simplisticCastAs()!
TypedAccess<T> VI;
return VI.extract(m_GV);
return getAs((T*)0);
}
template <typename T>
T Value::simplisticCastAs() const {
const clang::Type* desugCanon = m_ClangType->getUnqualifiedDesugaredType();
desugCanon = desugCanon->getCanonicalTypeUnqualified()->getTypePtr()
->getUnqualifiedDesugaredType();
if (desugCanon->isSignedIntegerOrEnumerationType()) {
EStorageType storageType = getStorageType();
switch (storageType) {
case kSignedIntegerOrEnumerationType:
return (T) getAs<signed long long>();
} else if (desugCanon->isUnsignedIntegerOrEnumerationType()) {
case kUnsignedIntegerOrEnumerationType:
return (T) getAs<unsigned long long>();
} else if (desugCanon->isRealFloatingType()) {
const clang::BuiltinType* BT = desugCanon->getAs<clang::BuiltinType>();
if (BT->getKind() == clang::BuiltinType::Double)
return (T) getAs<double>();
else if (BT->getKind() == clang::BuiltinType::Float)
return (T) getAs<float>();
/* not yet supported in JIT:
else if (BT->getKind() == clang::BuiltinType::LongDouble)
return (T) getAs<long double>();
*/
} else if (desugCanon->isPointerType() || desugCanon->isObjectType()) {
case kDoubleType:
return (T) getAs<double>();
case kFloatType:
return (T) getAs<float>();
case kLongDoubleType:
return (T) getAs<long double>();
case kPointerType:
return (T) (size_t) getAs<void*>();
case kUnsupportedType:
assert("unsupported type in Value, cannot cast simplistically!" && 0);
}
assert("unsupported type in Value, cannot cast simplistically!" && 0);
return T();
}
} // end namespace cling

View File

@ -8,9 +8,13 @@
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/DynamicExprInfo.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Utils/AST.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Lex/Preprocessor.h"
@ -18,6 +22,8 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "cling/Interpreter/DynamicLookupLifetimeHandler.h"
using namespace clang;
namespace {
@ -362,7 +368,8 @@ namespace cling {
llvm::SmallVector<Expr*, 4> Inits;
// Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo
// DC,
// "MyClass")
// "MyClass"
// /*, Interp = gCling*/)
// Build Arg0 DynamicExprInfo
Inits.push_back(BuildDynamicExprInfo(E));
// Build Arg1 DeclContext* DC
@ -651,7 +658,7 @@ namespace cling {
}
Expr* EvaluateTSynthesizer::ConstructCStyleCasePtrExpr(QualType Ty,
uint64_t Ptr) {
uint64_t Ptr) {
if (!Ty->isPointerType())
Ty = m_Context->getPointerType(Ty);
TypeSourceInfo* TSI = m_Context->CreateTypeSourceInfo(Ty);
@ -825,4 +832,30 @@ namespace cling {
// end Helpers
namespace runtime {
namespace internal {
// Implementations from DynamicLookupLifetimeHandler.h
LifetimeHandler::LifetimeHandler(DynamicExprInfo* ExprInfo,
clang::DeclContext* DC,
const char* type,
Interpreter* Interp /* = gCling */):
m_Interpreter(Interp), m_Type(type) {
std::string ctor("new ");
ctor += type;
ctor += ExprInfo->getExpr();
StoredValueRef res = Interp->Evaluate(ctor.c_str(), DC,
ExprInfo->isValuePrinterRequested()
);
m_Memory = (void*)res.get().getGV().PointerVal;
}
LifetimeHandler::~LifetimeHandler() {
std::string str;
llvm::raw_string_ostream stream(str);
stream << "delete (" << m_Type << "*) " << m_Memory << ";";
stream.flush();
m_Interpreter->execute(str);
}
} // end namespace internal
} // end namespace runtime
} // end namespace cling

View File

@ -8,12 +8,15 @@
#include "cling/Interpreter/StoredValueRef.h"
#include "clang/AST/Type.h"
#include "llvm/Constants.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"

View File

@ -7,6 +7,7 @@
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/Interpreter/ValuePrinter.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ExecutionEngine/GenericValue.h"
using namespace cling;
using namespace clang;
@ -15,9 +16,7 @@ using namespace llvm;
StoredValueRef::StoredValue::StoredValue(const ASTContext& ctx,
QualType clangTy,
const llvm::Type* llvm_Ty)
:m_Mem(0) {
m_ClangType = clangTy;
m_LLVMType = llvm_Ty;
:Value(GenericValue(), clangTy, llvm_Ty), m_Mem(0) {
if (!(clangTy->isIntegralOrEnumerationType()
|| clangTy->isRealFloatingType()
|| clangTy->hasPointerRepresentation())) {
@ -25,7 +24,7 @@ StoredValueRef::StoredValue::StoredValue(const ASTContext& ctx,
if (size > sizeof(m_Buf))
m_Mem = new char[size];
else m_Mem = m_Buf;
m_GV = llvm::PTOGV(m_Mem);
setGV(llvm::PTOGV(m_Mem));
};
}
@ -34,9 +33,9 @@ StoredValueRef::StoredValue::~StoredValue() {
delete [] m_Mem;
}
int64_t StoredValueRef::StoredValue::getAllocSizeInBytes(
long long StoredValueRef::StoredValue::getAllocSizeInBytes(
const ASTContext& ctx) const {
return ctx.getTypeSizeInChars(m_ClangType).getQuantity();
return (long long) ctx.getTypeSizeInChars(getClangType()).getQuantity();
}

107
lib/Interpreter/Value.cpp Normal file
View File

@ -0,0 +1,107 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id: Value.cpp 48537 2013-02-11 17:30:03Z vvassilev $
// author: Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------
#include "cling/Interpreter/Value.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
namespace cling {
Value::Value(const llvm::GenericValue& v, clang::QualType t)
: m_ClangType(t.getAsOpaquePtr()), m_LLVMType(0)
{
setGV(v);
}
Value::Value(const llvm::GenericValue& v, clang::QualType clangTy,
const llvm::Type* llvmTy)
: m_ClangType(clangTy.getAsOpaquePtr()), m_LLVMType(llvmTy)
{
setGV(v);
}
llvm::GenericValue Value::getGV() const {
return reinterpret_cast<const llvm::GenericValue&>(m_GV);
}
void Value::setGV(llvm::GenericValue GV) {
reinterpret_cast<llvm::GenericValue&>(m_GV) = GV;
}
clang::QualType Value::getClangType() const {
assert(sizeof(clang::QualType) <= sizeof(m_ClangType) && "m_ClangType too small!");
return clang::QualType::getFromOpaquePtr(m_ClangType);
}
bool Value::isValid() const { return !getClangType().isNull(); }
bool Value::isVoid(const clang::ASTContext& ASTContext) const {
return isValid()
&& getClangType().getDesugaredType(ASTContext)->isVoidType();
}
Value::EStorageType Value::getStorageType() const {
const clang::Type* desugCanon = getClangType()->getUnqualifiedDesugaredType();
desugCanon = desugCanon->getCanonicalTypeUnqualified()->getTypePtr()
->getUnqualifiedDesugaredType();
if (desugCanon->isSignedIntegerOrEnumerationType())
return kSignedIntegerOrEnumerationType;
else if (desugCanon->isUnsignedIntegerOrEnumerationType())
return kUnsignedIntegerOrEnumerationType;
else if (desugCanon->isRealFloatingType()) {
const clang::BuiltinType* BT = desugCanon->getAs<clang::BuiltinType>();
if (BT->getKind() == clang::BuiltinType::Double)
return kDoubleType;
else if (BT->getKind() == clang::BuiltinType::Float)
return kFloatType;
else if (BT->getKind() == clang::BuiltinType::LongDouble)
return kLongDoubleType;
} else if (desugCanon->isPointerType() || desugCanon->isObjectType())
return kPointerType;
return kUnsupportedType;
}
void* Value::getAs(void**) const { return getGV().PointerVal; }
double Value::getAs(double*) const { return getGV().DoubleVal; }
long double Value::getAs(long double*) const {
return getAs((double*)0);
}
float Value::getAs(float*) const { return getGV().FloatVal; }
bool Value::getAs(bool*) const { return getGV().IntVal.getBoolValue(); }
signed char Value::getAs(signed char*) const {
return (signed char) getAs((signed long long*)0);
}
unsigned char Value::getAs(unsigned char*) const {
return (unsigned char) getAs((unsigned long long*)0);
}
signed short Value::getAs(signed short*) const {
return (signed short) getAs((signed long long*)0);
}
unsigned short Value::getAs(unsigned short*) const {
return (unsigned short) getAs((unsigned long long*)0);
}
signed int Value::getAs(signed int*) const {
return (signed int) getAs((signed long long*)0);
}
unsigned int Value::getAs(unsigned int*) const {
return (unsigned int) getAs((unsigned long long*)0);
}
signed long Value::getAs(signed long*) const {
return (long) getAs((signed long long*)0);
}
unsigned long Value::getAs(unsigned long*) const {
return (signed long) getAs((unsigned long long*)0);
}
signed long long Value::getAs(signed long long*) const {
return getGV().IntVal.getSExtValue();
}
unsigned long long Value::getAs(unsigned long long*) const {
return getGV().IntVal.getZExtValue();
}
} // namespace cling

View File

@ -18,6 +18,7 @@
#include "clang/AST/Type.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include <string>
#include <cstdio>