/**************************************************************************** Copyright (c) 2010, Radon Labs GmbH Copyright (c) 2011-2013,WebJet Business Division,CYOU http://www.genesis-3d.com.cn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "stdneb.h" #include "core/types.h" #include "core/sysfunc.h" // #include "threading/interlocked.h" // overriden new/delete operators #ifndef __OSX__ void* operator new(size_t size) { return Memory::Alloc(Memory::ObjectHeap, size); } void* operator new(size_t size, size_t align) { return Memory::Alloc(Memory::ObjectHeap, size, align); } void* operator new[](size_t size) { return Memory::Alloc(Memory::ObjectArrayHeap, size); } void* operator new[](size_t size, size_t align) { return Memory::Alloc(Memory::ObjectArrayHeap, size, align); } void operator delete(void* p) { Memory::Free(Memory::ObjectHeap, p); } void operator delete[](void* p) { Memory::Free(Memory::ObjectArrayHeap, p); } #endif namespace Memory { #if NEBULA3_MEMORY_STATS int volatile TotalAllocCount = 0; int volatile TotalAllocSize = 0; int volatile HeapTypeAllocCount[NumHeapTypes] = { 0 }; int volatile HeapTypeAllocSize[NumHeapTypes] = { 0 }; bool volatile MemoryLoggingEnabled = false; unsigned int volatile MemoryLoggingThreshold = 0; HeapType volatile MemoryLoggingHeapType = InvalidHeapType; #endif //------------------------------------------------------------------------------ /** Allocate a block of memory from one of the global heaps. */ void* Alloc(HeapType heapType, size_t size, size_t alignment) { n_assert(heapType < NumHeapTypes); // make sure everything has been setup already Core::SysFunc::Setup(); void* allocPtr = 0; #if NEBULA3_MEMORY_STATS size_t allocatedSize = 0; #endif // allocate memory from global heap allocPtr = malloc_zone_memalign(Heaps[heapType], alignment, size); if (0 == allocPtr) { n_error("Allocation failed from Heap '%s'!\n", GetHeapTypeName(heapType)); } #if NEBULA3_MEMORY_STATS allocatedSize = malloc_size(allocPtr); #endif #if NEBULA3_MEMORY_STATS Threading::Interlocked::Increment(TotalAllocCount); Threading::Interlocked::Add(TotalAllocSize, allocatedSize); Threading::Interlocked::Increment(HeapTypeAllocCount[heapType]); Threading::Interlocked::Add(HeapTypeAllocSize[heapType], allocatedSize); if (MemoryLoggingEnabled && (size >= MemoryLoggingThreshold) && ((MemoryLoggingHeapType == InvalidHeapType) || (MemoryLoggingHeapType == heapType))) { n_printf("Allocate(size=%d, allocSize=%d, heapType=%d): 0x%lx\n", size, allocatedSize, heapType, (long unsigned int) allocPtr); } #endif return allocPtr; } //------------------------------------------------------------------------------ /** Re-Allocate a block of memory from one of the global heaps. NOTE that this function may also be used to shrink a memory block! */ void* Realloc(HeapType heapType, void* ptr, size_t size) { n_assert(heapType < NumHeapTypes); // make sure everything has been setup already Core::SysFunc::Setup(); // get old size for stats tracking #if NEBULA3_MEMORY_STATS size_t oldSize = malloc_size(ptr); #endif // reallocate the memory void* allocPtr = malloc_zone_realloc(Heaps[heapType], ptr, size); if (0 == allocPtr) { n_error("Allocation failed from Heap '%s'!\n", GetHeapTypeName(heapType)); } #if NEBULA3_MEMORY_STATS size_t allocatedSize = mspace_malloc_usable_size(allocPtr); Threading::Interlocked::Add(TotalAllocSize, size_t(allocatedSize - oldSize)); Threading::Interlocked::Add(HeapTypeAllocSize[heapType], size_t(allocatedSize - oldSize)); if (MemoryLoggingEnabled && (size >= MemoryLoggingThreshold) && ((MemoryLoggingHeapType == InvalidHeapType) || (MemoryLoggingHeapType == heapType))) { n_printf("Reallocate(size=%d, allocSize=%d, heapType=%d): 0x%lx\n", size, allocatedSize, heapType, (long unsigned int) allocPtr); } #endif return allocPtr; } //------------------------------------------------------------------------------ /** Free a block of memory. */ void Free(HeapType heapType, void* ptr) { if (0 != ptr) { n_assert(heapType < NumHeapTypes); #if NEBULA3_MEMORY_STATS size_t allocatedSize = malloc_size(ptr); #endif malloc_zone_free(Heaps[heapType], ptr); #if NEBULA3_MEMORY_STATS Threading::Interlocked::Add(TotalAllocSize, -allocatedSize); Threading::Interlocked::Decrement(TotalAllocCount); Threading::Interlocked::Add(HeapTypeAllocSize[heapType], -allocatedSize); Threading::Interlocked::Decrement(HeapTypeAllocCount[heapType]); if (MemoryLoggingEnabled && (allocatedSize >= MemoryLoggingThreshold) && ((MemoryLoggingHeapType == InvalidHeapType) || (MemoryLoggingHeapType == heapType))) { n_printf("Mem::Free(heapType=%d, ptr=0x%lx, allocSize=%d)\n", heapType, (long unsigned int) ptr, allocatedSize); } #endif } } //------------------------------------------------------------------------------ /** Duplicate a 0-terminated string, this method should no longer be used! */ char* DuplicateCString(const char* from) { n_assert(0 != from); size_t len = (unsigned int) strlen(from) + 1; char* to = (char*) Memory::Alloc(Memory::StringDataHeap, len); Memory::Copy((void*)from, to, len); return to; } //------------------------------------------------------------------------------ /** Test if 2 areas of memory areas are overlapping. */ bool IsOverlapping(const unsigned char* srcPtr, size_t srcSize, const unsigned char* dstPtr, size_t dstSize) { if (srcPtr == dstPtr) { return true; } else if (srcPtr > dstPtr) { return (srcPtr + srcSize) > dstPtr; } else { return (dstPtr + dstSize) > srcPtr; } } //------------------------------------------------------------------------------ /** Get the system's total memory status. */ TotalMemoryStatus GetTotalMemoryStatus() { n_error("IMPLEMENT ME: GetTotalMemoryStatus()!"); TotalMemoryStatus status = { 0 }; return status; } //------------------------------------------------------------------------------ /** Copy a chunk of memory (note the argument order is different from memcpy()!!!) */ void Copy(const void* from, void* to, size_t numBytes) { if (numBytes > 0) { n_assert(0 != from); n_assert(0 != to); n_assert(from != to); memcpy(to, from, numBytes); } } //------------------------------------------------------------------------------ /** Copy data from a system memory buffer to graphics resource memory. Some platforms may need special handling of this case. */ void CopyToGraphicsMemory(const void* from, void* to, size_t numBytes) { Memory::Copy(from, to, numBytes); } //------------------------------------------------------------------------------ /** Overwrite a chunk of memory with 0's. */ void Clear(void* ptr, size_t numBytes) { memset(ptr, 0, numBytes); } //------------------------------------------------------------------------------ /** Fill memory with a specific byte. */ void Fill(void* ptr, size_t numBytes, unsigned char value) { memset(ptr, value, numBytes); } #if NEBULA3_MEMORY_STATS //------------------------------------------------------------------------------ /** Enable memory logging. */ void EnableMemoryLogging(unsigned int threshold, HeapType heapType) { MemoryLoggingEnabled = true; MemoryLoggingThreshold = threshold; MemoryLoggingHeapType = heapType; } //------------------------------------------------------------------------------ /** Disable memory logging. */ void DisableMemoryLogging() { MemoryLoggingEnabled = false; } //------------------------------------------------------------------------------ /** Toggle memory logging. */ void ToggleMemoryLogging(unsigned int threshold, HeapType heapType) { if (MemoryLoggingEnabled) { DisableMemoryLogging(); } else { EnableMemoryLogging(threshold, heapType); } } #endif // NEBULA3_MEMORY_STATS #if NEBULA3_MEMORY_ADVANCED_DEBUGGING //------------------------------------------------------------------------------ /** Debug function which validates all heaps. */ bool ValidateMemory() { n_error("IMPLEMENT ME: ValidateMemory()"); return true; } //------------------------------------------------------------------------------ /** Write memory debugging info to log. */ void Checkpoint(const char* msg) { n_printf("MEMORY LOG: %s\n", msg); ValidateMemory(); // also dump a general alloc count/alloc size by heap type... n_printf("NEBULA ALLOC COUNT / SIZE: %d / %d\n", TotalAllocCount, TotalAllocSize); IndexT i; for (i = 0; i < NumHeapTypes; i++) { const char* heapName = GetHeapTypeName((HeapType)i); if (0 == heapName) { heapName = "UNKNOWN"; } n_printf("HEAP %lx ALLOC COUNT / SIZE: %s %d / %d\n", Heaps[i], heapName, HeapTypeAllocCount[i], HeapTypeAllocSize[i]); } } //------------------------------------------------------------------------------ /** Generate a memory leak dump for all heaps managed by Nebula. */ void DumpMemoryLeaks() { n_error("IMPLEMENT ME: DumpMemoryLeaks()"); } #endif // NEBULA3_MEMORY_ADVANCED_DEBUGGING } // namespace Memory