2013-02-22 19:59:54 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@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.
2013-02-22 19:59:54 +04:00
//------------------------------------------------------------------------------
# include "cling/Interpreter/Value.h"
2014-02-27 01:37:16 +04:00
# include "llvm/Support/raw_ostream.h"
# include "clang/AST/ASTContext.h"
2013-02-22 19:59:54 +04:00
# include "clang/AST/CanonicalType.h"
2014-02-27 01:37:16 +04:00
# include "clang/AST/Type.h"
# include "clang/Frontend/CompilerInstance.h"
# include "cling/Interpreter/Interpreter.h"
# include "cling/Utils/AST.h"
2013-02-22 19:59:54 +04:00
2014-02-23 02:54:28 +04:00
namespace {
///\brief The allocation starts with this layout; it is followed by the
/// value's object at m_Payload. This class does not inherit from
/// llvm::RefCountedBase because deallocation cannot use this type but must
/// free the character array.
2014-04-02 17:18:25 +04:00
2014-02-23 02:54:28 +04:00
class AllocatedValue {
public :
typedef void ( * DtorFunc_t ) ( void * ) ;
2013-02-22 19:59:54 +04:00
2014-02-23 02:54:28 +04:00
private :
///\brief The reference count - once 0, this object will be deallocated.
mutable unsigned m_RefCnt ;
2013-02-26 15:14:05 +04:00
2014-02-27 01:37:16 +04:00
///\brief The destructor function.
DtorFunc_t m_DtorFunc ;
2014-02-23 02:54:28 +04:00
2014-04-11 10:51:33 +04:00
///\brief The size of the allocation (for arrays)
unsigned long m_AllocSize ;
///\brief The number of elements in the array
unsigned long m_NElements ;
2014-02-23 02:54:28 +04:00
///\brief The start of the allocation.
char m_Payload [ 1 ] ;
2014-04-02 17:18:25 +04:00
static DtorFunc_t PtrToFunc ( void * ptr ) {
union {
void * m_Ptr ;
DtorFunc_t m_Func ;
} ;
m_Ptr = ptr ;
return m_Func ;
}
2014-02-23 02:54:28 +04:00
public :
///\brief Initialize the storage management part of the allocated object.
2014-02-27 01:37:16 +04:00
/// The allocator is referencing it, thus initialize m_RefCnt with 1.
///\param [in] dtorFunc - the function to be called before deallocation.
2014-04-11 10:51:33 +04:00
AllocatedValue ( void * dtorFunc , size_t allocSize , size_t nElements ) :
m_RefCnt ( 1 ) , m_DtorFunc ( PtrToFunc ( dtorFunc ) ) , m_AllocSize ( allocSize ) ,
m_NElements ( nElements )
{ }
2014-02-23 02:54:28 +04:00
2014-02-27 01:37:16 +04:00
char * getPayload ( ) { return m_Payload ; }
2014-02-23 02:54:28 +04:00
static unsigned getPayloadOffset ( ) {
2014-04-11 10:51:33 +04:00
static const AllocatedValue Dummy ( 0 , 0 , 0 ) ;
2014-02-27 01:37:16 +04:00
return Dummy . m_Payload - ( const char * ) & Dummy ;
2014-02-23 02:54:28 +04:00
}
2013-02-25 19:20:49 +04:00
2014-02-23 02:54:28 +04:00
static AllocatedValue * getFromPayload ( void * payload ) {
2014-02-27 01:37:16 +04:00
return
reinterpret_cast < AllocatedValue * > ( ( char * ) payload - getPayloadOffset ( ) ) ;
2014-02-23 02:54:28 +04:00
}
void Retain ( ) { + + m_RefCnt ; }
///\brief This object must be allocated as a char array. Deallocate it as
/// such.
void Release ( ) {
assert ( m_RefCnt > 0 & & " Reference count is already zero. " ) ;
if ( - - m_RefCnt = = 0 ) {
2014-04-11 10:51:33 +04:00
if ( m_DtorFunc ) {
char * payload = getPayload ( ) ;
for ( size_t el = 0 ; el < m_NElements ; + + el )
( * m_DtorFunc ) ( payload + el * m_AllocSize / m_NElements ) ;
}
2014-02-23 02:54:28 +04:00
delete [ ] ( char * ) this ;
}
}
} ;
2013-02-22 19:59:54 +04:00
}
2014-02-23 02:54:28 +04:00
namespace cling {
2014-03-09 16:53:19 +04:00
Value : : Value ( const Value & other ) :
2014-04-01 18:54:27 +04:00
m_Storage ( other . m_Storage ) , m_Type ( other . m_Type ) {
2014-02-23 02:54:28 +04:00
if ( needsManagedAllocation ( ) )
2014-02-27 01:37:16 +04:00
AllocatedValue : : getFromPayload ( m_Storage . m_Ptr ) - > Retain ( ) ;
2013-02-25 19:20:49 +04:00
}
2014-04-01 18:54:27 +04:00
Value : : Value ( Value & & other ) :
m_Storage ( other . m_Storage ) , m_Type ( other . m_Type ) {
// Invalidate other so it will not release.
other . m_Type = 0 ;
}
2014-02-27 01:37:16 +04:00
Value : : Value ( clang : : QualType clangTy , Interpreter * Interp ) :
2014-02-23 02:54:28 +04:00
m_Type ( clangTy . getAsOpaquePtr ( ) ) {
if ( needsManagedAllocation ( ) )
ManagedAllocate ( Interp ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-04 19:08:55 +04:00
2014-02-27 01:37:16 +04:00
Value & Value : : operator = ( const Value & other ) {
2014-03-09 16:53:19 +04:00
// Release old value.
if ( needsManagedAllocation ( ) )
AllocatedValue : : getFromPayload ( m_Storage . m_Ptr ) - > Release ( ) ;
// Retain new one.
2014-02-27 01:37:16 +04:00
m_Type = other . m_Type ;
2014-03-09 16:53:19 +04:00
m_Storage = other . m_Storage ;
2014-02-23 02:54:28 +04:00
if ( needsManagedAllocation ( ) )
2014-02-27 01:37:16 +04:00
AllocatedValue : : getFromPayload ( m_Storage . m_Ptr ) - > Retain ( ) ;
return * this ;
2014-02-04 19:08:55 +04:00
}
2014-04-01 18:54:27 +04:00
Value & Value : : operator = ( Value & & other ) {
// Release old value.
if ( needsManagedAllocation ( ) )
AllocatedValue : : getFromPayload ( m_Storage . m_Ptr ) - > Release ( ) ;
// Move new one.
m_Type = other . m_Type ;
m_Storage = other . m_Storage ;
// Invalidate other so it will not release.
other . m_Type = 0 ;
return * this ;
}
2014-02-27 01:37:16 +04:00
Value : : ~ Value ( ) {
2014-02-23 02:54:28 +04:00
if ( needsManagedAllocation ( ) )
2014-02-27 01:37:16 +04:00
AllocatedValue : : getFromPayload ( m_Storage . m_Ptr ) - > Release ( ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-23 02:54:28 +04:00
clang : : QualType Value : : getType ( ) const {
return clang : : QualType : : getFromOpaquePtr ( m_Type ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-23 02:54:28 +04:00
bool Value : : isValid ( ) const { return ! getType ( ) . isNull ( ) ; }
2013-02-22 19:59:54 +04:00
2014-03-09 16:53:19 +04:00
bool Value : : isVoid ( const clang : : ASTContext & Ctx ) const {
return isValid ( ) & & Ctx . hasSameType ( getType ( ) , Ctx . VoidTy ) ;
2013-02-22 19:59:54 +04:00
}
2014-04-11 10:51:33 +04:00
unsigned long Value : : GetNumberOfElements ( ) const {
if ( const clang : : ConstantArrayType * ArrTy
= llvm : : dyn_cast < clang : : ConstantArrayType > ( getType ( ) ) ) {
llvm : : APInt arrSize ( sizeof ( unsigned long ) * 8 , 1 ) ;
do {
arrSize * = ArrTy - > getSize ( ) ;
ArrTy = llvm : : dyn_cast < clang : : ConstantArrayType > ( ArrTy - > getElementType ( )
. getTypePtr ( ) ) ;
} while ( ArrTy ) ;
return ( unsigned long ) arrSize . getZExtValue ( ) ;
}
return 1 ;
}
2013-02-22 19:59:54 +04:00
Value : : EStorageType Value : : getStorageType ( ) const {
2014-02-23 02:54:28 +04:00
const clang : : Type * desugCanon = getType ( ) - > getUnqualifiedDesugaredType ( ) ;
2013-02-22 19:59:54 +04:00
desugCanon = desugCanon - > getCanonicalTypeUnqualified ( ) - > getTypePtr ( )
- > getUnqualifiedDesugaredType ( ) ;
if ( desugCanon - > isSignedIntegerOrEnumerationType ( ) )
return kSignedIntegerOrEnumerationType ;
else if ( desugCanon - > isUnsignedIntegerOrEnumerationType ( ) )
return kUnsignedIntegerOrEnumerationType ;
else if ( desugCanon - > isRealFloatingType ( ) ) {
2014-02-27 01:37:16 +04:00
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 ;
2014-02-23 02:54:28 +04:00
} else if ( desugCanon - > isPointerType ( ) | | desugCanon - > isObjectType ( )
| | desugCanon - > isReferenceType ( ) )
2013-02-22 19:59:54 +04:00
return kPointerType ;
return kUnsupportedType ;
}
2014-02-23 02:54:28 +04:00
bool Value : : needsManagedAllocation ( ) const {
2014-03-09 16:53:19 +04:00
if ( ! isValid ( ) ) return false ;
const clang : : Type * UnqDes = getType ( ) - > getUnqualifiedDesugaredType ( ) ;
2014-04-11 10:51:33 +04:00
return UnqDes - > isRecordType ( ) | | UnqDes - > isConstantArrayType ( )
2014-03-09 16:53:19 +04:00
| | UnqDes - > isMemberPointerType ( ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-23 02:54:28 +04:00
2014-02-27 01:37:16 +04:00
void Value : : ManagedAllocate ( Interpreter * interp ) {
assert ( interp & & " This type requires the interpreter for value allocation " ) ;
2014-02-23 02:54:28 +04:00
void * dtorFunc = 0 ;
2014-04-11 10:51:33 +04:00
clang : : QualType DtorType = getType ( ) ;
// For arrays we destruct the elements.
if ( const clang : : ConstantArrayType * ArrTy
= llvm : : dyn_cast < clang : : ConstantArrayType > ( DtorType . getTypePtr ( ) ) ) {
DtorType = ArrTy - > getElementType ( ) ;
}
if ( const clang : : RecordType * RTy = DtorType - > getAs < clang : : RecordType > ( ) )
2014-02-27 01:37:16 +04:00
dtorFunc = GetDtorWrapperPtr ( RTy - > getDecl ( ) , * interp ) ;
2014-02-23 02:54:28 +04:00
2014-02-27 01:37:16 +04:00
const clang : : ASTContext & ctx = interp - > getCI ( ) - > getASTContext ( ) ;
2014-02-23 02:54:28 +04:00
unsigned payloadSize = ctx . getTypeSizeInChars ( getType ( ) ) . getQuantity ( ) ;
2014-02-27 01:37:16 +04:00
char * alloc = new char [ AllocatedValue : : getPayloadOffset ( ) + payloadSize ] ;
2014-04-11 10:51:33 +04:00
AllocatedValue * allocVal = new ( alloc ) AllocatedValue ( dtorFunc , payloadSize ,
GetNumberOfElements ( ) ) ;
2014-02-23 02:54:28 +04:00
m_Storage . m_Ptr = allocVal - > getPayload ( ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-23 02:54:28 +04:00
2014-02-27 01:37:16 +04:00
void Value : : AssertOnUnsupportedTypeCast ( ) const {
assert ( " unsupported type in Value, cannot cast simplistically! " & & 0 ) ;
2013-02-22 19:59:54 +04:00
}
2014-02-27 01:37:16 +04:00
/// \brief Get the function address of the wrapper of the destructor.
void * Value : : GetDtorWrapperPtr ( const clang : : RecordDecl * RD ,
Interpreter & interp ) const {
std : : string funcname ;
{
llvm : : raw_string_ostream namestr ( funcname ) ;
namestr < < " __cling_StoredValue_Destruct_ " < < RD ;
}
std : : string code ( " extern \" C \" void " ) ;
{
2014-04-11 10:51:33 +04:00
clang : : QualType RDQT ( RD - > getTypeForDecl ( ) , 0 ) ;
2014-02-27 01:37:16 +04:00
std : : string typeName
2014-04-11 10:51:33 +04:00
= utils : : TypeName : : GetFullyQualifiedName ( RDQT , RD - > getASTContext ( ) ) ;
2014-02-27 01:37:16 +04:00
std : : string dtorName = RD - > getNameAsString ( ) ;
code + = funcname + " (void* obj){(( " + typeName + " *)obj)->~ "
+ dtorName + " ();} " ;
}
return interp . compileFunction ( funcname , code , true /*ifUniq*/ ,
false /*withAccessControl*/ ) ;
}
2013-02-22 19:59:54 +04:00
} // namespace cling