Skip to content

Commit 727ad30

Browse files
author
devsh
committed
make sure to run destructors for all IR nodes
1 parent 54aad34 commit 727ad30

File tree

1 file changed

+54
-21
lines changed

1 file changed

+54
-21
lines changed

include/nbl/asset/material_compiler3/CNodePool.h

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class CNodePool : public core::IReferenceCounted
167167
const uint32_t size = T::calc_size(args...);
168168
const Handle retval = alloc(size,alignof(T));
169169
if (retval)
170-
new(deref<T>(retval)) T(std::forward<Args>(args)...);
170+
std::construct_at<T>(deref<T>(retval),std::forward<Args>(args)...);
171171
return retval;
172172
}
173173
// delete
@@ -176,25 +176,12 @@ class CNodePool : public core::IReferenceCounted
176176
{
177177
T* ptr = deref<T>(h);
178178
const uint32_t size = ptr->getSize();
179-
ptr->~T();
179+
std::destroy_at<T>(ptr);
180+
// wipe v-table to mark as dead (so `~CNodePool` doesn't run destructor twice)
181+
memset(static_cast<INode*>(ptr),0,sizeof(INode));
180182
free(h,size);
181183
}
182184

183-
// for now using KISS, we can use geeneralpupose allocator later
184-
struct Chunk
185-
{
186-
inline Handle::value_t alloc(const uint32_t size, const uint16_t alignment)
187-
{
188-
return m_alloc.alloc_addr(size,alignment);
189-
}
190-
inline void free(const Handle::value_t addr, const uint32_t size)
191-
{
192-
m_alloc.free_addr(addr,size);
193-
}
194-
195-
core::LinearAddressAllocatorST<Handle::value_t> m_alloc;
196-
uint8_t* m_data;
197-
};
198185
inline CNodePool(const uint8_t _chunkSizeLog2, const uint8_t _maxNodeAlignLog2, refctd_pmr_t&& _pmr) :
199186
m_chunkSizeLog2(_chunkSizeLog2), m_maxNodeAlignLog2(_maxNodeAlignLog2), m_pmr(_pmr ? std::move(_pmr):core::getDefaultMemoryResource())
200187
{
@@ -206,19 +193,65 @@ class CNodePool : public core::IReferenceCounted
206193
const auto chunkAlign = 0x1u<<m_maxNodeAlignLog2;
207194
for (auto& chunk : m_chunks)
208195
{
209-
// TODO: destroy nodes allocated from chunk
196+
for (auto handleOff=chunk.m_alloc.get_total_size(); handleOff<chunkSize; handleOff+=sizeof(Handle))
197+
{
198+
const auto pHandle = reinterpret_cast<const Handle*>(chunk.m_data+handleOff);
199+
if (auto* node=deref<INode>({.value=*pHandle}); node)
200+
std::destroy_at(node);
201+
}
210202
m_pmr->deallocate(chunk.m_data,chunkSize,chunkAlign);
211203
}
212204
}
213205

214206
private:
207+
struct Chunk
208+
{
209+
inline Handle::value_t alloc(const uint32_t size, const uint16_t alignment)
210+
{
211+
const auto retval = m_alloc.alloc_addr(size,alignment);
212+
// successful allocation, time for some book keeping
213+
constexpr auto invalid_address = decltype(m_alloc)::invalid_address;
214+
if (retval!=invalid_address)
215+
{
216+
// we keep a list of all the allocated nodes at the back of a chunk
217+
const auto newSize = m_alloc.get_total_size()-sizeof(retval);
218+
// handle no space left for bookkeeping case
219+
if (retval+size>newSize)
220+
{
221+
free(retval,size);
222+
return invalid_address;
223+
}
224+
// clear vtable to mark as not initialized yet
225+
memset(m_data+retval,0,sizeof(INode));
226+
*reinterpret_cast<Handle::value_t*>(m_data+newSize) = retval;
227+
// shrink allocator
228+
m_alloc = decltype(m_alloc)(newSize,std::move(m_alloc));
229+
}
230+
return retval;
231+
}
232+
inline void free(const Handle::value_t addr, const uint32_t size)
233+
{
234+
m_alloc.free_addr(addr,size);
235+
}
236+
237+
// for now using KISS, we can use geeneralpupose allocator later
238+
core::LinearAddressAllocatorST<Handle::value_t> m_alloc;
239+
uint8_t* m_data;
240+
};
215241
inline uint32_t getChunkIx(const Handle& h) {h.value>>m_chunkSizeLog2;}
216242

217243
template<typename T> requires (std::is_base_of_v<INode,T> && !std::is_const_v<T>)
218244
inline T* deref(const Handle& h)
219245
{
220-
const auto loAddr = h.value&(0x1u<<m_chunkSizeLog2);
221-
return reinterpret_cast<T*>(chunks[getChunkIx(h)].data()+loAddr);
246+
const auto hiAddr = getChunkIx(h);
247+
assert(hiAddr<chunks.size());
248+
{
249+
const auto loAddr = h.value&(0x1u<<m_chunkSizeLog2);
250+
void* ptr = chunks[hiAddr].data()+loAddr;
251+
if (ptr) // vtable not wiped
252+
return reinterpret_cast<T*>(ptr);
253+
}
254+
return nullptr;
222255
}
223256
template<typename T> requires (std::is_base_of_v<INode,T> && std::is_const_v<T>)
224257
inline T* deref(const Handle& h) const
@@ -228,7 +261,7 @@ class CNodePool : public core::IReferenceCounted
228261

229262
core::vector<Chunk> m_chunks;
230263
refctd_pmr_t m_pmr;
231-
const uint8_t m_chunkSizeLog2;
264+
const uint8_t m_chunkSizeLog2; // maybe hardcode chunk sizes to 64kb ?
232265
const uint8_t m_maxNodeAlignLog2;
233266
};
234267

0 commit comments

Comments
 (0)