mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-10 12:32:20 +02:00
331 lines
8.3 KiB
Beef
331 lines
8.3 KiB
Beef
#if BF_ENABLE_OBJECT_DEBUG_FLAGS || BF_DEBUG_ALLOC
|
|
#define BF_DBG_RUNTIME
|
|
#endif
|
|
|
|
namespace System
|
|
{
|
|
[StaticInitPriority(100)]
|
|
class Runtime
|
|
{
|
|
const int32 cVersion = 8;
|
|
|
|
[CRepr, AlwaysInclude]
|
|
struct BfDebugMessageData
|
|
{
|
|
enum MessageType : int32
|
|
{
|
|
None = 0,
|
|
Error = 1,
|
|
ProfilerCmd = 2
|
|
};
|
|
|
|
MessageType mMessageType;
|
|
int32 mStackWindbackCount;
|
|
int32 mBufferParamLen;
|
|
char8* mBufferParam;
|
|
void* mPCOverride;
|
|
|
|
char8* mBufferPtr = null;
|
|
int mStrSize = 0;
|
|
|
|
[CLink]
|
|
public static BfDebugMessageData gBfDebugMessageData;
|
|
|
|
public static ~this()
|
|
{
|
|
if (gBfDebugMessageData.mBufferPtr != null)
|
|
{
|
|
Internal.Free(gBfDebugMessageData.mBufferPtr);
|
|
gBfDebugMessageData.mBufferPtr = null;
|
|
gBfDebugMessageData.mStrSize = 0;
|
|
}
|
|
}
|
|
|
|
public void SetupError(char8* str, int32 stackWindbackCount = 0) mut
|
|
{
|
|
mMessageType = .Error;
|
|
mStackWindbackCount = stackWindbackCount;
|
|
int size = Internal.CStrLen(str) + 1;
|
|
if (mStrSize < size)
|
|
{
|
|
if (mBufferPtr != null)
|
|
Internal.Free(mBufferPtr);
|
|
mStrSize = size;
|
|
mBufferPtr = (char8*)Internal.Malloc(mStrSize);
|
|
}
|
|
Internal.MemCpy(mBufferPtr, str, size);
|
|
mBufferParam = mBufferPtr;
|
|
mBufferParamLen = (int32)size - 1;
|
|
mPCOverride = null;
|
|
}
|
|
|
|
public void SetupProfilerCmd(char8* str) mut
|
|
{
|
|
mMessageType = .ProfilerCmd;
|
|
mStackWindbackCount = 0;
|
|
|
|
int size = Internal.CStrLen(str) + 1;
|
|
if (mStrSize < size)
|
|
{
|
|
if (mBufferPtr != null)
|
|
Internal.Free(mBufferPtr);
|
|
mStrSize = size;
|
|
mBufferPtr = (char8*)Internal.Malloc(mStrSize);
|
|
}
|
|
Internal.MemCpy(mBufferPtr, str, size);
|
|
mBufferParam = mBufferPtr;
|
|
mBufferParamLen = (int32)size - 1;
|
|
mPCOverride = null;
|
|
}
|
|
|
|
public void Fatal() mut
|
|
{
|
|
var str = scope String();
|
|
str.Reference(mBufferPtr, mBufferParamLen, 0);
|
|
Internal.FatalError(str, -1);
|
|
}
|
|
|
|
public void Clear() mut
|
|
{
|
|
mMessageType = .None;
|
|
if (mBufferPtr != null)
|
|
mBufferPtr[0] = 0;
|
|
mBufferParamLen = 0;
|
|
}
|
|
}
|
|
|
|
struct BfRtCallbacks
|
|
{
|
|
public static BfRtCallbacks sCallbacks = .();
|
|
|
|
function void* (int size) mAlloc;
|
|
function void (void* ptr) mFree;
|
|
function void (Object obj) mObject_Delete;
|
|
function void (Object obj, String str) mObject_ToString;
|
|
function Type (Object obj) mObject_GetType;
|
|
function void (Object obj) mObject_GCMarkMembers;
|
|
function Object (Object obj, int32 typeId) mObject_DynamicCastToTypeId;
|
|
function void (Type type, String str) mType_GetFullName;
|
|
function String () mString_Alloc;
|
|
function char8* (String str) mString_ToCStr;
|
|
function Object () mThread_Alloc;
|
|
function Object () mThread_GetMainThread;
|
|
function void (Object thread) mThread_ThreadProc;
|
|
function void* (Object thread) mThread_GetInternalThread;
|
|
function void (Object thread, void* internalThread) mThread_SetInternalThread;
|
|
function bool (Object thread) mThread_IsAutoDelete;
|
|
function void (Object thread) mThread_AutoDelete;
|
|
function int32 (Object thread) mThread_GetMaxStackSize;
|
|
function void () mGC_MarkAllStaticMembers;
|
|
function bool () mGC_CallRootCallbacks;
|
|
function void () mGC_Shutdown;
|
|
function void (char8* str) mSetErrorString;
|
|
function void (char8* str, int32 stackWindbackCount) mDebugMessageData_SetupError;
|
|
function void (char8* str) mDebugMessageData_SetupProfilerCmd;
|
|
function void () mDebugMessageData_Fatal;
|
|
function void () mDebugMessageData_Clear;
|
|
|
|
static void* Alloc(int size)
|
|
{
|
|
return Internal.Malloc(size);
|
|
}
|
|
|
|
static void Free(void* ptr)
|
|
{
|
|
Internal.Free(ptr);
|
|
}
|
|
|
|
static void Object_Delete(Object obj)
|
|
{
|
|
delete obj;
|
|
}
|
|
|
|
static void Object_ToString(Object obj, String str)
|
|
{
|
|
#if BF_DBG_RUNTIME
|
|
obj.ToString(str);
|
|
#endif
|
|
}
|
|
|
|
static Type Object_GetType(Object obj)
|
|
{
|
|
#if BF_DBG_RUNTIME
|
|
return obj.[Friend]RawGetType();
|
|
#else
|
|
return null;
|
|
#endif
|
|
}
|
|
|
|
static void Object_GCMarkMembers(Object obj)
|
|
{
|
|
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
|
obj.[Friend, DisableObjectAccessChecks]GCMarkMembers();
|
|
#endif
|
|
}
|
|
|
|
static Object Object_DynamicCastToTypeId(Object obj, int32 typeId)
|
|
{
|
|
#if BF_DYNAMIC_CAST_CHECK
|
|
return obj.DynamicCastToTypeId(typeId);
|
|
#else
|
|
return null;
|
|
#endif
|
|
}
|
|
|
|
static void Type_GetFullName(Type type, String str)
|
|
{
|
|
#if BF_DBG_RUNTIME
|
|
type.GetFullName(str);
|
|
#else
|
|
//
|
|
#endif
|
|
}
|
|
|
|
static String String_Alloc()
|
|
{
|
|
return new String();
|
|
}
|
|
|
|
static char8* String_ToCStr(String str)
|
|
{
|
|
return str.CStr();
|
|
}
|
|
|
|
static void GC_MarkAllStaticMembers()
|
|
{
|
|
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
|
GC.[Friend]MarkAllStaticMembers();
|
|
#endif
|
|
}
|
|
|
|
static bool GC_CallRootCallbacks()
|
|
{
|
|
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
|
return GC.[Friend]CallRootCallbacks();
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
static void GC_Shutdown()
|
|
{
|
|
#if BF_DBG_RUNTIME
|
|
GC.Shutdown();
|
|
#endif
|
|
}
|
|
|
|
static void DebugMessageData_SetupError(char8* str, int32 stackWindbackCount)
|
|
{
|
|
BfDebugMessageData.gBfDebugMessageData.SetupError(str, stackWindbackCount);
|
|
}
|
|
|
|
static void DebugMessageData_SetupProfilerCmd(char8* str)
|
|
{
|
|
BfDebugMessageData.gBfDebugMessageData.SetupProfilerCmd(str);
|
|
}
|
|
|
|
static void DebugMessageData_Fatal()
|
|
{
|
|
BfDebugMessageData.gBfDebugMessageData.Fatal();
|
|
}
|
|
|
|
static void DebugMessageData_Clear()
|
|
{
|
|
BfDebugMessageData.gBfDebugMessageData.Clear();
|
|
}
|
|
|
|
|
|
public void Init() mut
|
|
{
|
|
mAlloc = => Alloc;
|
|
mFree = => Free;
|
|
mObject_Delete = => Object_Delete;
|
|
mObject_ToString = => Object_ToString;
|
|
mObject_GetType = => Object_GetType;
|
|
mObject_GCMarkMembers = => Object_GCMarkMembers;
|
|
mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId;
|
|
mType_GetFullName = => Type_GetFullName;
|
|
mString_Alloc = => String_Alloc;
|
|
mString_ToCStr = => String_ToCStr;
|
|
mGC_MarkAllStaticMembers = => GC_MarkAllStaticMembers;
|
|
mGC_CallRootCallbacks = => GC_CallRootCallbacks;
|
|
mGC_Shutdown = => GC_Shutdown;
|
|
mSetErrorString = => SetErrorString;
|
|
mDebugMessageData_SetupError = => DebugMessageData_SetupError;
|
|
mDebugMessageData_SetupProfilerCmd = => DebugMessageData_SetupProfilerCmd;
|
|
mDebugMessageData_Fatal = => DebugMessageData_Fatal;
|
|
mDebugMessageData_Clear = => DebugMessageData_Clear;
|
|
}
|
|
};
|
|
|
|
private static extern void Init(int32 version, int32 flags, BfRtCallbacks* callbacks);
|
|
private static extern void AddCrashInfoFunc(void* func);
|
|
private static extern void Dbg_Init(int32 version, int32 flags, BfRtCallbacks* callbacks);
|
|
private static extern void SetErrorString(char8* error);
|
|
private static extern void* Dbg_GetCrashInfoFunc();
|
|
public static extern void SetCrashReportKind(RtCrashReportKind crashReportKind);
|
|
|
|
public enum RtCrashReportKind : int32
|
|
{
|
|
Default,
|
|
GUI,
|
|
Console,
|
|
PrintOnly,
|
|
None
|
|
}
|
|
|
|
enum RtFlags : int32
|
|
{
|
|
ObjectHasDebugFlags = 1,
|
|
LeakCheck = 2,
|
|
SilentCrash = 4,
|
|
DebugAlloc = 8,
|
|
NoThreadExitWait = 0x10
|
|
}
|
|
|
|
static RtFlags sExtraFlags;
|
|
|
|
public static this()
|
|
{
|
|
BfRtCallbacks.sCallbacks.Init();
|
|
|
|
RtFlags flags = sExtraFlags;
|
|
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
|
|
flags |= .ObjectHasDebugFlags;
|
|
#endif
|
|
#if BF_ENABLE_REALTIME_LEAK_CHECK
|
|
flags |= .LeakCheck;
|
|
#endif
|
|
#if BF_DEBUG_ALLOC
|
|
flags |= .DebugAlloc;
|
|
#endif
|
|
Init(cVersion, (int32)flags, &BfRtCallbacks.sCallbacks);
|
|
#if BF_DBG_RUNTIME
|
|
Dbg_Init(cVersion, (int32)flags, &BfRtCallbacks.sCallbacks);
|
|
#endif
|
|
}
|
|
|
|
[NoReturn]
|
|
public static void FatalError(String msg = "Fatal error encountered", String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
|
{
|
|
String failStr = scope .()..AppendF("{} at line {} in {}", msg, line, filePath);
|
|
Internal.FatalError(failStr, 1);
|
|
}
|
|
|
|
[NoReturn]
|
|
public static void NotImplemented(String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
|
{
|
|
String failStr = scope .()..AppendF("Not Implemented at line {} in {}", line, filePath);
|
|
Internal.FatalError(failStr, 1);
|
|
}
|
|
|
|
public static void Assert(bool condition, String error = Compiler.CallerExpression[0], String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
|
{
|
|
if (!condition)
|
|
{
|
|
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
|
|
Internal.FatalError(failStr, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|