#include "il2cpp-config.h" #include "MarshalAlloc.h" #include "os/MarshalAlloc.h" #include "os/ThreadLocalValue.h" #include "vm/Exception.h" #include #include "Baselib.h" #include "Cpp/ReentrantLock.h" namespace il2cpp { namespace vm { #if _DEBUG static os::ThreadLocalValue s_Allocations; static baselib::ReentrantLock s_AllocationStorageMutex; static std::deque > > s_AllocationStorage; static std::vector >& GetAllocationsForCurrentThread() { std::vector >* ptr = NULL; s_Allocations.GetValue(reinterpret_cast(&ptr)); if (ptr == NULL) { os::FastAutoLock lock(&s_AllocationStorageMutex); s_AllocationStorage.push_back(std::vector >()); ptr = &s_AllocationStorage.back(); s_Allocations.SetValue(ptr); } return *ptr; } static std::map* GetAllocationsForCurrentFrame() { std::vector >& currentThreadAllocations = GetAllocationsForCurrentThread(); if (currentThreadAllocations.size() > 0) return ¤tThreadAllocations.back(); return NULL; } #endif void* MarshalAlloc::Allocate(size_t size) { void* ptr = os::MarshalAlloc::Allocate(size); #if _DEBUG std::map* allocations = GetAllocationsForCurrentFrame(); if (allocations != NULL) (*allocations)[ptr] = size; #endif return ptr; } void* MarshalAlloc::ReAlloc(void* ptr, size_t size) { void* realloced = os::MarshalAlloc::ReAlloc(ptr, size); #if _DEBUG std::map* allocations = GetAllocationsForCurrentFrame(); if (allocations != NULL) { if (ptr != NULL && ptr != realloced) { std::map::iterator found = allocations->find(ptr); IL2CPP_ASSERT(found != allocations->end() && "Invalid call to MarshalAlloc::ReAlloc. The pointer is not in the allocation list."); allocations->erase(found); } (*allocations)[realloced] = size; } #endif return realloced; } void MarshalAlloc::Free(void* ptr) { #if _DEBUG std::map* allocations = GetAllocationsForCurrentFrame(); if (allocations != NULL) { std::map::iterator found = allocations->find(ptr); if (found != allocations->end()) // It might not be necessarily allocated by us, e.g. we might be freeing memory that's returned from native P/Invoke call allocations->erase(found); } #endif os::MarshalAlloc::Free(ptr); } void* MarshalAlloc::AllocateHGlobal(size_t size) { return os::MarshalAlloc::AllocateHGlobal(size); } void* MarshalAlloc::ReAllocHGlobal(void* ptr, size_t size) { return os::MarshalAlloc::ReAllocHGlobal(ptr, size); } void MarshalAlloc::FreeHGlobal(void* ptr) { os::MarshalAlloc::FreeHGlobal(ptr); } #if _DEBUG void MarshalAlloc::PushAllocationFrame() { GetAllocationsForCurrentThread().push_back(std::map()); } void MarshalAlloc::PopAllocationFrame() { GetAllocationsForCurrentThread().pop_back(); } bool MarshalAlloc::HasUnfreedAllocations() { std::map* allocations = GetAllocationsForCurrentFrame(); return allocations != NULL && allocations->size() > 0; } void MarshalAlloc::ClearAllTrackedAllocations() { std::map* allocations = GetAllocationsForCurrentFrame(); if (allocations != NULL) allocations->clear(); } #endif } /* namespace vm */ } /* namespace il2cpp */