• R/O
  • SSH
  • HTTPS

eirrepo: Commit


Commit MetaInfo

Revision112 (tree)
Time2018-08-29 02:44:48
Authorquiret

Log Message

- added native heap allocator realloc functionality basing on optimized memory "resizing" logic; it is recommended to resize memory instead of calling Realloc

Change Summary

Incremental Difference

--- common/sdk/OSUtils.memheap.h (revision 111)
+++ common/sdk/OSUtils.memheap.h (revision 112)
@@ -205,6 +205,150 @@
205205 }
206206 }
207207
208+ // Attempts to change the size of an allocation.
209+ inline bool SetAllocationSize( void *memPtr, size_t newSize )
210+ {
211+ // We can only fail if the allocation does not fit with regards to the remaining free space.
212+
213+ size_t header_size = sizeof(VMemAllocation);
214+
215+ size_t memOff = (size_t)memPtr;
216+
217+ size_t memHandleOff = UINT_DOWNPUSH( memOff - sizeof(VMemAllocation), VMemIsland::HEADER_ALIGNMENT );
218+
219+ VMemAllocation *memHandle = (VMemAllocation*)memHandleOff;
220+
221+ // We do not have to update anything, so bail.
222+ size_t oldDataSize = memHandle->dataSize;
223+
224+ if ( oldDataSize == newSize )
225+ return true;
226+
227+ // Since we know the free space after the memory handle, we can simply grow or shrink without issue.
228+ // The operation takes logarithmic time though, because we update the AVL tree.
229+
230+ size_t startOfDataOffset = (size_t)memPtr;
231+
232+ size_t newRequestedStartOfFreeBytes = ( startOfDataOffset + newSize );
233+
234+ // Get the offset to the byte that is last of the available (possible) free space.
235+ size_t endOfFreeSpaceOffset;
236+
237+ bool wasFreeSpaceEmpty = memHandle->freeSpaceAfterThis.freeRegion.IsEmpty();
238+
239+ if ( wasFreeSpaceEmpty == false )
240+ {
241+ endOfFreeSpaceOffset = memHandle->freeSpaceAfterThis.freeRegion.GetSliceEndPoint();
242+ }
243+ else
244+ {
245+ endOfFreeSpaceOffset = memHandle->GetRegion().GetSliceEndPoint();
246+ }
247+
248+ // If this is not a valid offset for the free bytes, we bail.
249+ // We add 1 because it could become empty aswell.
250+ if ( endOfFreeSpaceOffset + 1 < newRequestedStartOfFreeBytes )
251+ return false;
252+
253+ // Update the meta-data.
254+ VMemIsland *memIsland = memHandle->manager;
255+
256+ if ( wasFreeSpaceEmpty == false )
257+ {
258+ memIsland->avlSortedBySize.RemoveByNodeFast( &memHandle->freeSpaceAfterThis.sortedBySizeNode );
259+ }
260+
261+ memHandle->freeSpaceAfterThis.freeRegion = memBlockSlice_t::fromOffsets( newRequestedStartOfFreeBytes, endOfFreeSpaceOffset );
262+ memHandle->dataSize = newSize;
263+
264+ // Insert the new thing again.
265+ if ( memHandle->freeSpaceAfterThis.freeRegion.IsEmpty() == false )
266+ {
267+ memIsland->avlSortedBySize.Insert( &memHandle->freeSpaceAfterThis.sortedBySizeNode );
268+ }
269+
270+ return true;
271+ }
272+
273+ // Returns the data size of an allocation.
274+ inline size_t GetAllocationSize( void *memPtr )
275+ {
276+ size_t header_size = sizeof(VMemAllocation);
277+
278+ size_t memOff = (size_t)memPtr;
279+
280+ size_t memHandleOff = UINT_DOWNPUSH( memOff - sizeof(VMemAllocation), VMemIsland::HEADER_ALIGNMENT );
281+
282+ VMemAllocation *memHandle = (VMemAllocation*)memHandleOff;
283+
284+ return memHandle->dataSize;
285+ }
286+
287+ // Simple realloc helper just because it is being exposed in the CRT aswell.
288+ inline void* Realloc( void *memPtr, size_t newSize, size_t alignment = sizeof(void*) )
289+ {
290+ if ( memPtr == nullptr )
291+ {
292+ return Allocate( newSize, alignment );
293+ }
294+
295+ if ( newSize == 0 )
296+ {
297+ Free( memPtr );
298+ return nullptr;
299+ }
300+
301+ // Now do the tricky part.
302+ // If we suceeded in resizing, we leave it at that.
303+ // Otherwise we must allocate a new bit of memory, copy all old bytes over, free the old and return the new.
304+ bool couldResize = SetAllocationSize( memPtr, newSize );
305+
306+ if ( couldResize )
307+ {
308+ return memPtr;
309+ }
310+
311+ // Now we just trash the old block.
312+ // Did the CRT state anything about alignment tho?
313+ void *newMemPtr = Allocate( newSize, alignment );
314+
315+ if ( newMemPtr == nullptr )
316+ {
317+ // DESTROY!
318+ // There is no recovery for impartial failure.
319+ Free( memPtr );
320+ return nullptr;
321+ }
322+
323+ // Memory copy.
324+ {
325+ char *srcPtr = (char*)memPtr;
326+ char *dstPtr = (char*)newMemPtr;
327+ size_t srcSize = GetAllocationSize( memPtr );
328+
329+ for ( size_t n = 0; n < newSize; n++ )
330+ {
331+ char putByte;
332+
333+ if ( n < srcSize )
334+ {
335+ putByte = *( srcPtr + n );
336+ }
337+ else
338+ {
339+ putByte = 0;
340+ }
341+
342+ *( dstPtr + n ) = putByte;
343+ }
344+ }
345+
346+ // Free the old.
347+ Free( memPtr );
348+
349+ return newMemPtr;
350+ }
351+
208352 private:
209353 // Virtual memory manager object.
210354 NativePageAllocator nativeMemProv;
--- unittests/src/heaptests.cpp (revision 111)
+++ unittests/src/heaptests.cpp (revision 112)
@@ -103,4 +103,56 @@
103103 heapAlloc.Free( ptrSeven );
104104 }
105105 printf( "ok.\n" );
106+
107+ printf( "testing native heap allocator allocation resize..." );
108+ {
109+ void *initialAlloc = heapAlloc.Allocate( sizeof(void*) * 2 );
110+ void *barrierAlloc = heapAlloc.Allocate( 1 );
111+
112+ heapAlloc.Free( initialAlloc );
113+
114+ void *growerAlloc = heapAlloc.Allocate( 5 );
115+
116+ // We allocate best-fit so the small free space must be considered before the big last free space.
117+ assert( (size_t)growerAlloc < (size_t)barrierAlloc );
118+
119+ // Try to grow the allocation.
120+ bool successGrowInitial = heapAlloc.SetAllocationSize( growerAlloc, sizeof(void*) * 2 );
121+ bool failGrowBeyond = heapAlloc.SetAllocationSize( growerAlloc, sizeof(void*) * 2 + 1 );
122+ bool successGrowSmall = heapAlloc.SetAllocationSize( growerAlloc, 3 );
123+
124+ assert( successGrowInitial == true );
125+ assert( failGrowBeyond == false );
126+ assert( successGrowSmall == true );
127+
128+ heapAlloc.Free( barrierAlloc );
129+ heapAlloc.Free( growerAlloc );
130+ }
131+ printf( "ok.\n" );
132+
133+ printf( "testing native heap allocation reallocation..." );
134+ {
135+ const char someData[] = "meow meow";
136+
137+ void *someMemBlock = heapAlloc.Allocate( sizeof(someData) );
138+
139+ memcpy( someMemBlock, someData, sizeof(someData) );
140+
141+ assert( memcmp( someMemBlock, someData, sizeof(someData) ) == 0 );
142+
143+ // If we reallocate this block to an enourmous size it should work.
144+ // But it gotta be on a new block of memory.
145+ void *newMemBlock = heapAlloc.Realloc( someMemBlock, 0x20000 );
146+
147+ assert( newMemBlock != someMemBlock );
148+
149+ // Must have the same data.
150+ assert( memcmp( newMemBlock, someData, sizeof(someData) ) == 0 );
151+
152+ // So if we shrink it it must reside on the same block.
153+ void *shrinkedMemBlock = heapAlloc.Realloc( newMemBlock, sizeof(someData) );
154+
155+ assert( shrinkedMemBlock == newMemBlock );
156+ }
157+ printf( "ok.\n" );
106158 }
\ No newline at end of file
Show on old repository browser