1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00

Added Runtime.AddErrorHandler

This commit is contained in:
Brian Fiete 2022-02-11 08:12:30 -05:00
parent 9e80281d1a
commit 657a64f59c
8 changed files with 192 additions and 6 deletions

View file

@ -1,3 +1,6 @@
using System.Reflection;
using System.Threading;
namespace System
{
interface IRawAllocator
@ -18,4 +21,32 @@ namespace System
Internal.StdFree(ptr);
}
}
struct AllocWrapper<T> where T : new, delete
{
alloctype(T) mVal;
public alloctype(T) Val
{
get mut
{
if (mVal != default)
return mVal;
var newVal = new T();
let prevValue = Interlocked.CompareExchange(ref mVal, default, newVal);
if (prevValue != default)
{
delete newVal;
return prevValue;
}
return newVal;
}
}
public void Dispose() mut
{
delete mVal;
mVal = default;
}
}
}

View file

@ -9,6 +9,8 @@ namespace System.Diagnostics
{
if (!condition)
{
if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Debug, error, filePath, line)) == .Ignore)
return;
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
Internal.FatalError(failStr, 1);
}

View file

@ -1,4 +1,5 @@
using System.Threading;
using System.Collections;
#if BF_ENABLE_OBJECT_DEBUG_FLAGS || BF_DEBUG_ALLOC
#define BF_DBG_RUNTIME
#endif
@ -8,7 +9,7 @@ namespace System
[StaticInitPriority(101)]
static class Runtime
{
const int32 cVersion = 8;
const int32 cVersion = 9;
[CRepr, AlwaysInclude]
struct BfDebugMessageData
@ -125,6 +126,7 @@ namespace System
function void (char8* str) mDebugMessageData_SetupProfilerCmd;
function void () mDebugMessageData_Fatal;
function void () mDebugMessageData_Clear;
function int32 (char8* kind, char8* arg1, char8* arg2, int arg3) mCheckErrorHandler;
static void* Alloc(int size)
{
@ -228,6 +230,22 @@ namespace System
BfDebugMessageData.gBfDebugMessageData.Clear();
}
static int32 CheckErrorHandler(char8* kind, char8* arg1, char8* arg2, int arg3)
{
Error error = null;
switch (StringView(kind))
{
case "FatalError":
error = scope:: FatalError() { mError = new .(arg1) };
case "LoadSharedLibrary":
error = scope:: LoadSharedLibraryError() { mPath = new .(arg1) };
case "GetSharedProcAddress":
error = scope:: GetSharedProcAddressError() { mPath = new .(arg1), mProcName = new .(arg2) };
}
if (error == null)
return 0;
return (int32)Runtime.CheckErrorHandlers(error);
}
public void Init() mut
{
@ -247,7 +265,8 @@ namespace System
mDebugMessageData_SetupError = => DebugMessageData_SetupError;
mDebugMessageData_SetupProfilerCmd = => DebugMessageData_SetupProfilerCmd;
mDebugMessageData_Fatal = => DebugMessageData_Fatal;
mDebugMessageData_Clear = => DebugMessageData_Clear;
mDebugMessageData_Clear = => DebugMessageData_Clear;
mCheckErrorHandler = => CheckErrorHandler;
}
};
@ -276,7 +295,68 @@ namespace System
NoThreadExitWait = 0x10
}
public enum ErrorHandlerResult
{
ContinueFailure,
Ignore,
}
public class Error
{
}
public class FatalError : Error
{
public String mError ~ delete _;
}
public class LoadSharedLibraryError : Error
{
public String mPath ~ delete _;
}
public class GetSharedProcAddressError : Error
{
public String mPath ~ delete _;
public String mProcName ~ delete _;
}
public class AssertError : Error
{
public enum Kind
{
Debug,
Runtime,
Test
}
public Kind mKind;
public String mError ~ delete _;
public String mFilePath ~ delete _;
public int mLineNum;
public this(Kind kind, String error, String filePath, int lineNum)
{
mKind = kind;
mError = new .(error);
mFilePath = new .(filePath);
mLineNum = lineNum;
}
}
public enum ErrorStage
{
PreFail,
Fail
}
public delegate ErrorHandlerResult ErrorHandler(ErrorStage stage, Error error);
static RtFlags sExtraFlags;
static AllocWrapper<Monitor> sMonitor ~ _.Dispose();
static List<ErrorHandler> sErrorHandlers ~ DeleteContainerAndItems!(_);
static bool sInsideErrorHandler;
public static this()
{
@ -317,9 +397,64 @@ namespace System
{
if (!condition)
{
if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Runtime, error, filePath, line)) == .Ignore)
return;
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
Internal.FatalError(failStr, 1);
}
}
public static void AddErrorHandler(ErrorHandler handler)
{
using (sMonitor.Val.Enter())
{
if (sErrorHandlers == null)
sErrorHandlers = new .();
sErrorHandlers.Add(handler);
}
}
public static Result<void> RemoveErrorHandler(ErrorHandler handler)
{
using (sMonitor.Val.Enter())
{
if (sErrorHandlers.Remove(handler))
return .Ok;
}
return .Err;
}
public static ErrorHandlerResult CheckErrorHandlers(Error error)
{
using (sMonitor.Val.Enter())
{
if (sInsideErrorHandler)
return .ContinueFailure;
sInsideErrorHandler = true;
defer { sInsideErrorHandler = false; }
for (int pass = 0; pass < 2; pass++)
{
int idx = (sErrorHandlers?.Count).GetValueOrDefault() - 1;
while (idx >= 0)
{
if (idx < sErrorHandlers.Count)
{
var handler = sErrorHandlers[idx];
var result = handler((pass == 0) ? .PreFail : .Fail, error);
if (result == .Ignore)
{
if (pass == 1)
Internal.FatalError("Can only ignore error on prefail");
return .Ignore;
}
}
idx--;
}
}
}
return .ContinueFailure;
}
}
}

