2727
2828#include " llvm/IR/GlobalValue.h"
2929#include " llvm/IR/Module.h"
30+ #include " llvm/Support/Host.h"
3031#include " llvm/Support/raw_os_ostream.h"
3132
32- #include < stddef.h> // offsetof
33-
3433namespace {
3534
3635 // /\brief The allocation starts with this layout; it is followed by the
@@ -53,51 +52,78 @@ namespace {
5352 size_t m_NElements;
5453
5554 // /\brief The reference count - once 0, this object will be deallocated.
56- size_t m_RefCnt;
55+ // / Hopefully 2^55 - 1 references should be enough as the last byte is
56+ // / used for flag storage.
57+ enum { SizeBytes = sizeof (size_t ), ConstructedByte = SizeBytes - 1 };
58+ union {
59+ size_t m_Count;
60+ char m_Bytes[SizeBytes];
61+ };
62+
63+ size_t UpdateRefCount (int Amount) {
64+ // Bit shift the bytes used in m_Bytes for representing an integer
65+ // respecting endian-ness and which of those bytes are significant.
66+ assert ((Amount == 1 || Amount == -1 ) && " Invalid amount" );
67+ union { size_t m_Count; char m_Bytes[SizeBytes]; } RC = { 0 };
68+ const size_t NBytes = SizeBytes - sizeof (char );
69+ const size_t Endian = llvm::sys::IsBigEndianHost;
70+ ::memcpy (&RC.m_Bytes[Endian], &m_Bytes[0 ], NBytes);
71+ RC.m_Count += Amount;
72+ ::memcpy (&m_Bytes[0 ], &RC.m_Bytes[Endian], NBytes);
73+ return RC.m_Count ;
74+ }
75+
76+ static AllocatedValue* FromPtr (void * Ptr) {
77+ return reinterpret_cast <AllocatedValue*>(reinterpret_cast <char *>(Ptr) -
78+ sizeof (AllocatedValue));
79+ }
5780
58- public:
5981 // /\brief Initialize the storage management part of the allocated object.
6082 // / The allocator is referencing it, thus initialize m_RefCnt with 1.
6183 // /\param [in] dtorFunc - the function to be called before deallocation.
62- AllocatedValue (void * dtorFunc, size_t allocSize, size_t nElements) :
63- m_DtorFunc (cling::utils::VoidToFunctionPtr<DtorFunc_t>(dtorFunc)),
64- m_AllocSize (allocSize), m_NElements(nElements), m_RefCnt(1 )
65- {}
66-
67- static constexpr unsigned getPayloadOffset () {
68- static_assert (std::is_standard_layout<AllocatedValue>::value,
69- " Cannot use offsetof" );
70- static_assert (((offsetof (AllocatedValue, m_RefCnt) + sizeof (m_RefCnt)) %
71- sizeof (size_t )) == 0 ,
72- " Buffer may not be machine aligned" );
73- return offsetof (AllocatedValue, m_RefCnt) + sizeof (m_RefCnt);
84+ AllocatedValue (size_t Size, size_t NElem, DtorFunc_t Dtor) :
85+ m_DtorFunc (Dtor), m_AllocSize(Size), m_NElements(NElem) {
86+ m_Count = 0 ;
87+ UpdateRefCount (1 );
7488 }
7589
76- char * getPayload () {
77- return reinterpret_cast <char *>(&m_RefCnt) + sizeof (m_RefCnt);
78- }
90+ public:
91+ // /\brief Create an AllocatedValue whose lifetime is reference counted.
92+ // / \returns The address of the writeable client data.
93+ static void * Create (size_t Size, size_t NElem, DtorFunc_t Dtor) {
94+ char * Alloc = new char [sizeof (AllocatedValue) + Size];
95+ AllocatedValue* AV = new (Alloc) AllocatedValue (Size, NElem, Dtor);
96+
97+ static_assert (std::is_standard_layout<AllocatedValue>::value, " padding" );
98+ static_assert (sizeof (m_Count) == sizeof (m_Bytes), " union padding" );
99+ static_assert (((offsetof (AllocatedValue, m_Count) + sizeof (m_Count)) %
100+ SizeBytes) == 0 ,
101+ " Buffer may not be machine aligned" );
102+ assert (&Alloc[sizeof (AllocatedValue) - 1 ] == &AV->m_Bytes [SizeBytes - 1 ]
103+ && " Padded AllocatedValue" );
79104
80- static AllocatedValue* getFromPayload (void * payload) {
81- return
82- reinterpret_cast <AllocatedValue*>((char *)payload - getPayloadOffset ());
105+ // Give back the first client writable byte.
106+ return AV->m_Bytes + SizeBytes;
83107 }
84108
85- void Retain () { ++m_RefCnt; }
109+ static void Retain (void * Ptr) {
110+ FromPtr (Ptr)->UpdateRefCount (1 );
111+ }
86112
87113 // /\brief This object must be allocated as a char array. Deallocate it as
88114 // / such.
89- void Release () {
90- assert (m_RefCnt > 0 && " Reference count is already zero. " );
91- if (--m_RefCnt == 0 ) {
92- if (m_DtorFunc) {
93- assert (m_NElements && " No elements!" );
94- char * Payload = getPayload ( );
95- const auto Skip = m_AllocSize / m_NElements;
96- while (m_NElements-- != 0 )
97- (*m_DtorFunc)(Payload + m_NElements * Skip);
115+ static void Release (void * Ptr ) {
116+ AllocatedValue* AV = FromPtr (Ptr );
117+ if (AV-> UpdateRefCount (- 1 ) == 0 ) {
118+ if (AV-> m_DtorFunc && AV-> m_Bytes [ConstructedByte] ) {
119+ assert (AV-> m_NElements && " No elements!" );
120+ char * Payload = reinterpret_cast < char *>(Ptr );
121+ const auto Skip = AV-> m_AllocSize / AV-> m_NElements ;
122+ while (AV-> m_NElements -- != 0 )
123+ (*AV-> m_DtorFunc )(Payload + AV-> m_NElements * Skip);
98124 }
99125 this ->~AllocatedValue ();
100- delete [] ( char *) this ;
126+ delete [] reinterpret_cast < char *>(AV) ;
101127 }
102128 }
103129 };
@@ -109,7 +135,7 @@ namespace cling {
109135 m_Storage (other.m_Storage), m_StorageType(other.m_StorageType),
110136 m_Type (other.m_Type), m_Interpreter(other.m_Interpreter) {
111137 if (other.needsManagedAllocation ())
112- AllocatedValue::getFromPayload (m_Storage.m_Ptr )-> Retain ( );
138+ AllocatedValue::Retain (m_Storage.m_Ptr );
113139 }
114140
115141 Value::Value (clang::QualType clangTy, Interpreter& Interp):
@@ -123,22 +149,22 @@ namespace cling {
123149 Value& Value::operator =(const Value& other) {
124150 // Release old value.
125151 if (needsManagedAllocation ())
126- AllocatedValue::getFromPayload (m_Storage.m_Ptr )-> Release ( );
152+ AllocatedValue::Release (m_Storage.m_Ptr );
127153
128154 // Retain new one.
129155 m_Type = other.m_Type ;
130156 m_Storage = other.m_Storage ;
131157 m_StorageType = other.m_StorageType ;
132158 m_Interpreter = other.m_Interpreter ;
133159 if (needsManagedAllocation ())
134- AllocatedValue::getFromPayload (m_Storage.m_Ptr )-> Retain ( );
160+ AllocatedValue::Retain (m_Storage.m_Ptr );
135161 return *this ;
136162 }
137163
138164 Value& Value::operator =(Value&& other) {
139165 // Release old value.
140166 if (needsManagedAllocation ())
141- AllocatedValue::getFromPayload (m_Storage.m_Ptr )-> Release ( );
167+ AllocatedValue::Release (m_Storage.m_Ptr );
142168
143169 // Move new one.
144170 m_Type = other.m_Type ;
@@ -153,7 +179,7 @@ namespace cling {
153179
154180 Value::~Value () {
155181 if (needsManagedAllocation ())
156- AllocatedValue::getFromPayload (m_Storage.m_Ptr )-> Release ( );
182+ AllocatedValue::Release (m_Storage.m_Ptr );
157183 }
158184
159185 clang::QualType Value::getType () const {
@@ -211,22 +237,24 @@ namespace cling {
211237
212238 void Value::ManagedAllocate () {
213239 assert (needsManagedAllocation () && " Does not need managed allocation" );
214- void * dtorFunc = 0 ;
215- clang::QualType DtorType = getType ();
240+ const clang::QualType Ty = getType ();
241+ clang::QualType DtorTy = Ty;
242+
216243 // For arrays we destruct the elements.
217- if (const clang::ConstantArrayType* ArrTy
218- = llvm::dyn_cast<clang::ConstantArrayType>(DtorType .getTypePtr ())) {
219- DtorType = ArrTy->getElementType ();
244+ if (const clang::ConstantArrayType* ArrTy =
245+ llvm::dyn_cast<clang::ConstantArrayType>(Ty .getTypePtr ())) {
246+ DtorTy = ArrTy->getElementType ();
220247 }
221- if (const clang::RecordType* RTy = DtorType->getAs <clang::RecordType>())
222- dtorFunc = m_Interpreter->compileDtorCallFor (RTy->getDecl ());
223-
224- const clang::ASTContext& ctx = getASTContext ();
225- const auto payloadSize = ctx.getTypeSizeInChars (getType ()).getQuantity ();
226- char * alloc = new char [AllocatedValue::getPayloadOffset () + payloadSize];
227- AllocatedValue* allocVal = new (alloc) AllocatedValue (dtorFunc, payloadSize,
228- GetNumberOfElements ());
229- m_Storage.m_Ptr = allocVal->getPayload ();
248+
249+ AllocatedValue::DtorFunc_t DtorFunc = nullptr ;
250+ if (const clang::RecordType* RTy = DtorTy->getAs <clang::RecordType>()) {
251+ DtorFunc = cling::utils::VoidToFunctionPtr<AllocatedValue::DtorFunc_t>(
252+ m_Interpreter->compileDtorCallFor (RTy->getDecl ()));
253+ }
254+
255+ m_Storage.m_Ptr = AllocatedValue::Create (
256+ getASTContext ().getTypeSizeInChars (Ty).getQuantity (),
257+ GetNumberOfElements (), DtorFunc);
230258 }
231259
232260 void Value::AssertOnUnsupportedTypeCast () const {
0 commit comments