uAutoReleasePool::~uAutoReleasePool() { uThreadData* thread = uGetThreadData(); uAutoReleaseFrame& frame = thread->AutoReleaseStack[thread->AutoReleaseStack.Length() - 1]; // Note: Rewritten because that uAutoReleaseObject() might be called from uReleaseObject() inside this loop. // TODO: It may be faster if uAutoReleaseObject() were able to handle this, i.e. not adding anything to pool while flushing it. for (int i = frame.StartIndex; i < (int)thread->AutoReleasePool.Length(); i++) { uObject* obj = thread->AutoReleasePool[i]; #ifdef U_DEBUG_MEM frame.AllocCount++; frame.AllocSize += obj->__obj_alloc_size; #endif uReleaseObject(obj); } #if U_DEBUG_MEM >= 1 Xli::Error->WriteFormat("ARC FRAME: Alloc'd %d objects (%d bytes), Free'd %d objects (%d bytes)\n", frame.AllocCount, frame.AllocSize, frame.FreeCount, frame.FreeSize); #endif thread->AutoReleasePool.Resize(frame.StartIndex); thread->AutoReleaseStack.RemoveLast(); }
void uAutoReleaseObject(uObject* obj) { uThreadData* thread = uGetThreadData(); if (thread->AutoReleaseStack.Length() == 0) uFatalError(XLI_FUNCTION); if (obj) { thread->AutoReleasePool.Add(obj); #ifdef U_DEBUG_MEM int releaseCount = 0; for (int i = 0; i < thread->AutoReleasePool.Length(); i++) if (thread->AutoReleasePool[i] == obj) releaseCount++; int retainCount = obj->__obj_retains - releaseCount; if (retainCount < 0) Xli::Error->WriteFormat("*** BAD RELEASE: '%s', object id: %d (%d retains) ***\n", obj->__obj_type->TypeName, obj->__obj_id, retainCount); #endif } }
uStackFrame::uStackFrame(const char* type, const char* function) { uThreadData* thread = uGetThreadData(); uCallStackFrame& frame = thread->CallStack[thread->CallStack.Add()]; frame.Type = type; frame.Function = function; }
void uAutoRelease(uObject* object) { if (object) { uThreadData* thread = uGetThreadData(); thread->AutoReleaseList.Add(object); U_ASSERT(thread->AutoReleasePtr >= thread->AutoReleaseStack); #ifdef DEBUG_ARC int releaseCount = 0; for (size_t i = 0; i < thread->AutoReleaseList.Length(); i++) if (thread->AutoReleaseList[i] == object) releaseCount++; int retainCount = object->__retains - releaseCount; if (retainCount < 0) { Xli::Error->WriteFormat("*** BAD AUTORELEASE: %s #%d (%d bytes, %d retains) ***%s\n", object->__type->FullName, object->__id, object->__size, retainCount, uGetCaller().Ptr()); U_FATAL(); } #endif #if DEBUG_ARC >= 4 Xli::Error->WriteFormat("autorelease %s #%d (%d bytes, %d retains)%s\n", object->__type->FullName, object->__id, object->__size, object->__retains, uGetCaller().Ptr()); #endif } }
uType* uSwapThreadType(uType* type) { uThreadData* thread = uGetThreadData(); uType* result = thread->CurrentType; thread->CurrentType = type; return result; }
uStackFrame::uStackFrame(const char* type, const char* function) { uThreadData* thread = uGetThreadData(); uCallStackFrame* frame = ++thread->CallStackPtr; U_ASSERT(frame < thread->CallStackEnd); frame->Type = type; frame->Function = function; }
uAutoReleasePool::uAutoReleasePool() { uThreadData* thread = uGetThreadData(); uAutoReleaseFrame& frame = thread->AutoReleaseStack[thread->AutoReleaseStack.Add()]; frame.StartIndex = thread->AutoReleasePool.Length(); #ifdef U_DEBUG_MEM frame.AllocCount = 0; frame.AllocSize = 0; frame.FreeCount = 0; frame.FreeSize = 0; #endif }
uAutoReleasePool::uAutoReleasePool() { uThreadData* thread = uGetThreadData(); uAutoReleaseFrame* frame = ++thread->AutoReleasePtr; U_ASSERT(frame < thread->AutoReleaseEnd); frame->StartIndex = thread->AutoReleaseList.Length(); #ifdef DEBUG_ARC frame->AllocCount = 0; frame->AllocSize = 0; frame->FreeCount = 0; frame->FreeSize = 0; #endif }
static Xli::String uGetCaller() { uThreadData* thread = uGetThreadData(); if (thread->CallStackPtr < thread->CallStack) return ""; Xli::StringBuilder sb; uCallStackFrame* frame = thread->CallStackPtr; sb += " -- at "; sb += frame->Type; sb += '.'; sb += frame->Function; return sb.ToString(); }
uString* uGetStackTrace() { Xli::StringBuilder sb; uThreadData* thread = uGetThreadData(); for (int i = thread->CallStack.Length() - 1; i >= 0; i--) { if (sb.GetLength() > 0) sb += '\n'; uCallStackFrame& frame = thread->CallStack[i]; sb += " at "; sb += frame.Type; sb += '.'; sb += frame.Function; } return uStringFromXliString(sb.ToString()); }
uString* uGetStackTrace() { Xli::StringBuilder sb; uThreadData* thread = uGetThreadData(); for (uCallStackFrame* frame = thread->CallStackPtr; frame >= thread->CallStack; frame--) { if (sb.GetLength() > 0) sb += '\n'; sb += " at "; sb += frame->Type; sb += '.'; sb += frame->Function; } return uStringFromXliString(sb.ToString()); }
uAutoReleasePool::~uAutoReleasePool() { uThreadData* thread = uGetThreadData(); uAutoReleaseFrame* frame = thread->AutoReleasePtr; U_ASSERT(thread->AutoReleasePtr >= thread->AutoReleaseStack); for (size_t i = frame->StartIndex; i < thread->AutoReleaseList.Length(); i++) { uObject* object = thread->AutoReleaseList[i]; #ifdef DEBUG_ARC frame->AllocCount++; frame->AllocSize += object->__size; #endif uRelease(object); } #if DEBUG_ARC >= 1 Xli::Error->WriteFormat("--- Alloc'd %d objects (%d bytes), Free'd %d objects (%d bytes) ---\n", frame->AllocCount, frame->AllocSize, frame->FreeCount, frame->FreeSize); #endif thread->AutoReleaseList.Resize(frame->StartIndex); thread->AutoReleasePtr--; }
void uReleaseObject(uObject* obj) { if (obj) { if (Xli::AtomicDecrement(&obj->__obj_retains) == 0) { if (!uTryClearWeakObject(obj)) return; #ifdef U_DEBUG_MEM uThreadData* thread = uGetThreadData(); if (thread->AutoReleaseStack.Length() > 0 && thread->AutoReleaseStack.Last().AllocCount > 0) { thread->AutoReleaseStack.Last().FreeCount++; thread->AutoReleaseStack.Last().FreeSize += obj->__obj_alloc_size; } #endif uType* type = obj->__obj_type; switch (type->TypeType) { case uTypeTypeClass: do { if (type->__fp_Finalize) { try { (*type->__fp_Finalize)(obj); } catch (...) { Xli::Error->WriteFormat("Runtime Error: Unhandled exception in finalizer for '%s'\n", type->TypeName); } } uReleaseValue(type, obj); type = type->BaseType; } while (type); break; case uTypeTypeEnum: break; case uTypeTypeStruct: // Note: This must be a boxed value, so append size of object header uReleaseValue(type, (uByte*)obj + sizeof(uObject)); break; case uTypeTypeDelegate: uReleaseObject(((uDelegate*)obj)->_obj); uReleaseObject(((uDelegate*)obj)->_prev); break; case uTypeTypeArray: { uArray* array = (uArray*)obj; uArrayType* arrayType = (uArrayType*)type; uType* elmType = arrayType->ElementType; switch (elmType->TypeType) { case uTypeTypeClass: case uTypeTypeInterface: case uTypeTypeDelegate: case uTypeTypeArray: for (uObject** objAddr = (uObject**)array->_ptr; array->_len--; objAddr++) uReleaseObject(*objAddr); break; case uTypeTypeEnum: break; case uTypeTypeStruct: for (uByte* valueAddr = (uByte*)array->_ptr; array->_len--; valueAddr += elmType->ValueSize) uReleaseValue(elmType, valueAddr); break; default: uFatalError(XLI_FUNCTION); } } break; default: uFatalError(XLI_FUNCTION); } #if U_DEBUG_MEM >= 2 Xli::Error->WriteFormat("Freeing '%s' (%d bytes)\n", obj->__obj_type->TypeName, obj->__obj_alloc_size); #endif #ifdef U_DEBUG_MEM uEnterCritical(); uHeapObjects->Remove(obj); uExitCritical(); #endif U_FREE_OBJECT(obj); } else if ((*(uUInt*)&obj->__obj_retains) & 0xF0000000) { // Object must be corrupt if one of the four first bits are set uFatalError(XLI_FUNCTION); } else { #if U_DEBUG_MEM >= 3 Xli::Error->WriteFormat("Released '%s' (%d bytes) (%d retains)\n", obj->__obj_type->TypeName, obj->__obj_alloc_size, obj->__obj_retains); #endif } } }
uStackFrame::~uStackFrame() { uGetThreadData()->CallStack.RemoveLast(); }
void uRelease(uObject* object) { if (object) { if (Xli::AtomicDecrement(&object->__retains) == 0) { if (!uTryClearWeak(object)) return; #ifdef DEBUG_ARC uThreadData* thread = uGetThreadData(); if (thread->AutoReleasePtr >= thread->AutoReleaseStack) { uAutoReleaseFrame* frame = thread->AutoReleasePtr; if (frame->AllocCount > 0) { frame->FreeCount++; frame->FreeSize += object->__size; } } #endif uType* type = object->__type; switch (type->Type) { case uTypeTypeClass: { uType* baseType = type; do { if (baseType->fp_Finalize) { try { (*baseType->fp_Finalize)(object); } catch (...) { Xli::Error->WriteFormat("Runtime Error: Unhandled exception in finalizer for %s\n", baseType->FullName); } } } while ((baseType = baseType->Base)); uReleaseStruct(type, object); break; } case uTypeTypeStruct: // This must be a boxed value, so append size of object header uReleaseStruct(type, (uint8_t*)object + sizeof(uObject)); break; case uTypeTypeDelegate: uRelease(((uDelegate*)object)->_object); uRelease(((uDelegate*)object)->_prev); break; case uTypeTypeArray: { uArray* array = (uArray*)object; uArrayType* arrayType = (uArrayType*)type; uType* elmType = arrayType->ElementType; switch (elmType->Type) { case uTypeTypeClass: case uTypeTypeInterface: case uTypeTypeDelegate: case uTypeTypeArray: for (uObject** objAddr = (uObject**)array->_ptr; array->_length--; objAddr++) uRelease(*objAddr); break; case uTypeTypeStruct: for (uint8_t* address = (uint8_t*)array->_ptr; array->_length--; address += elmType->ValueSize) uReleaseStruct(elmType, address); break; default: break; } break; } default: break; } #if DEBUG_ARC >= 2 Xli::Error->WriteFormat("free %s #%d (%d bytes)%s\n", object->__type->FullName, object->__id, object->__size, uGetCaller().Ptr()); #endif #ifdef DEBUG_DUMPS uEnterCritical(); _HeapObjects->Remove(object); uExitCritical(); #endif U_ASSERT(object->__type != ::g::Uno::Type_typeof()); U_FREE_OBJECT(object); return; } if (object->__retains < 0) { #if DEBUG_ARC >= 4 Xli::Error->WriteFormat("*** BAD OBJECT: %s #%d (%d retains) ***%s\n", object->__type->FullName, object->__id, object->__retains, uGetCaller().Ptr()); #else Xli::Error->WriteFormat("*** BAD OBJECT: 0x%llx ***\n", (uintptr_t)object); #endif U_FATAL(); } else { #if DEBUG_ARC >= 3 Xli::Error->WriteFormat("release %s #%d (%d bytes, %d retains)%s\n", object->__type->FullName, object->__id, object->__size, object->__retains, uGetCaller().Ptr()); #endif } } }
uStackFrame::~uStackFrame() { uGetThreadData()->CallStackPtr--; }