summaryrefslogtreecommitdiffstats
path: root/source/core
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-09-14 14:16:28 -0400
committerGitHub <noreply@github.com>2018-09-14 14:16:28 -0400
commit3c505c22673701339d35eb2151f01c16eb3c78c3 (patch)
treeff21543fcc846c693cbb6aba43a4e8ae9918f600 /source/core
parente1c934972509f4bbd2c05affe565f91e7a1e6c16 (diff)
Improvements around IR representation and memory usage (#635)
* * Remove dispose from IRInst * Use MemoryArena instead of MemoryPool * Make all IRInst not require Dtor - by having ref counted array store ptrs that need freeing * Increase block size - typically compilation is 2Mb of IR space(!) * Fix issues around StringRepresentation::equal because null has special meaning. * Don't bother to construct as String to compare StringRepresentation, just used UnownedStringSlice. * Added fromLiteral support to UnownedStringSlice and use instead of strlen version. * Use more conventional way to test StringRepresentation against a String. * Fix gcc/clang template problem with cast.
Diffstat (limited to 'source/core')
-rw-r--r--source/core/slang-memory-arena.cpp10
-rw-r--r--source/core/slang-memory-arena.h106
-rw-r--r--source/core/slang-string.h177
-rw-r--r--source/core/smart-pointer.h19
4 files changed, 195 insertions, 117 deletions
diff --git a/source/core/slang-memory-arena.cpp b/source/core/slang-memory-arena.cpp
index 4d8b2ed2a..a0a89155c 100644
--- a/source/core/slang-memory-arena.cpp
+++ b/source/core/slang-memory-arena.cpp
@@ -222,6 +222,16 @@ MemoryArena::Block* MemoryArena::_newBlock(size_t allocSize, size_t alignment)
return block;
}
+void* MemoryArena::_allocateAlignedFromNewBlockAndZero(size_t sizeInBytes, size_t alignment)
+{
+ void* mem = _allocateAlignedFromNewBlock(sizeInBytes, alignment);
+ if (mem)
+ {
+ ::memset(mem, 0, sizeInBytes);
+ }
+ return mem;
+}
+
void* MemoryArena::_allocateAlignedFromNewBlock(size_t size, size_t alignment)
{
// Make sure init has been called (or has been set up in parameterized constructor)
diff --git a/source/core/slang-memory-arena.h b/source/core/slang-memory-arena.h
index 1c59ee7d7..54b380b32 100644
--- a/source/core/slang-memory-arena.h
+++ b/source/core/slang-memory-arena.h
@@ -46,7 +46,7 @@ public:
typedef MemoryArena ThisType;
/** The minimum alignment of the backing memory allocator.
- NOTE! That this should not be greater than the alignment of the underlying allocator.
+ NOTE! That this should not be greater than the alignment of the underlying allocator, and should never be less than sizeof(void*).
*/
static const size_t kMinAlignment = sizeof(void*);
/** Determines if an allocation is consistent with an allocation from this arena.
@@ -60,7 +60,7 @@ public:
/** Initialize the arena with specified block size and alignment
If the arena has been previously initialized will free and deallocate all memory */
- void init(size_t blockSize, size_t blockAlignment = kMinAlignment);
+ void init(size_t blockSizeInBytes, size_t blockAlignment = kMinAlignment);
/** Allocate some memory of at least size bytes without having any specific alignment.
@@ -72,6 +72,11 @@ public:
@return The allocation. Can be nullptr if backing allocator was not able to request required memory */
void* allocate(size_t sizeInBytes);
+ /** Same as allocate, but zeros memory before returning
+ @param size The size of the allocation requested (in bytes and must be > 0).
+ @return The allocation. Can be nullptr if backing allocator was not able to request required memory */
+ void* allocateAndZero(size_t sizeInBytes);
+
/** Allocate some aligned memory of at least size bytes
@param size Size of allocation wanted (must be > 0).
@param alignment Alignment of allocation - must be a power of 2.
@@ -100,15 +105,15 @@ public:
/// Allocate an array of a specified type. NOTE Constructor of T is NOT executed.
template <typename T>
- T* allocateArray(size_t size);
+ T* allocateArray(size_t numElems);
/// Allocate an array of a specified type, and copy array passed into it.
template <typename T>
- T* allocateAndCopyArray(const T* src, size_t size);
+ T* allocateAndCopyArray(const T* src, size_t numElems);
/// Allocate an array of a specified type, and zero it.
template <typename T>
- T* allocateAndZeroArray(size_t size);
+ T* allocateAndZeroArray(size_t numElems);
/** Deallocates all allocated memory. That backing memory will generally not be released so
subsequent allocation will be fast, and from the same memory. Note though that 'oversize' blocks
@@ -160,13 +165,14 @@ protected:
/// Create a new block with regular block alignment
Block* _newNormalBlock();
/// Allocates a new block with allocSize and alignment
- Block* _newBlock(size_t allocSize, size_t alignment);
+ Block* _newBlock(size_t allocSizeInBytes, size_t alignment);
- void* _allocateAlignedFromNewBlock(size_t size, size_t alignment);
+ void* _allocateAlignedFromNewBlock(size_t sizeInBytes, size_t alignment);
+ void* _allocateAlignedFromNewBlockAndZero(size_t sizeInBytes, size_t alignment);
/// Find block that contains data/size that is _NOT_ current (ie not first block in m_usedBlocks)
- const Block* _findNonCurrent(const void* data, size_t size) const;
- const Block* _findInBlocks(const Block* block, const void* data, size_t size) const;
+ const Block* _findNonCurrent(const void* data, size_t sizeInBytes) const;
+ const Block* _findInBlocks(const Block* block, const void* data, size_t sizeInBytes) const;
size_t _calcBlocksUsedMemory(const Block* block) const;
size_t _calcBlocksAllocatedMemory(const Block* block) const;
@@ -192,7 +198,7 @@ protected:
};
// --------------------------------------------------------------------------
-inline bool MemoryArena::isValid(const void* data, size_t size) const
+SLANG_FORCE_INLINE bool MemoryArena::isValid(const void* data, size_t size) const
{
assert(size);
uint8_t* ptr = (uint8_t*)data;
@@ -200,12 +206,12 @@ inline bool MemoryArena::isValid(const void* data, size_t size) const
}
// --------------------------------------------------------------------------
-SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t size)
+SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t sizeInBytes)
{
- assert(size > 0);
+ assert(sizeInBytes > 0);
// Align with the minimum alignment
uint8_t* mem = m_current;
- uint8_t* end = mem + size;
+ uint8_t* end = mem + sizeInBytes;
if (end <= m_end)
{
m_current = end;
@@ -213,33 +219,54 @@ SLANG_FORCE_INLINE void* MemoryArena::allocateUnaligned(size_t size)
}
else
{
- return _allocateAlignedFromNewBlock(size, kMinAlignment);
+ return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment);
}
}
// --------------------------------------------------------------------------
-SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t size)
+SLANG_FORCE_INLINE void* MemoryArena::allocate(size_t sizeInBytes)
{
- assert(size > 0);
+ assert(sizeInBytes > 0);
// Align with the minimum alignment
const size_t alignMask = kMinAlignment - 1;
uint8_t* mem = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask);
- if (mem + size <= m_end)
+ if (mem + sizeInBytes <= m_end)
{
- m_current = mem + size;
+ m_current = mem + sizeInBytes;
return mem;
}
else
{
- return _allocateAlignedFromNewBlock(size, kMinAlignment);
+ return _allocateAlignedFromNewBlock(sizeInBytes, kMinAlignment);
}
}
// --------------------------------------------------------------------------
-inline void* MemoryArena::allocateAligned(size_t size, size_t alignment)
+SLANG_FORCE_INLINE void* MemoryArena::allocateAndZero(size_t sizeInBytes)
{
- assert(size > 0);
+ // Implement without calling ::allocate, because in most common case we don't need to test for null.
+ assert(sizeInBytes > 0);
+ // Align with the minimum alignment
+ const size_t alignMask = kMinAlignment - 1;
+ uint8_t* mem = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask);
+ uint8_t* end = mem + sizeInBytes;
+ if ( end <= m_end)
+ {
+ ::memset(mem, 0, sizeInBytes);
+ m_current = end;
+ return mem;
+ }
+ else
+ {
+ return _allocateAlignedFromNewBlockAndZero(sizeInBytes, kMinAlignment);
+ }
+}
+
+// --------------------------------------------------------------------------
+SLANG_FORCE_INLINE void* MemoryArena::allocateAligned(size_t sizeInBytes, size_t alignment)
+{
+ assert(sizeInBytes > 0);
// Alignment must be a power of 2
assert(((alignment - 1) & alignment) == 0);
@@ -247,19 +274,19 @@ inline void* MemoryArena::allocateAligned(size_t size, size_t alignment)
const size_t alignMask = alignment - 1;
uint8_t* memory = (uint8_t*)((size_t(m_current) + alignMask) & ~alignMask);
- if (memory + size <= m_end)
+ if (memory + sizeInBytes <= m_end)
{
- m_current = memory + size;
+ m_current = memory + sizeInBytes;
return memory;
}
else
{
- return _allocateAlignedFromNewBlock(size, alignment);
+ return _allocateAlignedFromNewBlock(sizeInBytes, alignment);
}
}
// --------------------------------------------------------------------------
-inline const char* MemoryArena::allocateString(const char* str)
+SLANG_FORCE_INLINE const char* MemoryArena::allocateString(const char* str)
{
size_t size = ::strlen(str);
if (size == 0)
@@ -272,43 +299,42 @@ inline const char* MemoryArena::allocateString(const char* str)
}
// --------------------------------------------------------------------------
-inline const char* MemoryArena::allocateString(const char* chars, size_t charsCount)
+inline const char* MemoryArena::allocateString(const char* chars, size_t numChars)
{
- if (charsCount == 0)
+ if (numChars == 0)
{
return "";
}
- char* dst = (char*)allocateUnaligned(charsCount + 1);
- ::memcpy(dst, chars, charsCount);
+ char* dst = (char*)allocateUnaligned(numChars + 1);
+ ::memcpy(dst, chars, numChars);
// Add null-terminating zero
- dst[charsCount] = 0;
+ dst[numChars] = 0;
return dst;
}
// --------------------------------------------------------------------------
template <typename T>
-inline T* MemoryArena::allocate()
+SLANG_FORCE_INLINE T* MemoryArena::allocate()
{
return reinterpret_cast<T*>(allocateAligned(sizeof(T), SLANG_ALIGN_OF(T)));
}
// --------------------------------------------------------------------------
template <typename T>
-inline T* MemoryArena::allocateArray(size_t count)
+SLANG_FORCE_INLINE T* MemoryArena::allocateArray(size_t numElems)
{
- return (count > 0) ? reinterpret_cast<T*>(allocateAligned(sizeof(T) * count, SLANG_ALIGN_OF(T))) : nullptr;
+ return (numElems > 0) ? reinterpret_cast<T*>(allocateAligned(sizeof(T) * numElems, SLANG_ALIGN_OF(T))) : nullptr;
}
// --------------------------------------------------------------------------
template <typename T>
-inline T* MemoryArena::allocateAndCopyArray(const T* arr, size_t size)
+SLANG_FORCE_INLINE T* MemoryArena::allocateAndCopyArray(const T* arr, size_t numElems)
{
SLANG_COMPILE_TIME_ASSERT(std::is_pod<T>::value);
-
- if (size > 0)
+ if (numElems > 0)
{
- const size_t totalSize = sizeof(T) * size;
+ const size_t totalSize = sizeof(T) * numElems;
void* ptr = allocateAligned(totalSize, SLANG_ALIGN_OF(T));
::memcpy(ptr, arr, totalSize);
return reinterpret_cast<T*>(ptr);
@@ -318,11 +344,11 @@ inline T* MemoryArena::allocateAndCopyArray(const T* arr, size_t size)
// ---------------------------------------------------------------------------
template <typename T>
-inline T* MemoryArena::allocateAndZeroArray(size_t size)
+SLANG_FORCE_INLINE T* MemoryArena::allocateAndZeroArray(size_t numElems)
{
- if (size > 0)
+ if (numElems > 0)
{
- const size_t totalSize = sizeof(T) * size;
+ const size_t totalSize = sizeof(T) * numElems;
void* ptr = allocateAligned(totalSize, SLANG_ALIGN_OF(T));
::memset(ptr, 0, totalSize);
return reinterpret_cast<T*>(ptr);
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index a67597360..2609b37ab 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -62,84 +62,15 @@ namespace Slang
return (((unsigned char)ch) & 0xC0) == 0x80;
}
- // A `StringRepresentation` provides the backing storage for
- // all reference-counted string-related types.
- class StringRepresentation : public RefObject
- {
- public:
- UInt length;
- UInt capacity;
-
- UInt getLength()
- {
- return length;
- }
-
- char* getData()
- {
- return (char*) (this + 1);
- }
-
- static StringRepresentation* createWithCapacityAndLength(UInt capacity, UInt length)
- {
- SLANG_ASSERT(capacity >= length);
- void* allocation = operator new(sizeof(StringRepresentation) + capacity + 1);
- StringRepresentation* obj = new(allocation) StringRepresentation();
- obj->capacity = capacity;
- obj->length = length;
- obj->getData()[length] = 0;
- return obj;
- }
-
- static StringRepresentation* createWithCapacity(UInt capacity)
- {
- return createWithCapacityAndLength(capacity, 0);
- }
-
- static StringRepresentation* createWithLength(UInt length)
- {
- return createWithCapacityAndLength(length, length);
- }
-
- StringRepresentation* cloneWithCapacity(UInt newCapacity)
- {
- StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length);
- memcpy(getData(), newObj->getData(), length + 1);
- return newObj;
- }
-
- StringRepresentation* clone()
- {
- return cloneWithCapacity(length);
- }
-
- StringRepresentation* ensureCapacity(UInt required)
- {
- if (capacity >= required) return this;
-
- UInt newCapacity = capacity;
- if (!newCapacity) newCapacity = 16; // TODO: figure out good value for minimum capacity
-
- while (newCapacity < required)
- {
- newCapacity = 2 * newCapacity;
- }
-
- return cloneWithCapacity(newCapacity);
- }
- };
-
- class String;
-
struct UnownedStringSlice
{
public:
UnownedStringSlice()
: beginData(nullptr)
- , endData(0)
+ , endData(nullptr)
{}
- explicit UnownedStringSlice(char const* a):
+ explicit UnownedStringSlice(char const* a) :
beginData(a),
endData(a + strlen(a))
{}
@@ -147,6 +78,10 @@ namespace Slang
: beginData(b)
, endData(e)
{}
+ UnownedStringSlice(char const* b, size_t len)
+ : beginData(b)
+ , endData(b + len)
+ {}
char const* begin() const
{
@@ -202,11 +137,104 @@ namespace Slang
bool endsWith(UnownedStringSlice const& other) const;
bool endsWith(char const* str) const;
+ template <size_t SIZE>
+ SLANG_FORCE_INLINE static UnownedStringSlice fromLiteral(const char (&in)[SIZE]) { return UnownedStringSlice(in, SIZE - 1); }
+
private:
char const* beginData;
char const* endData;
};
+ // A `StringRepresentation` provides the backing storage for
+ // all reference-counted string-related types.
+ class StringRepresentation : public RefObject
+ {
+ public:
+ UInt length;
+ UInt capacity;
+
+ SLANG_FORCE_INLINE UInt getLength() const
+ {
+ return length;
+ }
+
+ SLANG_FORCE_INLINE char* getData()
+ {
+ return (char*) (this + 1);
+ }
+ SLANG_FORCE_INLINE const char* getData() const
+ {
+ return (const char*)(this + 1);
+ }
+
+ static const char* getData(const StringRepresentation* stringRep)
+ {
+ return stringRep ? stringRep->getData() : "";
+ }
+
+ static UnownedStringSlice asSlice(const StringRepresentation* rep)
+ {
+ return rep ? UnownedStringSlice(rep->getData(), rep->getLength()) : UnownedStringSlice();
+ }
+
+ static bool equal(const StringRepresentation* a, const StringRepresentation* b)
+ {
+ return (a == b) || asSlice(a) == asSlice(b);
+ }
+
+ static StringRepresentation* createWithCapacityAndLength(UInt capacity, UInt length)
+ {
+ SLANG_ASSERT(capacity >= length);
+ void* allocation = operator new(sizeof(StringRepresentation) + capacity + 1);
+ StringRepresentation* obj = new(allocation) StringRepresentation();
+ obj->capacity = capacity;
+ obj->length = length;
+ obj->getData()[length] = 0;
+ return obj;
+ }
+
+ static StringRepresentation* createWithCapacity(UInt capacity)
+ {
+ return createWithCapacityAndLength(capacity, 0);
+ }
+
+ static StringRepresentation* createWithLength(UInt length)
+ {
+ return createWithCapacityAndLength(length, length);
+ }
+
+ StringRepresentation* cloneWithCapacity(UInt newCapacity)
+ {
+ StringRepresentation* newObj = createWithCapacityAndLength(newCapacity, length);
+ memcpy(getData(), newObj->getData(), length + 1);
+ return newObj;
+ }
+
+ StringRepresentation* clone()
+ {
+ return cloneWithCapacity(length);
+ }
+
+ StringRepresentation* ensureCapacity(UInt required)
+ {
+ if (capacity >= required) return this;
+
+ UInt newCapacity = capacity;
+ if (!newCapacity) newCapacity = 16; // TODO: figure out good value for minimum capacity
+
+ while (newCapacity < required)
+ {
+ newCapacity = 2 * newCapacity;
+ }
+
+ return cloneWithCapacity(newCapacity);
+ }
+ };
+
+ class String;
+
+
+
struct UnownedTerminatedStringSlice : public UnownedStringSlice
{
public:
@@ -300,11 +328,12 @@ namespace Slang
RefPtr<StringRepresentation> buffer;
- String(StringRepresentation* buffer)
+ public:
+
+ explicit String(StringRepresentation* buffer)
: buffer(buffer)
{}
- public:
static String FromWString(const wchar_t * wstr);
static String FromWString(const wchar_t * wstr, const wchar_t * wend);
static String FromWChar(const wchar_t ch);
@@ -313,6 +342,8 @@ namespace Slang
{
}
+ SLANG_FORCE_INLINE StringRepresentation* getStringRepresentation() const { return buffer; }
+
const char * begin() const
{
return getData();
diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h
index f45618050..abd7763ee 100644
--- a/source/core/smart-pointer.h
+++ b/source/core/smart-pointer.h
@@ -61,6 +61,18 @@ namespace Slang
{
return referenceCount;
}
+
+ // Use instead of dynamic_cast as it allows for replacement without using Rtti in the future
+ template<typename T>
+ SLANG_FORCE_INLINE const T* dynamicCast() const
+ {
+ return dynamic_cast<const T*>(this);
+ }
+ template<typename T>
+ SLANG_FORCE_INLINE T* dynamicCast()
+ {
+ return dynamic_cast<T*>(this);
+ }
};
inline void addReference(RefObject* obj)
@@ -78,7 +90,7 @@ namespace Slang
struct RefPtr
{
RefPtr()
- : pointer(0)
+ : pointer(nullptr)
{}
RefPtr(T* p)
@@ -96,7 +108,7 @@ namespace Slang
RefPtr(RefPtr<T>&& p)
: pointer(p.pointer)
{
- p.pointer = 0;
+ p.pointer = nullptr;
}
template <typename U>
@@ -170,8 +182,7 @@ namespace Slang
template<typename U>
RefPtr<U> As() const
{
- RefPtr<U> result(dynamic_cast<U*>(pointer));
- return result;
+ return RefPtr<U>(pointer->template dynamicCast<U>());
}
~RefPtr()