diff --git a/BeefLibs/corlib/src/Internal.bf b/BeefLibs/corlib/src/Internal.bf index a4f4d507..1deb7126 100644 --- a/BeefLibs/corlib/src/Internal.bf +++ b/BeefLibs/corlib/src/Internal.bf @@ -78,6 +78,33 @@ namespace System [AlwaysInclude] static class Internal { + enum BfObjectFlags : uint8 + { + None = 0, + Mark1 = 0x01, + Mark2 = 0x02, + Mark3 = 0x03, + Allocated = 0x04, + StackAlloc = 0x08, + AppendAlloc = 0x10, + AllocInfo = 0x20, + AllocInfo_Short = 0x40, + Deleted = 0x80 + }; + + struct AppendAllocEntry + { + public enum Kind + { + case None; + case Object(Object obj); + case Raw(void* ptr, DbgRawAllocData* allocData); + } + + public Kind mKind; + public AppendAllocEntry* mNext; + } + [Intrinsic("cast")] public static extern Object UnsafeCastToObject(void* ptr); [Intrinsic("cast")] @@ -273,11 +300,11 @@ namespace System [CallingConvention(.Cdecl)] public static extern int Dbg_PrepareStackTrace(int baseAllocSize, int maxStackTraceDepth); [CallingConvention(.Cdecl)] - public static extern void Dbg_ObjectStackInit(Object object, ClassVData* classVData); + public static extern void Dbg_ObjectStackInit(Object object, ClassVData* classVData, int size, uint8 allocFlags); [CallingConvention(.Cdecl)] public static extern Object Dbg_ObjectAlloc(TypeInstance typeInst, int size); [CallingConvention(.Cdecl)] - public static extern Object Dbg_ObjectAlloc(ClassVData* classVData, int size, int align, int maxStackTraceDepth); + public static extern Object Dbg_ObjectAlloc(ClassVData* classVData, int size, int align, int maxStackTraceDepth, uint8 flags); [CallingConvention(.Cdecl)] public static extern void Dbg_ObjectPreDelete(Object obj); [CallingConvention(.Cdecl)] @@ -293,6 +320,183 @@ namespace System [CallingConvention(.Cdecl)] public static extern void Dbg_RawFree(void* ptr); +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + static void AddAppendInfo(Object rootObj, AppendAllocEntry.Kind kind) + { + Compiler.Assert(sizeof(AppendAllocEntry) <= sizeof(int)*4); + + void Handle(AppendAllocEntry* headAllocEntry) + { + if (headAllocEntry.mKind case .None) + { + headAllocEntry.mKind = kind; + } + else + { + AppendAllocEntry* newAppendAllocEntry = (.)new uint8[sizeof(AppendAllocEntry)]*; + newAppendAllocEntry.mKind = kind; + newAppendAllocEntry.mNext = headAllocEntry.mNext; + headAllocEntry.mNext = newAppendAllocEntry; + } + } + + if (rootObj.[Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + uint8 allocFlag = (.)(dbgAllocInfo >> 8); + Debug.Assert(allocFlag == 1); + if ((allocFlag & 1) != 0) + { + int allocSize = (.)(dbgAllocInfo >> 16); + int capturedTraceCount = (uint8)(dbgAllocInfo); + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + ptr += allocSize + capturedTraceCount * sizeof(int); + Handle((.)ptr); + } + } + else if (rootObj.[Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + int allocSize = dbgAllocInfo; + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + int info = *(int*)(ptr + allocSize); + int capturedTraceCount = info >> 8; + uint8 allocFlag = (.)info; + Debug.Assert(allocFlag == 1); + if ((allocFlag & 1) != 0) + { + ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int); + Handle((.)ptr); + } + } + } +#endif + + public static void Dbg_ObjectAppended(Object rootObj, Object appendObj) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + AddAppendInfo(rootObj, .Object(appendObj)); +#endif + } + + public static void Dbg_RawAppended(Object rootObj, void* ptr, DbgRawAllocData* rawAllocData) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + AddAppendInfo(rootObj, .Raw(ptr, rawAllocData)); +#endif + } + + public static void Dbg_MarkAppended(Object rootObj) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + void Handle(AppendAllocEntry* checkAllocEntry) + { + var checkAllocEntry; + while (checkAllocEntry != null) + { + switch (checkAllocEntry.mKind) + { + case .Object(let obj): + obj.[Friend]GCMarkMembers(); + case .Raw(let rawPtr, let allocData): + ((function void(void*))allocData.mMarkFunc)(rawPtr); + default: + } + + checkAllocEntry = checkAllocEntry.mNext; + } + } + + if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + uint8 allocFlag = (.)(dbgAllocInfo >> 8); + if ((allocFlag & 1) != 0) + { + int allocSize = (.)(dbgAllocInfo >> 16); + int capturedTraceCount = (uint8)(dbgAllocInfo); + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + ptr += allocSize + capturedTraceCount * sizeof(int); + Handle((.)ptr); + } + } + else if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + int allocSize = dbgAllocInfo; + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + int info = *(int*)(ptr + allocSize); + int capturedTraceCount = info >> 8; + uint8 allocFlag = (.)info; + if ((allocFlag & 1) != 0) + { + ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int); + Handle((.)ptr); + } + } +#endif + } + + public static void Dbg_AppendDeleted(Object rootObj) + { +#if BF_ENABLE_OBJECT_DEBUG_FLAGS + void Handle(AppendAllocEntry* headAllocEntry) + { + AppendAllocEntry* checkAllocEntry = headAllocEntry; + while (checkAllocEntry != null) + { + switch (checkAllocEntry.mKind) + { + case .Object(let obj): +#unwarn + if (!obj.[DisableObjectAccessChecks]IsDeleted()) + { + if (obj.GetType().HasDestructor) + Debug.FatalError("Appended object not deleted with 'delete:append'"); + } + case .Raw(let rawPtr, let allocData): + default: + } + + var nextAllocEntry = checkAllocEntry.mNext; + if (checkAllocEntry == headAllocEntry) + *checkAllocEntry = default; + else + delete (uint8*)checkAllocEntry; + checkAllocEntry = nextAllocEntry; + } + } + + if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + uint8 allocFlag = (.)(dbgAllocInfo >> 8); + if ((allocFlag & 1) != 0) + { + int allocSize = (.)(dbgAllocInfo >> 16); + int capturedTraceCount = (uint8)(dbgAllocInfo); + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + ptr += allocSize + capturedTraceCount * sizeof(int); + Handle((.)ptr); + } + } + else if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0) + { + var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo; + int allocSize = dbgAllocInfo; + uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj); + int info = *(int*)(ptr + allocSize); + int capturedTraceCount = info >> 8; + uint8 allocFlag = (.)info; + if ((allocFlag & 1) != 0) + { + ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int); + Handle((.)ptr); + } + } +#endif + } + [CallingConvention(.Cdecl)] static extern void Shutdown_Internal(); @@ -304,19 +508,7 @@ namespace System } #else - enum BfObjectFlags : uint8 - { - None = 0, - Mark1 = 0x01, - Mark2 = 0x02, - Mark3 = 0x03, - Allocated = 0x04, - StackAlloc = 0x08, - AppendAlloc = 0x10, - AllocInfo = 0x20, - AllocInfo_Short = 0x40, - Deleted = 0x80 - }; + [NoReturn] static void Crash() diff --git a/BeefLibs/corlib/src/Reflection/TypeInstance.bf b/BeefLibs/corlib/src/Reflection/TypeInstance.bf index a8a0a7e2..f5bbce4c 100644 --- a/BeefLibs/corlib/src/Reflection/TypeInstance.bf +++ b/BeefLibs/corlib/src/Reflection/TypeInstance.bf @@ -178,7 +178,7 @@ namespace System.Reflection int32 stackCount = Compiler.Options.AllocStackCount; if (mAllocStackCountOverride != 0) stackCount = mAllocStackCountOverride; - obj = Internal.Dbg_ObjectAlloc(mTypeClassVData, allocSize, mInstAlign, stackCount); + obj = Internal.Dbg_ObjectAlloc(mTypeClassVData, allocSize, mInstAlign, stackCount, 0); #else void* mem = new [Align(16)] uint8[allocSize]* (?); obj = Internal.UnsafeCastToObject(mem); diff --git a/BeefLibs/corlib/src/Runtime.bf b/BeefLibs/corlib/src/Runtime.bf index 1006535c..42f2df7d 100644 --- a/BeefLibs/corlib/src/Runtime.bf +++ b/BeefLibs/corlib/src/Runtime.bf @@ -111,7 +111,7 @@ namespace System function void* (int size) mAlloc; function void (void* ptr) mFree; function void (Object obj) mObject_Delete; - void* mUnused0; + function void* (ClassVData* vdataPtr) mClassVData_GetTypeData; function Type (Object obj) mObject_GetType; function void (Object obj) mObject_GCMarkMembers; function Object (Object obj, int32 typeId) mObject_DynamicCastToTypeId; @@ -152,6 +152,16 @@ namespace System delete obj; } + static void* ClassVData_GetTypeData(ClassVData* classVData) + { +#if BF_32_BIT + Type type = Type.[Friend]GetType_(classVData.mType2); +#else + Type type = Type.[Friend]GetType_((.)(classVData.mType >> 32)); +#endif + return &type.[Friend]mSize; + } + static Type Object_GetType(Object obj) { #if BF_DBG_RUNTIME @@ -259,6 +269,7 @@ namespace System mAlloc = => Alloc; mFree = => Free; mObject_Delete = => Object_Delete; + mClassVData_GetTypeData = => ClassVData_GetTypeData; mObject_GetType = => Object_GetType; mObject_GCMarkMembers = => Object_GCMarkMembers; mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId; diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 4f724970..0b5cd53f 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -1660,7 +1660,7 @@ namespace System.Reflection int32 stackCount = Compiler.Options.AllocStackCount; if (mAllocStackCountOverride != 0) stackCount = mAllocStackCountOverride; - obj = Internal.Dbg_ObjectAlloc([Friend]mTypeClassVData, arraySize, [Friend]mInstAlign, stackCount); + obj = Internal.Dbg_ObjectAlloc([Friend]mTypeClassVData, arraySize, [Friend]mInstAlign, stackCount, 0); #else void* mem = new [Align(16)] uint8[arraySize]* (?); obj = Internal.UnsafeCastToObject(mem); @@ -1720,6 +1720,7 @@ namespace System.Reflection Static = 0x200000, Abstract = 0x400000, + HasAppendWantMark = 0x800000, } public enum FieldFlags : uint16 diff --git a/BeefRT/dbg/DbgInternal.cpp b/BeefRT/dbg/DbgInternal.cpp index 754dc74a..34b0db97 100644 --- a/BeefRT/dbg/DbgInternal.cpp +++ b/BeefRT/dbg/DbgInternal.cpp @@ -49,10 +49,10 @@ namespace bf BFRT_EXPORT static void Dbg_ObjectCreatedEx(bf::System::Object* result, intptr size, bf::System::ClassVData* classVData); BFRT_EXPORT static void Dbg_ObjectAllocated(bf::System::Object* result, intptr size, bf::System::ClassVData* classVData); BFRT_EXPORT static void Dbg_ObjectAllocatedEx(bf::System::Object* result, intptr size, bf::System::ClassVData* classVData); - BFRT_EXPORT static Object* Dbg_ObjectAlloc(bf::System::Reflection::TypeInstance* typeInst, intptr size); - BFRT_EXPORT static Object* Dbg_ObjectAlloc(bf::System::ClassVData* classVData, intptr size, intptr align, intptr maxStackTraceDept); + BFRT_EXPORT static Object* Dbg_ObjectAlloc(bf::System::Reflection::TypeInstance* typeInst, intptr size); + BFRT_EXPORT static Object* Dbg_ObjectAlloc(bf::System::ClassVData* classVData, intptr size, intptr align, intptr maxStackTraceDept, uint8 allocFlags); BFRT_EXPORT static void Dbg_MarkObjectDeleted(bf::System::Object* obj); - BFRT_EXPORT static void Dbg_ObjectStackInit(bf::System::Object* result, bf::System::ClassVData* classVData); + BFRT_EXPORT static void Dbg_ObjectStackInit(bf::System::Object* result, bf::System::ClassVData* classVData, intptr size, uint8 allocFlags); BFRT_EXPORT static void Dbg_ObjectPreDelete(bf::System::Object* obj); BFRT_EXPORT static void Dbg_ObjectPreCustomDelete(bf::System::Object* obj); @@ -315,20 +315,28 @@ bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::Reflection::TypeInstan //#define DBG_OBJECTEND -bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData, intptr size, intptr align, intptr maxStackTraceDepth) +bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData, intptr size, intptr align, intptr maxStackTraceDepth, uint8 allocFlags) { void* stackTrace[1024]; int capturedTraceCount = 0; intptr allocSize = size; bool largeAllocInfo = false; - + if ((BFRTFLAGS & BfRtFlags_ObjectHasDebugFlags) != 0) { if (maxStackTraceDepth > 1) { capturedTraceCount = BF_CAPTURE_STACK(1, (intptr*)stackTrace, min((int)maxStackTraceDepth, 1024)); const intptr maxSmallObjectSize = ((intptr)1 << ((sizeof(intptr) - 2) * 8)) - 1; - if ((capturedTraceCount > 255) || (size >= maxSmallObjectSize)) + + bool forceLarge = false; + auto typeData = BFRTCALLBACKS.ClassVData_GetTypeDataPtr(classVData); + if ((typeData->mTypeFlags & BfTypeFlag_HasAppendWantMark) != 0) + { + forceLarge = true; + } + + if ((capturedTraceCount > 255) || (size >= maxSmallObjectSize) || (forceLarge)) { largeAllocInfo = true; allocSize += (1 + capturedTraceCount) * sizeof(intptr); @@ -336,6 +344,12 @@ bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData else allocSize += capturedTraceCount * sizeof(intptr); } + + // Append want mark + if ((allocFlags & 1) != 0) + { + allocSize += 4 * sizeof(intptr); + } } #ifdef DBG_OBJECTEND @@ -385,7 +399,7 @@ bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData intptr dbgAllocInfo; auto classVDataVal = (intptr)classVData | (intptr)BfObjectFlag_Allocated; - if (maxStackTraceDepth <= 1) + if ((maxStackTraceDepth <= 1) && (allocFlags == 0)) dbgAllocInfo = (intptr)BF_RETURN_ADDRESS; else { @@ -393,13 +407,13 @@ bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData { classVDataVal |= (intptr)BfObjectFlag_AllocInfo; dbgAllocInfo = size; - *(intptr*)((uint8*)result + size) = capturedTraceCount; + *(intptr*)((uint8*)result + size) = (capturedTraceCount << 8) | allocFlags; memcpy((uint8*)result + size + sizeof(intptr), stackTrace, capturedTraceCount * sizeof(intptr)); } else { classVDataVal |= (intptr)BfObjectFlag_AllocInfo_Short; - dbgAllocInfo = (size << 16) | capturedTraceCount; + dbgAllocInfo = (size << 16) | (((intptr)allocFlags) << 8) | capturedTraceCount; memcpy((uint8*)result + size, stackTrace, capturedTraceCount * sizeof(intptr)); } } @@ -424,13 +438,27 @@ bf::System::Object* Internal::Dbg_ObjectAlloc(bf::System::ClassVData* classVData return result; } -void Internal::Dbg_ObjectStackInit(bf::System::Object* result, bf::System::ClassVData* classVData) +void Internal::Dbg_ObjectStackInit(bf::System::Object* result, bf::System::ClassVData* classVData, intptr totalSize, uint8 allocFlags) { BF_ASSERT((BFRTFLAGS & BfRtFlags_ObjectHasDebugFlags) != 0); result->mClassVData = (intptr)classVData | (intptr)BfObjectFlag_StackAlloc; #ifndef BFRT_NODBGFLAGS - result->mDbgAllocInfo = (intptr)BF_RETURN_ADDRESS; + if ((allocFlags & 1) == 0) + { + result->mDbgAllocInfo = (intptr)BF_RETURN_ADDRESS; + } + else + { + int size = (int)(totalSize - sizeof(intptr) - sizeof(intptr) * 4); + + int capturedTraceCount = 1; + *(intptr*)((uint8*)result + size) = (intptr)BF_RETURN_ADDRESS; + memset((uint8*)result + size + sizeof(intptr), 0, sizeof(intptr) * 4); + result->mDbgAllocInfo = (size << 16) | (((intptr)allocFlags) << 8) | capturedTraceCount; + BF_FULL_MEMORY_FENCE(); + result->mClassVData |= (intptr)BfObjectFlag_AllocInfo_Short; + } #endif } diff --git a/BeefRT/dbg/gc.cpp b/BeefRT/dbg/gc.cpp index e74cce25..5bc20ea6 100644 --- a/BeefRT/dbg/gc.cpp +++ b/BeefRT/dbg/gc.cpp @@ -2670,10 +2670,13 @@ void BFGC::WriteDebugDumpState() { //const bf::System::Type* bfTypeRootData = ((bf::System::Type*)obj->GetTypeSafe())->mTypeRootData; bf::System::Type* bfType = obj->GetTypeSafe(); - while ((int) debugInfoVector.size() <= bfType->mTypeId) + + auto typeData = bfType->GetTypeData(); + + while ((int) debugInfoVector.size() <= typeData->mTypeId) debugInfoVector.push_back(DebugInfo()); - DebugInfo* debugInfo = &debugInfoVector[bfType->mTypeId]; + DebugInfo* debugInfo = &debugInfoVector[typeData->mTypeId]; debugInfo->mType = obj->GetTypeSafe(); debugInfo->mCount++; int objSize = BFGetObjectSize(obj); diff --git a/BeefRT/dbg/gc_raw.cpp b/BeefRT/dbg/gc_raw.cpp index f24c8554..df73ad38 100644 --- a/BeefRT/dbg/gc_raw.cpp +++ b/BeefRT/dbg/gc_raw.cpp @@ -115,16 +115,18 @@ void BFGC::RawMarkSpan(tcmalloc_raw::Span* span, int expectedStartPage) if (rawAllocData != NULL) { if (rawAllocData->mMarkFunc != NULL) - { + { intptr extraDataSize = sizeof(intptr); if (rawAllocData->mMaxStackTrace == 1) { - extraDataSize += sizeof(intptr); + extraDataSize += sizeof(intptr) + 2; + extraDataSize += *(uint16*)((uint8*)spanPtr + elementSize - sizeof(intptr) - sizeof(intptr) - 2); } else if (rawAllocData->mMaxStackTrace > 1) { intptr stackTraceCount = *(intptr*)((uint8*)spanPtr + elementSize - sizeof(intptr) - sizeof(intptr)); - extraDataSize += (1 + stackTraceCount) * sizeof(intptr); + extraDataSize += (1 + stackTraceCount) * sizeof(intptr) + 2; + extraDataSize += *(uint16*)((uint8*)spanPtr + elementSize - sizeof(intptr) - sizeof(intptr) - stackTraceCount * sizeof(intptr) - 2); } struct MarkTarget @@ -132,17 +134,21 @@ void BFGC::RawMarkSpan(tcmalloc_raw::Span* span, int expectedStartPage) }; typedef void(MarkTarget::*MarkFunc)(); MarkFunc markFunc = *(MarkFunc*)&rawAllocData->mMarkFunc; - - // It's possible we can overestimate elemCount, particularly for large allocations. This doesn't cause a problem - // because we can safely mark on complete random memory -- pointer values are always validated before being followed - intptr elemStride = BF_ALIGN(rawAllocData->mType->mSize, rawAllocData->mType->mAlign); - if (elemStride > 0) + + auto typeData = rawAllocData->mType->GetTypeData(); + if (typeData != NULL) { - intptr dataSize = elementSize - extraDataSize; - intptr elemCount = dataSize / elemStride; - for (intptr elemIdx = 0; elemIdx < elemCount; elemIdx++) + // It's possible we can overestimate elemCount, particularly for large allocations. This doesn't cause a problem + // because we can safely mark on complete random memory -- pointer values are always validated before being followed + intptr elemStride = BF_ALIGN(typeData->mSize, typeData->mAlign); + if (elemStride > 0) { - (((MarkTarget*)((uint8*)spanPtr + elemIdx * elemStride))->*markFunc)(); + intptr dataSize = elementSize - extraDataSize; + intptr elemCount = dataSize / elemStride; + for (intptr elemIdx = 0; elemIdx < elemCount; elemIdx++) + { + (((MarkTarget*)((uint8*)spanPtr + elemIdx * elemStride))->*markFunc)(); + } } } } @@ -282,13 +288,13 @@ void BFGC::RawReportHandleSpan(tcmalloc_raw::Span* span, int expectedStartPage, if (rawAllocData->mType != NULL) { - intptr typeSize; - if ((gBfRtDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0) - typeSize = rawAllocData->mType->mSize; - else - typeSize = ((bf::System::Type_NOFLAGS*)rawAllocData->mType)->mSize; - if (typeSize > 0) - rawLeakInfo.mDataCount = (elementSize - extraDataSize) / typeSize; + bf::System::Type_NOFLAGS* typeData = rawAllocData->mType->GetTypeData(); + if (typeData != NULL) + { + intptr typeSize = typeData->mSize; + if (typeSize > 0) + rawLeakInfo.mDataCount = (elementSize - extraDataSize) / typeSize; + } } else rawLeakInfo.mDataCount = 1; @@ -558,8 +564,8 @@ void* BfRawAllocate(intptr size, bf::System::DbgRawAllocData* rawAllocData, void markOffsetPtr = (uint16*)((uint8*)result + totalSize - sizeof(intptr) - sizeof(intptr) - 2); } else if (rawAllocData->mMaxStackTrace > 1) - { - memcpy((uint8*)result + totalSize - sizeof(intptr) - sizeof(intptr), &stackTraceCount, sizeof(intptr)); + { + *(intptr*)((uint8*)result + totalSize - sizeof(intptr) - sizeof(intptr)) = stackTraceCount; memcpy((uint8*)result + totalSize - sizeof(intptr) - sizeof(intptr) - stackTraceCount*sizeof(intptr), stackTraceInfo, stackTraceCount*sizeof(intptr)); markOffsetPtr = (uint16*)((uint8*)result + totalSize - sizeof(intptr) - sizeof(intptr) - stackTraceCount * sizeof(intptr) - 2); } diff --git a/BeefRT/rt/BfObjects.h b/BeefRT/rt/BfObjects.h index f6a7b983..07f7b38d 100644 --- a/BeefRT/rt/BfObjects.h +++ b/BeefRT/rt/BfObjects.h @@ -59,6 +59,8 @@ namespace bf { namespace System { + class Type_NOFLAGS; + struct DbgRawAllocData { Type* mType; @@ -84,7 +86,7 @@ namespace bf void*(*Alloc)(intptr size); void(*Free)(void* ptr); void(*Object_Delete)(bf::System::Object* obj); - void* mUnused0; + Type_NOFLAGS*(*ClassVData_GetTypeDataPtr)(bf::System::ClassVData* classVData); bf::System::Type* (*Object_GetType)(bf::System::Object* obj); void(*Object_GCMarkMembers)(bf::System::Object* obj); bf::System::Object* (*Object_DynamicCastToTypeId)(bf::System::Object* obj, int typeId); @@ -196,28 +198,25 @@ namespace bf typedef int32 TypeId; + enum BfTypeFlags : uint32 + { + BfTypeFlag_HasAppendWantMark = 0x800000 + }; + class Type : public Object { - public: - int32 mSize; - TypeId mTypeId; - TypeId mBoxedId; - uint16 mTypeFlags; - int32 mMemberDataOffset; - uint8 mTypeCode; - uint8 mAlign; - + public: Beefy::String GetFullName(); + Type_NOFLAGS* GetTypeData(); }; class Type_NOFLAGS { - public: - intptr mClassVData; + public: int32 mSize; TypeId mTypeId; TypeId mBoxedId; - uint16 mTypeFlags; + BfTypeFlags mTypeFlags; int32 mMemberDataOffset; uint8 mTypeCode; uint8 mAlign; diff --git a/BeefRT/rt/Object.cpp b/BeefRT/rt/Object.cpp index 87c94262..41cf7506 100644 --- a/BeefRT/rt/Object.cpp +++ b/BeefRT/rt/Object.cpp @@ -20,3 +20,11 @@ Beefy::String bf::System::Type::GetFullName() BFRTCALLBACKS.Object_Delete(strObj); return str; } + +bf::System::Type_NOFLAGS* bf::System::Type::GetTypeData() +{ + if ((BFRTFLAGS & BfRtFlags_ObjectHasDebugFlags) != 0) + return BFRTCALLBACKS.ClassVData_GetTypeDataPtr((bf::System::ClassVData*)(mClassVData & ~0xFF)); + else + return BFRTCALLBACKS.ClassVData_GetTypeDataPtr((bf::System::ClassVData*)(mClassVData)); +} \ No newline at end of file diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index ca1c7c32..b0aca5ae 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -1232,6 +1232,7 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild typeInst->mHasPackingHoles = false; typeInst->mWantsGCMarking = false; typeInst->mHasDeclError = false; + typeInst->mHasAppendWantMark = false; delete typeInst->mTypeInfoEx; typeInst->mTypeInfoEx = NULL; diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index f2bdb7a0..e5eba3b3 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -2067,6 +2067,15 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) BfMethodDef* strictEqualsMethod = NULL; bool needsStaticInit = false; + if (mCurTypeDef->IsExtension()) + needsDefaultCtor = false; + + bool needsDtor = false; + bool needsStaticDtor = false; + bool hasStaticField = false; + bool hasNonStaticField = false; + bool hasThreadStatics = false; + for (int methodIdx = 0; methodIdx < (int)mCurTypeDef->mMethods.size(); methodIdx++) { auto method = mCurTypeDef->mMethods[methodIdx]; @@ -2080,6 +2089,9 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) if (method->mMethodType == BfMethodType_Ctor) { + if (method->HasAppend()) + needsDtor = true; + if (method->mIsStatic) { if ((staticCtor != NULL) && (staticCtor->mMethodDeclaration != NULL)) @@ -2239,15 +2251,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString) if ((method->mImportKind == BfImportKind_Import_Dynamic) || (method->mImportKind == BfImportKind_Import_Unknown)) needsStaticInit = true; } - - if (mCurTypeDef->IsExtension()) - needsDefaultCtor = false; - - bool needsDtor = false; - bool needsStaticDtor = false; - bool hasStaticField = false; - bool hasNonStaticField = false; - bool hasThreadStatics = false; + for (auto field : mCurTypeDef->mFields) { if (field->mIsStatic) diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index e0f00d1b..5ea75988 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -7492,7 +7492,7 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth else allowThisSplatting = methodInstance->AllowsSplatting(-1); - if ((!allowThisSplatting) || (methodDef->mIsMutating)) + if ((!allowThisSplatting) || (methodDef->mIsMutating) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl)) { argVal = mModule->MakeAddressable(argVal); irArgs.push_back(argVal.mValue); @@ -16569,7 +16569,8 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs int allocAlign = resolvedTypeRef->mAlign; if (typeInstance != NULL) allocAlign = typeInstance->mInstAlign; - int appendAllocAlign = 0; + int appendAllocAlign = 0; + BfAllocFlags allocFlags = BfAllocFlags_None; if ((bindResult.mMethodInstance != NULL) && (bindResult.mMethodInstance->mMethodDef->HasAppend())) { @@ -16605,6 +16606,9 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs appendSizeValue = appendSizeTypedValue.mValue; allocAlign = BF_MAX(allocAlign, calcAppendMethodModule.mMethodInstance->mAppendAllocAlign); appendAllocAlign = calcAppendMethodModule.mMethodInstance->mAppendAllocAlign; + + if (calcAppendMethodModule.mMethodInstance->mHasAppendWantMark) + allocFlags = (BfAllocFlags)(allocFlags | BfAllocFlags_HasAppendWantMark); } if (appendAllocAlign != 0) @@ -16616,6 +16620,12 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs appendSizeValue = mModule->mBfIRBuilder->CreateAdd(appendSizeValue, mModule->GetConstValue(extraSize)); } } + + if ((allocFlags & BfAllocFlags_HasAppendWantMark) != 0) + { + int markInfoSize = sizeof(intptr) + sizeof(intptr) * 4; // Stack trace, MarkAppendEntry + appendSizeValue = mModule->mBfIRBuilder->CreateAdd(appendSizeValue, mModule->GetConstValue(markInfoSize)); + } } // WTF? I'm not even sure this is correct - add more tests @@ -16635,7 +16645,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } else { - allocValue = mModule->AllocFromType(resolvedTypeRef, allocTarget, appendSizeValue, BfIRValue(), 0, BfAllocFlags_None, allocAlign); + allocValue = mModule->AllocFromType(resolvedTypeRef, allocTarget, appendSizeValue, BfIRValue(), 0, allocFlags, allocAlign); } if (((mBfEvalExprFlags & BfEvalExprFlags_Comptime) != 0) && (mModule->mCompiler->mCeMachine != NULL)) { @@ -16710,14 +16720,21 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs { auto impMethodInstance = (BfMethodInstance*)vtableEntry.mImplementingMethod; bool needsCall = false; - if (impMethodInstance != NULL) - { - needsCall = impMethodInstance->mMethodDef->mBody != NULL; - } - else - { + + if (allocFlags & BfAllocFlags_HasAppendWantMark) needsCall = true; - BF_ASSERT(vtableEntry.mImplementingMethod.mKind == BfMethodRefKind_AmbiguousRef); + + if (!needsCall) + { + if (impMethodInstance != NULL) + { + needsCall = impMethodInstance->mMethodDef->mBody != NULL; + } + else + { + needsCall = true; + BF_ASSERT(vtableEntry.mImplementingMethod.mKind == BfMethodRefKind_AmbiguousRef); + } } if (!needsCall) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index d18767aa..bffd377b 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -475,6 +475,7 @@ public: BfTypedValue mConstAccum; bool mFailed; bool mIsFirstConstPass; + bool mHasAppendWantMark; int mCurAppendAlign; public: @@ -482,6 +483,7 @@ public: { mFailed = false; mIsFirstConstPass = false; + mHasAppendWantMark = false; mCurAppendAlign = 1; } @@ -654,6 +656,9 @@ public: return; } + if (origResolvedTypeRef->WantsGCMarking()) + mHasAppendWantMark = true; + bool isGenericParam = origResolvedTypeRef->IsGenericParam(); auto resolvedTypeRef = origResolvedTypeRef; auto resultType = resolvedTypeRef; @@ -6272,6 +6277,8 @@ BfIRValue BfModule::GetTypeTypeData(BfType* type, BfCreateTypeDataContext& ctx, typeFlags |= BfTypeFlags_Static; if ((typeInstance != NULL) && (typeInstance->mTypeDef->mIsAbstract)) typeFlags |= BfTypeFlags_Abstract; + if ((typeInstance != NULL) && (typeInstance->mHasAppendWantMark)) + typeFlags |= BfTypeFlags_HasAppendWantMark; return typeTypeData; } @@ -9534,7 +9541,7 @@ BfTypedValue BfModule::GetOrCreateVarAddr(BfExpression* expr) } // Clear memory, set classVData, call init. Actual ctor is called elsewhere. -void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, bool zeroMemory, BfIRValue sizeValue) +void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, bool zeroMemory, BfIRValue sizeValue, BfAllocFlags allocFlags) { auto typeInstance = typedValue.mType->ToTypeInstance(); if (zeroMemory) @@ -9581,6 +9588,8 @@ void BfModule::InitTypeInst(BfTypedValue typedValue, BfScopeData* scopeData, boo SizedArray llvmArgs; llvmArgs.push_back(objectPtr); llvmArgs.push_back(vDataRef); + llvmArgs.push_back(sizeValue); + llvmArgs.push_back(mBfIRBuilder->CreateConst(BfTypeCode_Int8, allocFlags)); auto objectStackInitMethod = GetInternalMethod("Dbg_ObjectStackInit"); if (objectStackInitMethod) @@ -10213,7 +10222,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget doCondAlloca = !wasDynAlloc && isDynAlloc && mCurMethodState->mInConditionalBlock; AddStackAlloc(typedVal, arraySize, NULL, scopeData, doCondAlloca, true); } - InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue); + InitTypeInst(typedVal, scopeData, zeroMemory, sizeValue, allocFlags); return typedVal.mValue; } @@ -10443,7 +10452,8 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget llvmArgs.push_back(sizeValue); llvmArgs.push_back(GetConstValue(typeInstance->mAlign)); llvmArgs.push_back(GetConstValue(stackCount)); - auto moduleMethodInstance = GetInternalMethod("Dbg_ObjectAlloc", 4); + llvmArgs.push_back(GetConstValue(allocFlags, GetPrimitiveType(BfTypeCode_Int8))); + auto moduleMethodInstance = GetInternalMethod("Dbg_ObjectAlloc", 5); BfIRValue objectVal = mBfIRBuilder->CreateCall(moduleMethodInstance.mFunc, llvmArgs); result = mBfIRBuilder->CreateBitCast(objectVal, mBfIRBuilder->MapType(typeInstance)); } @@ -10647,6 +10657,9 @@ BfIRValue BfModule::AppendAllocFromType(BfType* type, BfIRValue appendSizeValue, BfIRType toType; if (typeInst != NULL) { + mBfIRBuilder->PopulateType(typeInst); + if (typeInst->WantsGCMarking()) + mCurTypeInstance->mHasAppendWantMark = true; EmitAppendAlign(typeInst->mInstAlign, typeInst->mInstSize); sizeValue = GetConstValue(typeInst->mInstSize); toType = mBfIRBuilder->MapTypeInstPtr(typeInst); @@ -10665,6 +10678,35 @@ BfIRValue BfModule::AppendAllocFromType(BfType* type, BfIRValue appendSizeValue, retTypeInstance = typeInst; retValue = mBfIRBuilder->CreateIntToPtr(curIdxVal, toType); + + if ((typeInst != NULL) && (typeInst->WantsGCMarking()) && (mCompiler->mOptions.mDebugAlloc)) + { + auto curThis = GetThis(); + auto thisObj = Cast(mCurMethodInstance->mMethodDef->GetRefNode(), curThis, mContext->mBfObjectType); + + if (typeInst->IsObject()) + { + auto appendedObj = Cast(mCurMethodInstance->mMethodDef->GetRefNode(), BfTypedValue(retValue, typeInst), mContext->mBfObjectType); + BfModuleMethodInstance allocMethod = GetInternalMethod("Dbg_ObjectAppended", 2); + SizedArray llvmArgs; + llvmArgs.push_back(thisObj.mValue); + llvmArgs.push_back(appendedObj.mValue); + mBfIRBuilder->CreateCall(allocMethod.mFunc, llvmArgs); + } + else + { + // Raw + BfIRValue allocPtr = mBfIRBuilder->CreateBitCast(retValue, mBfIRBuilder->MapType(voidPtrType)); + BfIRValue allocData = GetDbgRawAllocData(type); + BfModuleMethodInstance allocMethod = GetInternalMethod("Dbg_RawAppended", 3); + + SizedArray llvmArgs; + llvmArgs.push_back(thisObj.mValue); + llvmArgs.push_back(allocPtr); + llvmArgs.push_back(allocData); + mBfIRBuilder->CreateCall(allocMethod.mFunc, llvmArgs); + } + } } if ((retTypeInstance != NULL) && (retTypeInstance->IsObject())) @@ -15871,7 +15913,7 @@ BfTypedValue BfModule::GetThis(bool markUsing) auto curMethodOwner = mCurMethodInstance->mMethodInstanceGroup->mOwner; if ((curMethodOwner->IsStruct()) || (curMethodOwner->IsTypedPrimitive())) { - if ((localDef->mResolvedType->IsTypedPrimitive()) && (!mCurMethodInstance->mMethodDef->mIsMutating)) + if ((localDef->mResolvedType->IsTypedPrimitive()) && (!mCurMethodInstance->mMethodDef->mIsMutating) && (mCurMethodInstance->mCallingConvention != BfCallingConvention_Cdecl)) { return BfTypedValue(thisValue, useMethodState->mLocals[0]->mResolvedType, BfTypedValueKind_ReadOnlyThisValue); } @@ -17411,12 +17453,15 @@ BfTypedValue BfModule::TryConstCalcAppend(BfMethodInstance* methodInst, SizedArr appendAllocVisitor.mFailed = true; if (!appendAllocVisitor.mFailed) constValue = appendAllocVisitor.mConstAccum; + if (appendAllocVisitor.mHasAppendWantMark) + methodInst->mHasAppendWantMark = true; + if (isFirstRun) { mCurMethodInstance->mEndingAppendAllocAlign = appendAllocVisitor.mCurAppendAlign; if (mCurMethodInstance->mAppendAllocAlign <= 0) mCurMethodInstance->mAppendAllocAlign = 1; - } + } if (isFirstRun) { @@ -18090,6 +18135,19 @@ void BfModule::EmitDtorBody() } } } + + // If there are appends then we just need the rootmost append type to do the Dbg_AppendDeleted + if ((!mIsComptimeModule) && (!methodDef->mIsStatic) && (mCompiler->mOptions.mDebugAlloc) && + (mCurTypeInstance->HasAppendCtor()) && (!mCurTypeInstance->BaseHasAppendCtor())) + { + auto thisValue = GetThis(); + auto appendedObj = mBfIRBuilder->CreateBitCast(thisValue.mValue, mBfIRBuilder->MapType(mContext->mBfObjectType)); + BfModuleMethodInstance allocMethod = GetInternalMethod("Dbg_AppendDeleted", 1); + SizedArray llvmArgs; + llvmArgs.push_back(appendedObj); + if (allocMethod) + mBfIRBuilder->CreateCall(allocMethod.mFunc, llvmArgs); + } } BfIRValue BfModule::CreateDllImportGlobalVar(BfMethodInstance* methodInstance, bool define) @@ -20534,6 +20592,19 @@ void BfModule::EmitGCMarkMembers() CallChainedMethods(mCurMethodInstance, false); } } + + // If there are appends then we just need the rootmost append type to do the Dbg_MarkAppended + if ((!mIsComptimeModule) && (!methodDef->mIsStatic) && (mCompiler->mOptions.mDebugAlloc) && + (mCurTypeInstance->HasAppendCtor()) && (!mCurTypeInstance->BaseHasAppendCtor())) + { + auto thisValue = GetThis(); + auto appendedObj = mBfIRBuilder->CreateBitCast(thisValue.mValue, mBfIRBuilder->MapType(mContext->mBfObjectType)); + BfModuleMethodInstance allocMethod = GetInternalMethod("Dbg_MarkAppended", 1); + SizedArray llvmArgs; + llvmArgs.push_back(appendedObj); + if (allocMethod) + mBfIRBuilder->CreateCall(allocMethod.mFunc, llvmArgs); + } } void BfModule::EmitGCFindTLSMembers() @@ -21452,7 +21523,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, else { bool wantPtr = (thisType->IsComposite()) && (!paramVar->mIsLowered); - if ((thisType->IsTypedPrimitive()) && (methodDef->HasNoThisSplat())) + if ((thisType->IsTypedPrimitive()) && + ((methodDef->HasNoThisSplat()) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl))) wantPtr = true; if (wantPtr) @@ -21582,7 +21654,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, { diType = mBfIRBuilder->DbgGetType(paramVar->mResolvedType); bool wantRef = paramVar->mResolvedType->IsComposite(); - if ((paramVar->mResolvedType->IsTypedPrimitive()) && (methodDef->HasNoThisSplat())) + if ((paramVar->mResolvedType->IsTypedPrimitive()) && + ((methodDef->HasNoThisSplat()) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl))) wantRef = true; if (wantRef) @@ -23897,6 +23970,12 @@ void BfModule::GetMethodCustomAttributes(BfMethodInstance* methodInstance) } methodInstance->mCallingConvention = methodDef->mCallingConvention; + if ((typeInstance->IsValueType()) && (methodDef->mIsOverride) && (methodDef->mName == BF_METHODNAME_MARKMEMBERS)) + { + // Make sure we we pass 'this' as a pointer into GCMarkMembers so it's compatible with the mark function pointer + methodInstance->mCallingConvention = BfCallingConvention_Cdecl; + } + if (customAttributes != NULL) { auto linkNameAttr = customAttributes->Get(mCompiler->mCallingConventionAttributeTypeDef); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index ac072582..3cf97f7a 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -128,10 +128,11 @@ enum BfCastResultFlags : int8 enum BfAllocFlags : int8 { BfAllocFlags_None = 0, - BfAllocFlags_RawArray = 1, - BfAllocFlags_ZeroMemory = 2, - BfAllocFlags_NoDtorCall = 4, - BfAllocFlags_NoDefaultToMalloc = 8 + BfAllocFlags_HasAppendWantMark = 1, + BfAllocFlags_RawArray = 2, + BfAllocFlags_ZeroMemory = 4, + BfAllocFlags_NoDtorCall = 8, + BfAllocFlags_NoDefaultToMalloc = 0x10, }; enum BfProtectionCheckFlags : int8 @@ -1736,7 +1737,7 @@ public: void CleanupFileInstances(); void AssertErrorState(); void AssertParseErrorState(); - void InitTypeInst(BfTypedValue typedValue, BfScopeData* scope, bool zeroMemory, BfIRValue dataSize); + void InitTypeInst(BfTypedValue typedValue, BfScopeData* scope, bool zeroMemory, BfIRValue dataSize, BfAllocFlags allocFlags = BfAllocFlags_None); bool IsAllocatorAligned(); BfIRValue AllocBytes(BfAstNode* refNode, const BfAllocTarget& allocTarget, BfType* type, BfIRValue sizeValue, BfIRValue alignValue, BfAllocFlags allocFlags/*bool zeroMemory, bool defaultToMalloc*/); BfIRValue GetMarkFuncPtr(BfType* type); diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 4e0227d1..9b8af084 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -1381,11 +1381,6 @@ int BfMethodInstance::DbgGetVirtualMethodNum() void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, SizedArrayImpl& paramTypes, bool forceStatic) { - if (mMethodDef->mName == "Test4") - { - NOP; - } - BfModule* resolveModule = module->mContext->mUnreifiedModule; resolveModule->PopulateType(mReturnType); @@ -1458,7 +1453,11 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, bool doSplat = false; if (paramIdx == -1) { - if ((!mMethodDef->mIsMutating) && (checkType->IsTypedPrimitive())) + if (mCallingConvention == BfCallingConvention_Cdecl) + { + // Pass by pointer even for typed primitives + } + else if ((!mMethodDef->mIsMutating) && (checkType->IsTypedPrimitive())) { checkType = checkType->GetUnderlyingType(); } @@ -2468,6 +2467,22 @@ bool BfTypeInstance::IsAnonymousInitializerType() return (mTypeDef->mTypeDeclaration != NULL) && (mTypeDef->mTypeDeclaration->IsAnonymousInitializerType()); } +bool BfTypeInstance::HasAppendCtor() +{ + return mTypeDef->mHasAppendCtor; +} + +bool BfTypeInstance::BaseHasAppendCtor() +{ + if (mBaseType != NULL) + { + if (mBaseType->HasAppendCtor()) + return true; + return mBaseType->BaseHasAppendCtor(); + } + return false; +} + void BfTypeInstance::ReportMemory(MemReporter* memReporter) { if (mGenericTypeInfo != NULL) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 4d05e516..cd27b64c 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -908,6 +908,7 @@ public: bool mInCEMachine:1; bool mCeCancelled:1; bool mIsDisposed:1; + bool mHasAppendWantMark:1; BfMethodChainType mChainType; BfComptimeFlags mComptimeFlags; BfCallingConvention mCallingConvention; @@ -951,6 +952,7 @@ public: mInCEMachine = false; mCeCancelled = false; mIsDisposed = false; + mHasAppendWantMark = false; mChainType = BfMethodChainType_None; mComptimeFlags = BfComptimeFlag_None; mCallingConvention = BfCallingConvention_Unspecified; @@ -2064,6 +2066,7 @@ public: bool mHasPackingHoles; bool mWantsGCMarking; bool mHasDeclError; + bool mHasAppendWantMark; public: BfTypeInstance() @@ -2116,6 +2119,7 @@ public: mWantsGCMarking = false; mHasParameterizedBase = false; mHasDeclError = false; + mHasAppendWantMark = false; mMergedFieldDataCount = 0; mConstHolder = NULL; } @@ -2213,6 +2217,8 @@ public: bool DefineStateAllowsStaticMethods() { return mDefineState >= BfTypeDefineState_HasInterfaces_Direct; } bool IsAnonymous(); bool IsAnonymousInitializerType(); + bool HasAppendCtor(); + bool BaseHasAppendCtor(); virtual void ReportMemory(MemReporter* memReporter) override; }; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 7d3123c1..eefbe3ba 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -239,6 +239,7 @@ enum BfTypeFlags BfTypeFlags_Static = 0x200000, BfTypeFlags_Abstract = 0x400000, + BfTypeFlags_HasAppendWantMark = 0x800000, }; enum BfMethodFlags diff --git a/IDEHelper/WinDebugger.cpp b/IDEHelper/WinDebugger.cpp index d2419b55..e95f6a96 100644 --- a/IDEHelper/WinDebugger.cpp +++ b/IDEHelper/WinDebugger.cpp @@ -8513,7 +8513,7 @@ String WinDebugger::DbgTypedValueToString(const DbgTypedValue& origTypedValue, c { addr_target objectSize = ReadMemory(ptrVal + sizeof(addr_target)); addr_target largeAllocInfo = ReadMemory(ptrVal + objectSize); - stackTraceLen = largeAllocInfo & 0xFFFF; + stackTraceLen = (largeAllocInfo >> 8) & 0xFFFF; stackTraceAddr = ptrVal + objectSize + sizeof(addr_target); } else if ((bfObjectFlags & BfObjectFlag_AllocInfo_Short) != 0)