diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-09-14 14:16:28 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-09-14 14:16:28 -0400 |
| commit | 3c505c22673701339d35eb2151f01c16eb3c78c3 (patch) | |
| tree | ff21543fcc846c693cbb6aba43a4e8ae9918f600 /source/core | |
| parent | e1c934972509f4bbd2c05affe565f91e7a1e6c16 (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.cpp | 10 | ||||
| -rw-r--r-- | source/core/slang-memory-arena.h | 106 | ||||
| -rw-r--r-- | source/core/slang-string.h | 177 | ||||
| -rw-r--r-- | source/core/smart-pointer.h | 19 |
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() |