View file

@ -70,6 +70,8 @@ namespace System
{
if (!condition)
{
if (Runtime.CheckErrorHandlers(scope Runtime.AssertError(.Test, error, filePath, line)) == .Ignore)
return;
String failStr = scope .()..AppendF("Assert failed: {} at line {} in {}", error, line, filePath);
Internal.[Friend]Test_Error(failStr);
}

View file

@ -3,7 +3,7 @@
#include "BeefySysLib/Common.h"
#include "BeefySysLib/util/String.h"
#define BFRT_VERSION 8
#define BFRT_VERSION 9
#ifdef BFRT_DYNAMIC
#define BFRT_EXPORT __declspec(dllexport)
@ -106,7 +106,8 @@ namespace bf
void(*DebugMessageData_SetupError)(const char* str, int32 stackWindbackCount);
void(*DebugMessageData_SetupProfilerCmd)(const char* str);
void(*DebugMessageData_Fatal)();
void(*DebugMessageData_Clear)();
void(*DebugMessageData_Clear)();
int(*CheckErrorHandler)(const char* kind, const char* arg1, const char* arg2, intptr arg3);
};
public:

View file

@ -214,6 +214,9 @@ static void TestReadCmd(Beefy::String& str);
static void Internal_FatalError(const char* error)
{
if (gBfRtCallbacks.CheckErrorHandler != NULL)
gBfRtCallbacks.CheckErrorHandler("FatalError", error, NULL, 0);
if ((gClientPipe != NULL) && (!gTestBreakOnFailure))
{
Beefy::String str = ":TestFatal\t";
@ -532,6 +535,12 @@ void* Internal::LoadSharedLibrary(char* libName)
void* libHandle = BfpDynLib_Load(libName);
if (libHandle == NULL)
{
if (gBfRtCallbacks.CheckErrorHandler != NULL)
{
if (gBfRtCallbacks.CheckErrorHandler("LoadSharedLibrary", libName, NULL, 0) == 1)
return NULL;
}
Beefy::String errorStr = StrFormat("Failed to load shared library: %s", libName);
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();
@ -558,6 +567,12 @@ void* Internal::GetSharedProcAddress(void* libHandle, char* procName)
int libFileNameLen = 4096;
BfpDynLib_GetFilePath((BfpDynLib*)libHandle, libFileName, &libFileNameLen, NULL);
if (gBfRtCallbacks.CheckErrorHandler != NULL)
{
if (gBfRtCallbacks.CheckErrorHandler("GetSharedProcAddress", libFileName, procName, 0) == 1)
return NULL;
}
Beefy::String errorStr = StrFormat("Failed to load shared procedure '%s' from '%s'", procName, libFileName);
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();

View file

@ -373,7 +373,7 @@ bool BfConstResolver::PrepareMethodArguments(BfAstNode* targetSrc, BfMethodMatch
}
if (mModule->PreFail())
mModule->Fail(StrFormat("Not enough parameters specified. Expected %d fewer.", methodInstance->GetParamCount() - (int)arguments.size()), refNode);
mModule->Fail(StrFormat("Not enough parameters specified. Expected %d more.", methodInstance->GetParamCount() - (int)arguments.size()), refNode);
return false;
}

View file

@ -19107,7 +19107,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup,
{
BfIRValue dllImportGlobalVar = CreateDllImportGlobalVar(methodInstance, true);
methodInstance->mIRFunction = mBfIRBuilder->GetFakeVal();
BF_ASSERT(dllImportGlobalVar);
BF_ASSERT(dllImportGlobalVar || methodInstance->mHasFailed);
mFuncReferences[mCurMethodInstance] = dllImportGlobalVar;
}