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:
parent
9e80281d1a
commit
657a64f59c
8 changed files with 192 additions and 6 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue