// complement pool delete operator void CObject::operator delete(void* ptr, CObjectMemoryPool* memory_pool) { // Can be called either from regular destruction (with counter initialized) // or before CObject constructor is called (counter is not set yet). #if USE_TLS_PTR # ifdef _DEBUG TCount magic = sx_PopLastNewPtr(ptr); if ( !magic ) { // counter already initialized magic = static_cast<CObject*>(ptr)->m_Counter.Get(); } # else// !_DEBUG // Just remove saved operator new info. sx_PopLastNewPtr(ptr); # endif// _DEBUG #else// !USE_TLS_PTR # ifdef _DEBUG TCount magic = static_cast<CObject*>(ptr)->m_Counter.Get(); # endif//_DEBUG #endif// USE_TLS_PTR // magic can be equal to: // 1. eMagicCounterPoolDeleted when freed after CObject destructor. // 2. eMagicCounterPoolNew when freed before CObject constructor. _ASSERT(magic == eMagicCounterPoolDeleted || magic == eMagicCounterPoolNew); memory_pool->Deallocate(ptr); }
// initialization in debug mode inline void CObject::InitCounter(void) { #if USE_TLS_PTR if ( CAtomicCounter::TValue type = sx_PopLastNewPtr(this) ) { switch ( type ) { case eMagicCounterNew: // allocated in heap m_Counter.Set(eInitCounterInHeap); break; case eMagicCounterPoolNew: // allocated in memory pool m_Counter.Set(eInitCounterInPool); break; default: ERR_POST_X(1, ObjFatal << "CObject::InitCounter: " "Bad s_LastNewType="<<type<< " at "<<StackTrace); // something is broken in TLS data // mark as not in heap m_Counter.Set(eInitCounterNotInHeap); break; } } else { // surely not in heap m_Counter.Set(eInitCounterNotInHeap); } #else // This code can't use Get(), which may block waiting for an // update that will never happen. // ATTENTION: this code can cause UMR (Uninit Mem Read) -- it's okay here! TCount main_counter = m_Counter.m_Value; if ( main_counter != eMagicCounterNew && main_counter != eMagicCounterPoolNew ) { // takes care of statically allocated case m_Counter.Set(eInitCounterNotInHeap); } else { bool inStack = false; #if USE_HEAPOBJ_LIST const void* ptr = dynamic_cast<const void*>(this); {{ CFastMutexGuard LOCK(sm_ObjectMutex); list<const void*>::iterator i = find( s_heap_obj->begin(), s_heap_obj->end(), ptr); inStack = (i == s_heap_obj->end()); if (!inStack) { s_heap_obj->erase(i); } }} #else // USE_HEAPOBJ_LIST # if USE_COMPLEX_MASK inStack = GetSecondCounter(this)->m_Value != main_counter; # endif // USE_COMPLEX_MASK // m_Counter == main_counter -> possibly in heap if ( !inStack ) { char stackObject; const char* stackObjectPtr = &stackObject; const char* objectPtr = reinterpret_cast<const char*>(this); # if defined STACK_GROWS_UP inStack = (objectPtr < stackObjectPtr) && (objectPtr > stackObjectPtr - STACK_THRESHOLD); # elif defined STACK_GROWS_DOWN inStack = (objectPtr > stackObjectPtr) && (objectPtr < stackObjectPtr + STACK_THRESHOLD); # else inStack = (objectPtr < stackObjectPtr + STACK_THRESHOLD) && (objectPtr > stackObjectPtr - STACK_THRESHOLD); # endif } #endif // USE_HEAPOBJ_LIST if ( inStack ) { // surely not in heap m_Counter.Set(eInitCounterInStack); } else if ( main_counter == eMagicCounterNew ) { // allocated in heap m_Counter.Set(eInitCounterInHeap); } else { // allocated in memory pool m_Counter.Set(eInitCounterInPool); } } #endif }
static void RegisterDelete(CObjectWithTLS* ptr) { sx_PopLastNewPtr(ptr); }
void CTestTlsObjectApp::RunTest(void) { const size_t OBJECT_SIZE = sizeof(CObjectWithNew); for ( int t = 0; t < 1; ++t ) { // prealloc { size_t size = (OBJECT_SIZE+16)*COUNT; void* p = ::operator new(size); memset(p, 1, size); ::operator delete(p); } { const size_t COUNT2 = COUNT*2; void** p = new void*[COUNT2]; for ( size_t i = 0; i < COUNT2; ++i ) { add_alloc(1); add_step(); p[i] = ::operator new(OBJECT_SIZE); } for ( size_t i = 0; i < COUNT2; ++i ) { add_alloc(-1); add_step(); ::operator delete(p[i]); } delete[] p; } { const size_t COUNT2 = COUNT*2; int** p = new int*[COUNT2]; for ( size_t i = 0; i < COUNT2; ++i ) { add_alloc(1); add_step(); p[i] = new int(int(i)); } for ( size_t i = 0; i < COUNT2; ++i ) { add_alloc(-1); add_step(); delete p[i]; } delete[] p; } } //return; CStopWatch sw; check_cnts(); for ( int t = 0; t < 1; ++t ) { void** ptr = new void*[COUNT]; sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_alloc(1); add_step(); ptr[i] = ::operator new(OBJECT_SIZE); } double t1 = sw.Elapsed(); sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_alloc(-1); add_step(); ::operator delete(ptr[i]); } double t2 = sw.Elapsed(); message("plain malloc", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { sw.Start(); int* ptr = new int; sx_PushLastNewPtr(ptr, 2); double t1 = sw.Elapsed(); sw.Start(); _VERIFY(sx_PopLastNewPtr(ptr)); delete ptr; double t2 = sw.Elapsed(); message("tls", "set", t1, "get", t2, COUNT); } check_cnts(); { CObjectWithNew** ptr = new CObjectWithNew*[COUNT]; for ( size_t i = 0; i < COUNT; ++i ) { ptr[i] = 0; } sw.Start(); s_CurrentStep = "new CObjectWithNew"; s_CurrentInHeap = true; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); ptr[i] = new CObjectWithNew; } s_CurrentInHeap = false; double t1 = sw.Elapsed(); check_cnts(COUNT); for ( size_t i = 0; i < COUNT; ++i ) { _ASSERT(ptr[i]->IsInHeap()); } sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); CObjectWithNew::Delete(ptr[i]); } double t2 = sw.Elapsed(); message("new CObjectWithNew", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { CObjectWithTLS** ptr = new CObjectWithTLS*[COUNT]; sw.Start(); s_CurrentStep = "new CObjectWithTLS"; s_CurrentInHeap = true; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); try { switch ( rand()%3 ) { case 0: ptr[i] = new CObjectWithTLS; break; case 1: ptr[i] = new CObjectWithTLS2; break; case 2: ptr[i] = new CObjectWithTLS3; break; } } catch ( exception& ) { ptr[i] = 0; } _ASSERT(!sx_HaveLastNewPtr()); _ASSERT(!ptr[i] || ptr[i]->IsInHeap()); } s_CurrentInHeap = false; double t1 = sw.Elapsed(); check_cnts(COUNT); sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); CObjectWithTLS::Delete(ptr[i]); } double t2 = sw.Elapsed(); message("new CObjectWithTLS", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { CRef<CObjectWithRef>* ptr = new CRef<CObjectWithRef>[COUNT]; sw.Start(); s_CurrentStep = "new CObjectWithRef"; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); try { switch ( rand()%2 ) { case 0: ptr[i] = new CObjectWithRef; break; case 1: ptr[i] = new CObjectWithRef2; break; } } catch ( exception& ) { ptr[i] = 0; } _ASSERT(!sx_HaveLastNewPtr()); _ASSERT(!ptr[i] || ptr[i]->CanBeDeleted()); } double t1 = sw.Elapsed(); check_cnts(COUNT); sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); ptr[i].Reset(); } double t2 = sw.Elapsed(); message("new CObjectWithRef", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { CObjectWithNew** ptr = new CObjectWithNew*[COUNT]; for ( size_t i = 0; i < COUNT; ++i ) { ptr[i] = 0; } sw.Start(); s_CurrentStep = "new CObjectWithNew()"; s_CurrentInHeap = true; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); ptr[i] = new CObjectWithNew(); } s_CurrentInHeap = false; double t1 = sw.Elapsed(); check_cnts(COUNT); for ( size_t i = 0; i < COUNT; ++i ) { _ASSERT(ptr[i]->IsInHeap()); } sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); CObjectWithNew::Delete(ptr[i]); } double t2 = sw.Elapsed(); message("new CObjectWithNew()", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { CObjectWithTLS** ptr = new CObjectWithTLS*[COUNT]; sw.Start(); s_CurrentStep = "new CObjectWithTLS()"; s_CurrentInHeap = true; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); try { switch ( rand()%4 ) { case 0: ptr[i] = new CObjectWithTLS(); break; case 1: ptr[i] = new CObjectWithTLS2(); break; case 2: ptr[i] = new CObjectWithTLS3(); break; case 3: ptr[i] = new CObjectWithTLS3(RecursiveNewTLS(rand()%4)); break; } } catch ( exception& ) { ptr[i] = 0; } _ASSERT(!sx_HaveLastNewPtr()); _ASSERT(!ptr[i] || ptr[i]->IsInHeap()); } s_CurrentInHeap = false; double t1 = sw.Elapsed(); check_cnts(COUNT); sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); CObjectWithTLS::Delete(ptr[i]); } double t2 = sw.Elapsed(); message("new CObjectWithTLS()", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { CRef<CObjectWithRef>* ptr = new CRef<CObjectWithRef>[COUNT]; sw.Start(); s_CurrentStep = "new CObjectWithRef()"; for ( size_t i = 0; i < COUNT; ++i ) { add_step(); try { size_t j = rand()%COUNT; switch ( rand()%4 ) { case 0: ptr[j] = new CObjectWithRef(); break; case 1: ptr[j] = new CObjectWithRef(RecursiveNewRef(rand()%4)); break; case 2: ptr[j] = new CObjectWithRef2(); break; case 3: ptr[j] = new CObjectWithRef2(RecursiveNewRef(rand()%4)); break; } } catch ( exception& ) { ptr[i] = 0; } _ASSERT(!sx_HaveLastNewPtr()); _ASSERT(!ptr[i] || ptr[i]->CanBeDeleted()); } double t1 = sw.Elapsed(); check_cnts(COUNT); sw.Start(); for ( size_t i = 0; i < COUNT; ++i ) { add_step(); ptr[i] = 0; } double t2 = sw.Elapsed(); message("new CObjectWithRef()", "create", t1, "delete", t2, COUNT); delete[] ptr; } check_cnts(); { sw.Start(); s_CurrentStep = "CObjectWithNew[]"; CArray<CObjectWithNew, COUNT>* arr = new CArray<CObjectWithNew, COUNT>; double t1 = sw.Elapsed(); check_cnts(COUNT, COUNT); for ( size_t i = 0; i < COUNT; ++i ) { _ASSERT(!arr->m_Array[i].IsInHeap()); } sw.Start(); delete arr; double t2 = sw.Elapsed(); message("static CObjectWithNew", "create", t1, "delete", t2, COUNT); } check_cnts(); { sw.Start(); s_CurrentStep = "CObjectWithTLS[]"; CArray<CObjectWithTLS, COUNT, false>* arr = new CArray<CObjectWithTLS, COUNT, false>; double t1 = sw.Elapsed(); check_cnts(COUNT, COUNT); for ( size_t i = 0; i < COUNT; ++i ) { _ASSERT(!arr->m_Array[i].IsInHeap()); } sw.Start(); delete arr; double t2 = sw.Elapsed(); message("static CObjectWithTLS", "create", t1, "delete", t2, COUNT); } check_cnts(); { sw.Start(); s_CurrentStep = "CObjectWithRef[]"; CArray<CObjectWithRef, COUNT, false>* arr = new CArray<CObjectWithRef, COUNT, false>; double t1 = sw.Elapsed(); check_cnts(COUNT, COUNT); for ( size_t i = 0; i < COUNT; ++i ) { _ASSERT(!arr->m_Array[i].CanBeDeleted()); } sw.Start(); delete arr; double t2 = sw.Elapsed(); message("static CObjectWithRef", "create", t1, "delete", t2, COUNT); } check_cnts(); }
static bool IsNewInHeap(CObjectWithTLS* ptr) { return sx_PopLastNewPtr(ptr); }