mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-25 19:18:01 +02:00
763 lines
No EOL
19 KiB
Beef
763 lines
No EOL
19 KiB
Beef
using System.Threading;
|
|
using System.Collections;
|
|
#if (BF_ENABLE_OBJECT_DEBUG_FLAGS || BF_DEBUG_ALLOC) && !BF_RUNTIME_DISABLE
|
|
#define BF_DBG_RUNTIME
|
|
#endif
|
|
|
|
using internal System.Threading.Thread;
|
|
|
|
namespace System
|
|
{
|
|
struct RuntimeFeatures
|
|
{
|
|
public bool SSE, SSE2;
|
|
public bool AVX, AVX2, AVX512;
|
|
}
|
|
|
|
[StaticInitPriority(201)]
|
|
static class Runtime
|
|
{
|
|
const int32 cVersion = 10;
|
|
|
|
[CRepr]
|
|
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;
|
|
void* mUnused0;
|
|
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 StringView (String str) mString_ToStringView;
|
|
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 () mThread_Exiting;
|
|
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;
|
|
function int32 (char8* kind, char8* arg1, char8* arg2, int arg3) mCheckErrorHandler;
|
|
|
|
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 Type Object_GetType(Object obj)
|
|
{
|
|
#if BF_DBG_RUNTIME
|
|
return obj.[Friend, DisableObjectAccessChecks]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.ToString(str);
|
|
#else
|
|
//
|
|
#endif
|
|
}
|
|
|
|
static String String_Alloc()
|
|
{
|
|
return new String();
|
|
}
|
|
|
|
static StringView String_ToStringView(String str)
|
|
{
|
|
return str;
|
|
}
|
|
|
|
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)
|
|
{
|
|
#if !BF_RUNTIME_REDUCED
|
|
BfDebugMessageData.gBfDebugMessageData.SetupError(str, stackWindbackCount);
|
|
#endif
|
|
}
|
|
|
|
static void DebugMessageData_SetupProfilerCmd(char8* str)
|
|
{
|
|
#if !BF_RUNTIME_REDUCED
|
|
BfDebugMessageData.gBfDebugMessageData.SetupProfilerCmd(str);
|
|
#endif
|
|
}
|
|
|
|
static void DebugMessageData_Fatal()
|
|
{
|
|
#if !BF_RUNTIME_REDUCED
|
|
BfDebugMessageData.gBfDebugMessageData.Fatal();
|
|
#endif
|
|
}
|
|
|
|
static void DebugMessageData_Clear()
|
|
{
|
|
#if !BF_RUNTIME_REDUCED
|
|
BfDebugMessageData.gBfDebugMessageData.Clear();
|
|
#endif
|
|
}
|
|
|
|
static int32 CheckErrorHandle(char8* kind, char8* arg1, char8* arg2, int arg3)
|
|
{
|
|
if (Runtime.CheckErrorHandler != null)
|
|
return Runtime.CheckErrorHandler(kind, arg1, arg2, arg3);
|
|
return 0;
|
|
}
|
|
|
|
public void Init() mut
|
|
{
|
|
mAlloc = => Alloc;
|
|
mFree = => Free;
|
|
mObject_Delete = => Object_Delete;
|
|
mObject_GetType = => Object_GetType;
|
|
mObject_GCMarkMembers = => Object_GCMarkMembers;
|
|
mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId;
|
|
mType_GetFullName = => Type_GetFullName;
|
|
mString_Alloc = => String_Alloc;
|
|
mString_ToStringView = => String_ToStringView;
|
|
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;
|
|
mCheckErrorHandler = => CheckErrorHandler;
|
|
}
|
|
};
|
|
|
|
#if !BF_RUNTIME_DISABLE
|
|
private static extern void Init(int32 version, int32 flags, BfRtCallbacks* callbacks);
|
|
private static extern void InitCrashCatcher(int32 flags);
|
|
private static extern void ShutdownCrashCatcher();
|
|
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);
|
|
#else
|
|
private static void Init(int32 version, int32 flags, BfRtCallbacks* callbacks) {}
|
|
private static void AddCrashInfoFunc(void* func) {}
|
|
private static void Dbg_Init(int32 version, int32 flags, BfRtCallbacks* callbacks) {}
|
|
private static void SetErrorString(char8* error) {}
|
|
private static void* Dbg_GetCrashInfoFunc() => null;
|
|
public static void SetCrashReportKind(RtCrashReportKind crashReportKind) {}
|
|
#endif
|
|
|
|
public enum RtCrashReportKind : int32
|
|
{
|
|
Default,
|
|
GUI,
|
|
Console,
|
|
PrintOnly,
|
|
None,
|
|
System
|
|
}
|
|
|
|
enum RtFlags : int32
|
|
{
|
|
ObjectHasDebugFlags = 1,
|
|
LeakCheck = 2,
|
|
SilentCrash = 4,
|
|
DebugAlloc = 8,
|
|
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
|
|
}
|
|
|
|
static struct ErrorHandlerData
|
|
{
|
|
public delegate ErrorHandlerResult ErrorHandler(ErrorStage stage, Error error);
|
|
public static AllocWrapper<Monitor> sMonitor ~ _.Dispose();
|
|
public static List<ErrorHandler> sErrorHandlers ~ DeleteContainerAndItems!(_);
|
|
public static bool sInsideErrorHandler;
|
|
}
|
|
|
|
static RtFlags sExtraFlags;
|
|
static bool sQueriedFeatures = false;
|
|
static RuntimeFeatures sFeatures;
|
|
|
|
static function void() sThreadInit;
|
|
|
|
public static this()
|
|
{
|
|
#if !BF_RUNTIME_DISABLE
|
|
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_RUNTIME_REDUCED && BF_PLATFORM_WINDOWS
|
|
InitCrashCatcher((int32)flags);
|
|
#endif
|
|
#if BF_DBG_RUNTIME
|
|
Dbg_Init(cVersion, (int32)flags, &BfRtCallbacks.sCallbacks);
|
|
#endif
|
|
if (sThreadInit != null)
|
|
sThreadInit();
|
|
#endif
|
|
}
|
|
|
|
[NoReturn]
|
|
public static void FatalError(String msg = "Fatal error encountered", String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
|
{
|
|
#if !BF_RUNTIME_REDUCED
|
|
String failStr = scope .()..Append(msg, " at line ");
|
|
line.ToString(failStr);
|
|
failStr.Append(" in ", filePath);
|
|
Internal.FatalError(failStr, 1);
|
|
#else
|
|
Internal.FatalError("Fatal error", 1);
|
|
#endif
|
|
}
|
|
|
|
[NoReturn]
|
|
public static void NotImplemented(String filePath = Compiler.CallerFilePath, int line = Compiler.CallerLineNum)
|
|
{
|
|
String failStr = scope .()..Append("Not implemented at line ");
|
|
line.ToString(failStr);
|
|
failStr.Append(" in ", 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)
|
|
{
|
|
if ((!Compiler.IsComptime) && (Runtime.CheckAssertError != null) && (Runtime.CheckAssertError(.Runtime, error, filePath, line) == .Ignore))
|
|
return;
|
|
#if !BF_RUNTIME_REDUCED
|
|
String failStr = scope .()..Append("Assert failed: ", error, " at line ");
|
|
line.ToString(failStr);
|
|
failStr.Append(" in ", filePath);
|
|
Internal.FatalError(failStr, 1);
|
|
#else
|
|
Internal.FatalError("Assert failed", 1);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public static void AddErrorHandler(ErrorHandlerData.ErrorHandler handler)
|
|
{
|
|
if (Compiler.IsComptime)
|
|
return;
|
|
|
|
using (ErrorHandlerData.sMonitor.Val.Enter())
|
|
{
|
|
if (CheckAssertError == null)
|
|
{
|
|
CheckAssertError = => CheckAssertError_Impl;
|
|
CheckErrorHandler = => CheckErrorHandler_Impl;
|
|
}
|
|
|
|
if (ErrorHandlerData.sErrorHandlers == null)
|
|
ErrorHandlerData.sErrorHandlers = new .();
|
|
ErrorHandlerData.sErrorHandlers.Add(handler);
|
|
}
|
|
}
|
|
|
|
public static Result<void> RemoveErrorHandler(ErrorHandlerData.ErrorHandler handler)
|
|
{
|
|
if (Compiler.IsComptime)
|
|
return .Ok;
|
|
|
|
using (ErrorHandlerData.sMonitor.Val.Enter())
|
|
{
|
|
if (ErrorHandlerData.sErrorHandlers.RemoveStrict(handler))
|
|
return .Ok;
|
|
}
|
|
return .Err;
|
|
}
|
|
|
|
public static function ErrorHandlerResult(AssertError.Kind kind, String error, String filePath, int lineNum) CheckAssertError;
|
|
public static function int32(char8* kind, char8* arg1, char8* arg2, int arg3) CheckErrorHandler;
|
|
public static function void*(char8* filePath) LibraryLoadCallback;
|
|
|
|
static ErrorHandlerResult CheckAssertError_Impl(AssertError.Kind kind, String error, String filePath, int lineNum)
|
|
{
|
|
return CheckErrorHandlers(scope AssertError(kind, error, filePath, lineNum));
|
|
}
|
|
|
|
static int32 CheckErrorHandler_Impl(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)CheckErrorHandlers(error);
|
|
}
|
|
|
|
static ErrorHandlerResult CheckErrorHandlers(Error error)
|
|
{
|
|
if (Compiler.IsComptime)
|
|
return .ContinueFailure;
|
|
|
|
using (ErrorHandlerData.sMonitor.Val.Enter())
|
|
{
|
|
if (ErrorHandlerData.sInsideErrorHandler)
|
|
return .ContinueFailure;
|
|
|
|
ErrorHandlerData.sInsideErrorHandler = true;
|
|
defer { ErrorHandlerData.sInsideErrorHandler = false; }
|
|
|
|
for (int pass = 0; pass < 2; pass++)
|
|
{
|
|
int idx = (ErrorHandlerData.sErrorHandlers?.Count).GetValueOrDefault() - 1;
|
|
while (idx >= 0)
|
|
{
|
|
if (idx < ErrorHandlerData.sErrorHandlers.Count)
|
|
{
|
|
var handler = ErrorHandlerData.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;
|
|
}
|
|
|
|
public static RuntimeFeatures Features
|
|
{
|
|
get
|
|
{
|
|
if (!sQueriedFeatures)
|
|
{
|
|
#if BF_MACHINE_X86 || BF_MACHINE_X64
|
|
QueryFeaturesX86();
|
|
#else
|
|
sFeatures = .();
|
|
sQueriedFeatures = true;
|
|
#endif
|
|
}
|
|
|
|
return sFeatures;
|
|
}
|
|
}
|
|
|
|
#if BF_MACHINE_X86 || BF_MACHINE_X64
|
|
private static void QueryFeaturesX86()
|
|
{
|
|
sFeatures = .();
|
|
sQueriedFeatures = true;
|
|
|
|
uint32 _ = 0;
|
|
|
|
// 0: Basic information
|
|
uint32 maxBasicLeaf = 0;
|
|
cpuid(0, 0, &maxBasicLeaf, &_, &_, &_);
|
|
|
|
if (maxBasicLeaf < 1)
|
|
{
|
|
// Earlier Intel 486, CPUID not implemented
|
|
return;
|
|
}
|
|
|
|
// 1: Processor Info and Feature Bits
|
|
uint32 procInfoEcx = 0;
|
|
uint32 procInfoEdx = 0;
|
|
cpuid(1, 0, &_, &_, &procInfoEcx, &procInfoEdx);
|
|
|
|
sFeatures.SSE = (procInfoEdx & (1 << 25)) != 0;
|
|
sFeatures.SSE2 = (procInfoEdx & (1 << 26)) != 0;
|
|
|
|
// 7: Extended Features
|
|
uint32 extendedFeaturesEbx = 0;
|
|
cpuid(7, 0, &_, &extendedFeaturesEbx, &_, &_);
|
|
|
|
// `XSAVE` and `AVX` support:
|
|
if ((procInfoEcx & (1 << 26)) != 0)
|
|
{
|
|
// Here the CPU supports `XSAVE`
|
|
|
|
// Detect `OSXSAVE`, that is, whether the OS is AVX enabled and
|
|
// supports saving the state of the AVX/AVX2 vector registers on
|
|
// context-switches
|
|
if ((procInfoEcx & (1 << 27)) != 0)
|
|
{
|
|
// The OS must have signaled the CPU that it supports saving and restoring the
|
|
uint64 xcr0 = xgetbv(0);
|
|
|
|
bool avxSupport = (xcr0 & 6) == 6;
|
|
bool avx512Support = (xcr0 & 224) == 224;
|
|
|
|
// Only if the OS and the CPU support saving/restoring the AVX registers we enable `xsave` support
|
|
if (avxSupport)
|
|
{
|
|
sFeatures.AVX = (procInfoEcx & (1 << 28)) != 0;
|
|
sFeatures.AVX2 = (extendedFeaturesEbx & (1 << 5)) != 0;
|
|
|
|
// For AVX-512 the OS also needs to support saving/restoring
|
|
// the extended state, only then we enable AVX-512 support:
|
|
if (avx512Support)
|
|
sFeatures.AVX512 = (extendedFeaturesEbx & (1 << 16)) != 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Intrinsic("cpuid")]
|
|
private static extern void cpuid(uint32 leaf, uint32 subleaf, uint32* eax, uint32* ebx, uint32* ecx, uint32* edx);
|
|
|
|
[Intrinsic("xgetbv")]
|
|
private static extern uint64 xgetbv(uint32 xcr);
|
|
#endif
|
|
|
|
public static void Shutdown()
|
|
{
|
|
#if !BF_RUNTIME_REDUCED && BF_PLATFORM_WINDOWS
|
|
ShutdownCrashCatcher();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#if BF_RUNTIME_DISABLE && !BF_CRT_DISABLE
|
|
namespace System
|
|
{
|
|
[AlwaysInclude, StaticInitPriority(1000)]
|
|
static class MinRuntime
|
|
{
|
|
static function void*(int) sMallocFunc;
|
|
static function void(void*) sFreeFunc;
|
|
static function void(char8) sPutChar;
|
|
|
|
static this()
|
|
{
|
|
var lib = Windows.LoadLibraryA("msvcrt.dll");
|
|
sMallocFunc = (.)Windows.GetProcAddress(lib, "malloc");
|
|
sFreeFunc = (.)Windows.GetProcAddress(lib, "free");
|
|
sPutChar = (.)Windows.GetProcAddress(lib, "putchar");
|
|
}
|
|
|
|
/*[LinkName(.C), AlwaysInclude]
|
|
static void __chkstk()
|
|
{
|
|
|
|
}*/
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void* malloc(int size)
|
|
{
|
|
return sMallocFunc(size);
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void free(void* ptr)
|
|
{
|
|
sFreeFunc(ptr);
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void putchar(char8 c)
|
|
{
|
|
sPutChar(c);
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void memset(void* dest, uint8 val, int size)
|
|
{
|
|
uint8* outPtr = (.)dest;
|
|
for (int i < size)
|
|
*(outPtr++) = val;
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void memcpy(void* dest, void* src, int size)
|
|
{
|
|
uint8* destPtr = (.)dest;
|
|
uint8* srcPtr = (.)src;
|
|
|
|
if (destPtr < srcPtr)
|
|
{
|
|
for (int i < size)
|
|
*(destPtr++) = *(srcPtr++);
|
|
}
|
|
else
|
|
{
|
|
destPtr += size;
|
|
srcPtr += size;
|
|
for (int i < size)
|
|
*(--destPtr) = *(--srcPtr);
|
|
}
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void memmove(void* dest, void* src, int size)
|
|
{
|
|
uint8* destPtr = (.)dest;
|
|
uint8* srcPtr = (.)src;
|
|
|
|
if (destPtr < srcPtr)
|
|
{
|
|
for (int i < size)
|
|
*(destPtr++) = *(srcPtr++);
|
|
}
|
|
else
|
|
{
|
|
destPtr += size;
|
|
srcPtr += size;
|
|
for (int i < size)
|
|
*(--destPtr) = *(--srcPtr);
|
|
}
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static double strtod(char8* str, char8** endPtr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static extern void WinMain(void* module, void* prevModule, char8* args, int32 showCmd);
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static extern int32 main(int argc, char8** argv);
|
|
|
|
[LinkName(.C), AlwaysInclude]
|
|
static void mainCRTStartup()
|
|
{
|
|
main(0, null);
|
|
}
|
|
|
|
/*[LinkName(.C), AlwaysInclude]
|
|
static void WinMainCRTStartup()
|
|
{
|
|
//WinMain(null, null, "hi", 1);
|
|
}*/
|
|
|
|
[LinkName(.C), Export]
|
|
static int32 _tls_index;
|
|
|
|
[LinkName(.C), Export]
|
|
static bool _fltused;
|
|
}
|
|
}
|
|
#endif |